blob: 0f8d903a306d7518ec1f9a86502413c8e08d5d14 [file] [log] [blame]
Dees_Troya13d74f2013-03-24 08:54:55 -05001/*
2 Copyright 2012 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
19#include <linux/input.h>
20#include <pthread.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <fcntl.h>
26#include <sys/reboot.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <sys/mman.h>
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdlib.h>
35#include <dirent.h>
36#include <ctype.h>
37
38#include <algorithm>
39
40extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040043}
44
45#include "rapidxml.hpp"
46#include "objects.hpp"
47#include "../data.hpp"
Dees_Troy3ee47bc2013-01-25 21:47:37 +000048#include "../twrp-functions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040049
50#define TW_FILESELECTOR_UP_A_LEVEL "(Up A Level)"
51
52#define SCROLLING_SPEED_DECREMENT 6
53#define SCROLLING_FLOOR 10
54#define SCROLLING_MULTIPLIER 6
55
56int GUIFileSelector::mSortOrder = 0;
57
58GUIFileSelector::GUIFileSelector(xml_node<>* node)
59{
60 xml_attribute<>* attr;
61 xml_node<>* child;
62 int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
63
64 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
65 mIconWidth = mIconHeight = mFolderIconHeight = mFileIconHeight = mFolderIconWidth = mFileIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
66 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
67 mFolderIcon = mFileIcon = mBackground = mFont = mHeaderIcon = NULL;
68 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
69 mShowFolders = mShowFiles = mShowNavFolders = 1;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010070 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
71 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040072 mUpdate = 0;
73 touchDebounce = 6;
74 mPathVar = "cwd";
75 ConvertStrToColor("black", &mBackgroundColor);
76 ConvertStrToColor("black", &mHeaderBackgroundColor);
77 ConvertStrToColor("black", &mSeparatorColor);
78 ConvertStrToColor("black", &mHeaderSeparatorColor);
79 ConvertStrToColor("white", &mFontColor);
80 ConvertStrToColor("white", &mHeaderFontColor);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010081 ConvertStrToColor("white", &mFastScrollLineColor);
82 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troye7585ca2013-02-15 11:42:29 -060083 hasHighlightColor = false;
84 hasFontHighlightColor = false;
85 isHighlighted = false;
Dees_Troyc0583f52013-02-28 11:19:57 -060086 updateFileList = false;
Dees_Troye7585ca2013-02-15 11:42:29 -060087 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040088
89 // Load header text
90 child = node->first_node("header");
91 if (child)
92 {
93 attr = child->first_attribute("icon");
94 if (attr)
95 mHeaderIcon = PageManager::FindResource(attr->value());
96
97 attr = child->first_attribute("background");
98 if (attr)
99 {
100 std::string color = attr->value();
101 ConvertStrToColor(color, &mHeaderBackgroundColor);
102 header_background_color_specified = -1;
103 }
104 attr = child->first_attribute("textcolor");
105 if (attr)
106 {
107 std::string color = attr->value();
108 ConvertStrToColor(color, &mHeaderFontColor);
109 header_text_color_specified = -1;
110 }
111 attr = child->first_attribute("separatorcolor");
112 if (attr)
113 {
114 std::string color = attr->value();
115 ConvertStrToColor(color, &mHeaderSeparatorColor);
116 header_separator_color_specified = -1;
117 }
118 attr = child->first_attribute("separatorheight");
119 if (attr) {
120 string parsevalue = gui_parse_text(attr->value());
121 mHeaderSeparatorH = atoi(parsevalue.c_str());
122 header_separator_height_specified = -1;
123 }
124 }
125 child = node->first_node("text");
126 if (child) mHeaderText = child->value();
127
Dees_Troye7585ca2013-02-15 11:42:29 -0600128 memset(&mHighlightColor, 0, sizeof(COLOR));
129 child = node->first_node("highlight");
130 if (child) {
131 attr = child->first_attribute("color");
132 if (attr) {
133 hasHighlightColor = true;
134 std::string color = attr->value();
135 ConvertStrToColor(color, &mHighlightColor);
136 }
137 }
138
Dees_Troy51a0e822012-09-05 15:24:24 -0400139 // Simple way to check for static state
140 mLastValue = gui_parse_text(mHeaderText);
141 if (mLastValue != mHeaderText)
142 mHeaderIsStatic = 0;
143 else
144 mHeaderIsStatic = -1;
145
146 child = node->first_node("icon");
147 if (child)
148 {
149 attr = child->first_attribute("folder");
150 if (attr)
151 mFolderIcon = PageManager::FindResource(attr->value());
152 attr = child->first_attribute("file");
153 if (attr)
154 mFileIcon = PageManager::FindResource(attr->value());
155 }
156 child = node->first_node("background");
157 if (child)
158 {
159 attr = child->first_attribute("resource");
160 if (attr)
161 mBackground = PageManager::FindResource(attr->value());
162 attr = child->first_attribute("color");
163 if (attr)
164 {
165 std::string color = attr->value();
166 ConvertStrToColor(color, &mBackgroundColor);
167 if (!header_background_color_specified)
168 ConvertStrToColor(color, &mHeaderBackgroundColor);
169 }
170 }
171
172 // Load the placement
173 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
174 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
175
176 // Load the font, and possibly override the color
177 child = node->first_node("font");
178 if (child)
179 {
180 attr = child->first_attribute("resource");
181 if (attr)
182 mFont = PageManager::FindResource(attr->value());
183
184 attr = child->first_attribute("color");
185 if (attr)
186 {
187 std::string color = attr->value();
188 ConvertStrToColor(color, &mFontColor);
189 if (!header_text_color_specified)
190 ConvertStrToColor(color, &mHeaderFontColor);
191 }
192
193 attr = child->first_attribute("spacing");
194 if (attr) {
195 string parsevalue = gui_parse_text(attr->value());
196 mLineSpacing = atoi(parsevalue.c_str());
197 }
Dees_Troye7585ca2013-02-15 11:42:29 -0600198
199 attr = child->first_attribute("highlightcolor");
200 memset(&mFontHighlightColor, 0, sizeof(COLOR));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200201 if (attr)
202 {
203 std::string color = attr->value();
Dees_Troye7585ca2013-02-15 11:42:29 -0600204 ConvertStrToColor(color, &mFontHighlightColor);
205 hasFontHighlightColor = true;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200206 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400207 }
208
209 // Load the separator if it exists
210 child = node->first_node("separator");
211 if (child)
212 {
213 attr = child->first_attribute("color");
214 if (attr)
215 {
216 std::string color = attr->value();
217 ConvertStrToColor(color, &mSeparatorColor);
218 if (!header_separator_color_specified)
219 ConvertStrToColor(color, &mHeaderSeparatorColor);
220 }
221
222 attr = child->first_attribute("height");
223 if (attr) {
224 string parsevalue = gui_parse_text(attr->value());
225 mSeparatorH = atoi(parsevalue.c_str());
226 if (!header_separator_height_specified)
227 mHeaderSeparatorH = mSeparatorH;
228 }
229 }
230
231 child = node->first_node("filter");
232 if (child)
233 {
234 attr = child->first_attribute("extn");
235 if (attr)
236 mExtn = attr->value();
237 attr = child->first_attribute("folders");
238 if (attr)
239 mShowFolders = atoi(attr->value());
240 attr = child->first_attribute("files");
241 if (attr)
242 mShowFiles = atoi(attr->value());
243 attr = child->first_attribute("nav");
244 if (attr)
245 mShowNavFolders = atoi(attr->value());
246 }
247
248 // Handle the path variable
249 child = node->first_node("path");
250 if (child)
251 {
252 attr = child->first_attribute("name");
253 if (attr)
254 mPathVar = attr->value();
255 attr = child->first_attribute("default");
256 if (attr)
257 DataManager::SetValue(mPathVar, attr->value());
258 }
259
260 // Handle the result variable
261 child = node->first_node("data");
262 if (child)
263 {
264 attr = child->first_attribute("name");
265 if (attr)
266 mVariable = attr->value();
267 attr = child->first_attribute("default");
268 if (attr)
269 DataManager::SetValue(mVariable, attr->value());
270 }
271
272 // Handle the sort variable
273 child = node->first_node("sort");
274 if (child)
275 {
276 attr = child->first_attribute("name");
277 if (attr)
278 mSortVariable = attr->value();
279 attr = child->first_attribute("default");
280 if (attr)
281 DataManager::SetValue(mSortVariable, attr->value());
282
283 DataManager::GetValue(mSortVariable, mSortOrder);
284 }
285
286 // Handle the selection variable
287 child = node->first_node("selection");
288 if (child)
289 {
290 attr = child->first_attribute("name");
291 if (attr)
292 mSelection = attr->value();
293 else
294 mSelection = "0";
295 } else
296 mSelection = "0";
297
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100298 // Fast scroll colors
299 child = node->first_node("fastscroll");
300 if (child)
301 {
302 attr = child->first_attribute("linecolor");
303 if(attr)
304 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
305
306 attr = child->first_attribute("rectcolor");
307 if(attr)
308 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
309
310 attr = child->first_attribute("w");
311 if (attr) {
312 string parsevalue = gui_parse_text(attr->value());
313 mFastScrollW = atoi(parsevalue.c_str());
314 }
315
316 attr = child->first_attribute("linew");
317 if (attr) {
318 string parsevalue = gui_parse_text(attr->value());
319 mFastScrollLineW = atoi(parsevalue.c_str());
320 }
321
322 attr = child->first_attribute("rectw");
323 if (attr) {
324 string parsevalue = gui_parse_text(attr->value());
325 mFastScrollRectW = atoi(parsevalue.c_str());
326 }
327
328 attr = child->first_attribute("recth");
329 if (attr) {
330 string parsevalue = gui_parse_text(attr->value());
331 mFastScrollRectH = atoi(parsevalue.c_str());
332 }
333 }
334
Dees_Troy51a0e822012-09-05 15:24:24 -0400335 // Retrieve the line height
336 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
337 mLineHeight = mFontHeight;
338 mHeaderH = mFontHeight;
339
340 if (mFolderIcon && mFolderIcon->GetResource())
341 {
342 mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
343 mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
344 if (mFolderIconHeight > (int)mLineHeight)
345 mLineHeight = mFolderIconHeight;
346 mIconWidth = mFolderIconWidth;
347 }
348
349 if (mFileIcon && mFileIcon->GetResource())
350 {
351 mFileIconWidth = gr_get_width(mFileIcon->GetResource());
352 mFileIconHeight = gr_get_height(mFileIcon->GetResource());
353 if (mFileIconHeight > (int)mLineHeight)
354 mLineHeight = mFileIconHeight;
355 if (mFileIconWidth > mIconWidth)
356 mIconWidth = mFileIconWidth;
357 }
358
359 if (mHeaderIcon && mHeaderIcon->GetResource())
360 {
361 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
362 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
363 if (mHeaderIconHeight > mHeaderH)
364 mHeaderH = mHeaderIconHeight;
365 if (mHeaderIconWidth > mIconWidth)
366 mIconWidth = mHeaderIconWidth;
367 }
368
369 mHeaderH += mLineSpacing + mHeaderSeparatorH;
370 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
371 if (mHeaderH < actualLineHeight)
372 mHeaderH = actualLineHeight;
373
374 if (actualLineHeight / 3 > 6)
375 touchDebounce = actualLineHeight / 3;
376
377 if (mBackground && mBackground->GetResource())
378 {
379 mBackgroundW = gr_get_width(mBackground->GetResource());
380 mBackgroundH = gr_get_height(mBackground->GetResource());
381 }
382
383 // Fetch the file/folder list
384 std::string value;
385 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000386 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400387}
388
389GUIFileSelector::~GUIFileSelector()
390{
391}
392
393int GUIFileSelector::Render(void)
394{
395 // First step, fill background
396 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
397 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
398
399 // Next, render the background resource (if it exists)
400 if (mBackground && mBackground->GetResource())
401 {
402 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
403 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
404 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
405 }
406
Dees_Troy4622cf92013-03-01 15:29:36 -0600407 // Update the file list if needed
Dees_Troy4622cf92013-03-01 15:29:36 -0600408 if (updateFileList) {
Dees_Troy4622cf92013-03-01 15:29:36 -0600409 string value;
410 DataManager::GetValue(mPathVar, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200411 if (GetFileList(value) == 0)
Dees_Troy4622cf92013-03-01 15:29:36 -0600412 updateFileList = false;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 else
Dees_Troy4622cf92013-03-01 15:29:36 -0600414 return 0;
Dees_Troy4622cf92013-03-01 15:29:36 -0600415 }
416
Dees_Troy51a0e822012-09-05 15:24:24 -0400417 // This tells us how many lines we can actually render
418 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
419 int line;
420
421 int folderSize = mShowFolders ? mFolderList.size() : 0;
422 int fileSize = mShowFiles ? mFileList.size() : 0;
423
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100424 int listW = mRenderW;
425
Dees_Troy51a0e822012-09-05 15:24:24 -0400426 if (folderSize + fileSize < lines) {
427 lines = folderSize + fileSize;
428 scrollingY = 0;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100429 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400430 } else {
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100431 listW -= mFastScrollW; // space for fast scroll
Dees_Troy51a0e822012-09-05 15:24:24 -0400432 lines++;
433 if (lines < folderSize + fileSize)
434 lines++;
435 }
436
437 void* fontResource = NULL;
438 if (mFont) fontResource = mFont->GetResource();
439
440 int yPos = mRenderY + mHeaderH + scrollingY;
441 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
442 int currentIconHeight = 0, currentIconWidth = 0;
443 int currentIconOffsetY = 0, currentIconOffsetX = 0;
444 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
445 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
Dees_Troye7585ca2013-02-15 11:42:29 -0600446 int actualSelection = mStart;
447
448 if (isHighlighted) {
449 int selectY = scrollingY;
450
451 // Locate the correct line for highlighting
452 while (selectY + actualLineHeight < startSelection) {
453 selectY += actualLineHeight;
454 actualSelection++;
455 }
456 if (hasHighlightColor) {
457 // Highlight the area
458 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
459 int HighlightHeight = actualLineHeight;
460 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
461 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
462 }
463 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
464 }
465 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400466
467 for (line = 0; line < lines; line++)
468 {
469 Resource* icon;
470 std::string label;
471
Dees_Troye7585ca2013-02-15 11:42:29 -0600472 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
473 // Use the highlight color for the font
474 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
475 } else {
476 // Set the color for the font
477 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
478 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400479
480 if (line + mStart < folderSize)
481 {
482 icon = mFolderIcon;
483 label = mFolderList.at(line + mStart).fileName;
484 currentIconHeight = mFolderIconHeight;
485 currentIconWidth = mFolderIconWidth;
486 currentIconOffsetY = folderIconOffsetY;
487 currentIconOffsetX = folderIconOffsetX;
488 }
489 else if (line + mStart < folderSize + fileSize)
490 {
491 icon = mFileIcon;
492 label = mFileList.at((line + mStart) - folderSize).fileName;
493 currentIconHeight = mFileIconHeight;
494 currentIconWidth = mFileIconWidth;
495 currentIconOffsetY = fileIconOffsetY;
496 currentIconOffsetX = fileIconOffsetX;
497 } else {
498 continue;
499 }
500
501 if (icon && icon->GetResource())
502 {
503 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
504 if (image_y + currentIconHeight > mRenderY + mRenderH)
505 rect_y = mRenderY + mRenderH - image_y;
506 else
507 rect_y = currentIconHeight;
508 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
509 }
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100510 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400511
512 // Add the separator
513 if (yPos + actualLineHeight < mRenderH + mRenderY) {
514 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100515 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400516 }
517
518 // Move the yPos
519 yPos += actualLineHeight;
520 }
521
522 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
523 // First step, fill background
524 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
525 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
526
527 // Now, we need the header (icon + text)
528 yPos = mRenderY;
529 {
530 Resource* headerIcon;
531 int mIconOffsetX = 0;
532
533 // render the icon if it exists
534 headerIcon = mHeaderIcon;
535 if (headerIcon && headerIcon->GetResource())
536 {
537 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
538 mIconOffsetX = mIconWidth;
539 }
540
541 // render the text
542 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
543 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
544
545 // Add the separator
546 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
547 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
548 }
549
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100550 // render fast scroll
551 lines = (mRenderH - mHeaderH) / (actualLineHeight);
552 if(mFastScrollW > 0 && folderSize + fileSize > lines)
553 {
554 int startX = listW + mRenderX;
555 int fWidth = mRenderW - listW;
556 int fHeight = mRenderH - mHeaderH;
557
558 // line
559 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
560 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
561
562 // rect
563 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((folderSize + fileSize)*actualLineHeight-lines*actualLineHeight);
564 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
565 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
566
567 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
568 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
569 }
570
Dees_Troy4622cf92013-03-01 15:29:36 -0600571 // If a change came in during the render then we need to do another redraw so leave mUpdate alone if updateFileList is true.
Dees_Troy4622cf92013-03-01 15:29:36 -0600572 if (!updateFileList) {
573 mUpdate = 0;
574 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400575 return 0;
576}
577
578int GUIFileSelector::Update(void)
579{
580 if (!mHeaderIsStatic) {
581 std::string newValue = gui_parse_text(mHeaderText);
582 if (mLastValue != newValue) {
583 mLastValue = newValue;
584 mUpdate = 1;
585 }
586 }
587
588 if (mUpdate)
589 {
590 mUpdate = 0;
591 if (Render() == 0)
592 return 2;
593 }
594
595 // Handle kinetic scrolling
596 if (scrollingSpeed == 0) {
597 // Do nothing
598 } else if (scrollingSpeed > 0) {
599 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
600 scrollingY += scrollingSpeed;
601 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
602 } else {
603 scrollingY += ((int) (actualLineHeight * 2.5));
604 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
605 }
606 while (mStart && scrollingY > 0) {
607 mStart--;
608 scrollingY -= actualLineHeight;
609 }
610 if (mStart == 0 && scrollingY > 0) {
611 scrollingY = 0;
612 scrollingSpeed = 0;
613 } else if (scrollingSpeed < SCROLLING_FLOOR)
614 scrollingSpeed = 0;
615 mUpdate = 1;
616 } else if (scrollingSpeed < 0) {
617 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
618 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
619
620 if (totalSize > lines) {
621 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
622
623 bottom_offset -= actualLineHeight;
624
625 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
626 scrollingY += scrollingSpeed;
627 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
628 } else {
629 scrollingY -= ((int) (actualLineHeight * 2.5));
630 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
631 }
632 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
633 mStart++;
634 scrollingY += actualLineHeight;
635 }
636 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
637 mStart = totalSize - lines - 1;
638 scrollingY = bottom_offset;
639 } else if (mStart + lines >= totalSize && scrollingY < 0) {
640 mStart = totalSize - lines;
641 scrollingY = 0;
642 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
643 scrollingSpeed = 0;
644 mUpdate = 1;
645 }
646 }
647
648 return 0;
649}
650
651int GUIFileSelector::GetSelection(int x, int y)
652{
653 // We only care about y position
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200654 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH)
655 return -1;
656
Dees_Troy51a0e822012-09-05 15:24:24 -0400657 return (y - mRenderY - mHeaderH);
658}
659
660int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
661{
Dees_Troy51a0e822012-09-05 15:24:24 -0400662 static int lastY = 0, last2Y = 0;
663 int selection = 0;
664
665 switch (state)
666 {
667 case TOUCH_START:
668 if (scrollingSpeed != 0)
669 startSelection = -1;
670 else
671 startSelection = GetSelection(x,y);
Dees_Troye7585ca2013-02-15 11:42:29 -0600672 isHighlighted = (startSelection > -1);
673 if (isHighlighted)
674 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400675 startY = lastY = last2Y = y;
676 scrollingSpeed = 0;
677 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400678 case TOUCH_DRAG:
679 // Check if we dragged out of the selection window
680 if (GetSelection(x, y) == -1) {
681 last2Y = lastY = 0;
Dees_Troye7585ca2013-02-15 11:42:29 -0600682 if (isHighlighted) {
683 isHighlighted = false;
684 mUpdate = 1;
685 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400686 break;
687 }
688
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100689 // Fast scroll
690 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
691 {
692 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
693 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
694 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
695
696 float l = float((totalSize-lines)*pct)/100;
697 if(l + lines >= totalSize)
698 {
699 mStart = totalSize - lines;
700 scrollingY = 0;
701 }
702 else
703 {
704 mStart = l;
705 scrollingY = -(l - int(l))*actualLineHeight;
706 }
707
708 startSelection = -1;
709 mUpdate = 1;
710 scrollingSpeed = 0;
711 isHighlighted = false;
712 break;
713 }
714
Dees_Troy51a0e822012-09-05 15:24:24 -0400715 // Provide some debounce on initial touches
716 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
Dees_Troye7585ca2013-02-15 11:42:29 -0600717 isHighlighted = true;
718 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400719 break;
720 }
721
Dees_Troye7585ca2013-02-15 11:42:29 -0600722 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400723 last2Y = lastY;
724 lastY = y;
725 startSelection = -1;
726
727 // Handle scrolling
728 scrollingY += y - startY;
729 startY = y;
730 while(mStart && scrollingY > 0) {
731 mStart--;
732 scrollingY -= actualLineHeight;
733 }
734 if (mStart == 0 && scrollingY > 0)
735 scrollingY = 0;
736 {
737 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
738 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
739
740 if (totalSize > lines) {
741 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
742
743 bottom_offset -= actualLineHeight;
744
745 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
746 mStart++;
747 scrollingY += actualLineHeight;
748 }
749 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
750 mStart = totalSize - lines - 1;
751 scrollingY = bottom_offset;
752 } else if (mStart + lines >= totalSize && scrollingY < 0) {
753 mStart = totalSize - lines;
754 scrollingY = 0;
755 }
756 } else
757 scrollingY = 0;
758 }
759 mUpdate = 1;
760 break;
761
762 case TOUCH_RELEASE:
Dees_Troye7585ca2013-02-15 11:42:29 -0600763 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400764 if (startSelection >= 0)
765 {
766 // We've selected an item!
767 std::string str;
768
769 int folderSize = mShowFolders ? mFolderList.size() : 0;
770 int fileSize = mShowFiles ? mFileList.size() : 0;
771 int selectY = scrollingY, actualSelection = mStart;
772
773 // Move the selection to the proper place in the array
774 while (selectY + actualLineHeight < startSelection) {
775 selectY += actualLineHeight;
776 actualSelection++;
777 }
778 startSelection = actualSelection;
779
780 if (startSelection < folderSize + fileSize)
781 {
782 if (startSelection < folderSize)
783 {
784 std::string oldcwd;
785 std::string cwd;
786
787 str = mFolderList.at(startSelection).fileName;
788 if (mSelection != "0")
789 DataManager::SetValue(mSelection, str);
790 DataManager::GetValue(mPathVar, cwd);
791
792 oldcwd = cwd;
793 // Ignore requests to do nothing
794 if (str == ".") return 0;
795 if (str == TW_FILESELECTOR_UP_A_LEVEL)
796 {
797 if (cwd != "/")
798 {
799 size_t found;
800 found = cwd.find_last_of('/');
801 cwd = cwd.substr(0,found);
802
803 if (cwd.length() < 2) cwd = "/";
804 }
805 }
806 else
807 {
808 // Add a slash if we're not the root folder
809 if (cwd != "/") cwd += "/";
810 cwd += str;
811 }
812
813 if (mShowNavFolders == 0 && mShowFiles == 0)
814 {
815 // This is a "folder" selection
816 DataManager::SetValue(mVariable, cwd);
817 }
818 else
819 {
820 DataManager::SetValue(mPathVar, cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400821 mStart = 0;
822 scrollingY = 0;
823 mUpdate = 1;
824 }
825 }
826 else if (!mVariable.empty())
827 {
828 str = mFileList.at(startSelection - folderSize).fileName;
829 if (mSelection != "0")
830 DataManager::SetValue(mSelection, str);
831
832 std::string cwd;
833 DataManager::GetValue(mPathVar, cwd);
834 if (cwd != "/") cwd += "/";
835 DataManager::SetValue(mVariable, cwd + str);
836 }
837 }
838 } else {
839 // This is for kinetic scrolling
840 scrollingSpeed = lastY - last2Y;
841 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
842 scrollingSpeed *= SCROLLING_MULTIPLIER;
843 else
844 scrollingSpeed = 0;
845 }
846 case TOUCH_REPEAT:
847 case TOUCH_HOLD:
848 break;
849 }
850 return 0;
851}
852
853int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
854{
Dees_Troy146d72a2013-03-11 17:46:19 +0000855 if (varName.empty()) {
856 // Always clear the data variable so we know to use it
857 DataManager::SetValue(mVariable, "");
858 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400859 if (!mHeaderIsStatic) {
860 std::string newValue = gui_parse_text(mHeaderText);
861 if (mLastValue != newValue) {
862 mLastValue = newValue;
863 mStart = 0;
864 scrollingY = 0;
865 scrollingSpeed = 0;
866 mUpdate = 1;
867 }
868 }
869 if (varName == mPathVar || varName == mSortVariable)
870 {
Dees_Troy4622cf92013-03-01 15:29:36 -0600871 if (varName == mSortVariable) {
872 DataManager::GetValue(mSortVariable, mSortOrder);
Dees_Troyc0583f52013-02-28 11:19:57 -0600873 }
874 updateFileList = true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400875 mStart = 0;
876 scrollingY = 0;
877 scrollingSpeed = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400878 mUpdate = 1;
879 return 0;
880 }
881 return 0;
882}
883
884int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
885{
886 mRenderX = x;
887 mRenderY = y;
888 if (w || h)
889 {
890 mRenderW = w;
891 mRenderH = h;
892 }
893 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
894 mUpdate = 1;
895 return 0;
896}
897
898bool GUIFileSelector::fileSort(FileData d1, FileData d2)
899{
900 if (d1.fileName == ".")
901 return -1;
902 if (d2.fileName == ".")
903 return 0;
904 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
905 return -1;
906 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
907 return 0;
908
909 switch (mSortOrder) {
910 case 3: // by size largest first
911 if (d1.fileSize == d2.fileSize || d1.fileType == DT_DIR) // some directories report a different size than others - but this is not the size of the files inside the directory, so we just sort by name on directories
912 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600913 return d1.fileSize < d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400914 case -3: // by size smallest first
915 if (d1.fileSize == d2.fileSize || d1.fileType == DT_DIR) // some directories report a different size than others - but this is not the size of the files inside the directory, so we just sort by name on directories
916 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600917 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400918 case 2: // by last modified date newest first
919 if (d1.lastModified == d2.lastModified)
920 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600921 return d1.lastModified < d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400922 case -2: // by date oldest first
923 if (d1.lastModified == d2.lastModified)
924 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600925 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400926 case -1: // by name descending
927 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
928 default: // should be a 1 - sort by name ascending
929 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
930 }
931}
932
933int GUIFileSelector::GetFileList(const std::string folder)
934{
935 DIR* d;
936 struct dirent* de;
937 struct stat st;
938
939 // Clear all data
940 mFolderList.clear();
941 mFileList.clear();
942
943 d = opendir(folder.c_str());
944 if (d == NULL)
945 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000946 LOGINFO("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000947 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
948 size_t found;
949 found = folder.find_last_of('/');
950 if (found != string::npos) {
951 string new_folder = folder.substr(0, found);
952
953 if (new_folder.length() < 2)
954 new_folder = "/";
955 DataManager::SetValue(mPathVar, new_folder);
956 }
957 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400958 return -1;
959 }
960
961 while ((de = readdir(d)) != NULL)
962 {
963 FileData data;
964
965 data.fileName = de->d_name;
966 if (data.fileName == ".")
967 continue;
968 if (data.fileName == ".." && folder == "/")
969 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000970 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400971 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000972 data.fileType = DT_DIR;
973 } else {
974 data.fileType = de->d_type;
975 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400976
977 std::string path = folder + "/" + data.fileName;
978 stat(path.c_str(), &st);
979 data.protection = st.st_mode;
980 data.userId = st.st_uid;
981 data.groupId = st.st_gid;
982 data.fileSize = st.st_size;
983 data.lastAccess = st.st_atime;
984 data.lastModified = st.st_mtime;
985 data.lastStatChange = st.st_ctime;
986
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000987 if (data.fileType == DT_UNKNOWN) {
988 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
989 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400990 if (data.fileType == DT_DIR)
991 {
992 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
993 mFolderList.push_back(data);
994 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -0400995 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -0400996 {
997 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
998 {
999 mFileList.push_back(data);
1000 }
1001 }
1002 }
1003 closedir(d);
1004
1005 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
1006 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -06001007
Dees_Troy51a0e822012-09-05 15:24:24 -04001008 return 0;
1009}
1010
1011void GUIFileSelector::SetPageFocus(int inFocus)
1012{
1013 if (inFocus)
1014 {
Dees_Troyc0583f52013-02-28 11:19:57 -06001015 updateFileList = true;
1016 scrollingY = 0;
1017 scrollingSpeed = 0;
1018 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001019 }
Dees_Troya13d74f2013-03-24 08:54:55 -05001020}