blob: 38eaadd204a332cb15c80317cbee70830e1e71cf [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001// FileSelector.cpp - GUIFileSelector object
2
3#include <linux/input.h>
4#include <pthread.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <fcntl.h>
10#include <sys/reboot.h>
11#include <sys/stat.h>
12#include <sys/time.h>
13#include <sys/mman.h>
14#include <sys/types.h>
15#include <sys/ioctl.h>
16#include <time.h>
17#include <unistd.h>
18#include <stdlib.h>
19#include <dirent.h>
20#include <ctype.h>
21
22#include <algorithm>
23
24extern "C" {
25#include "../common.h"
26#include "../roots.h"
27#include "../minuitwrp/minui.h"
28#include "../recovery_ui.h"
29}
30
31#include "rapidxml.hpp"
32#include "objects.hpp"
33#include "../data.hpp"
Dees_Troy3ee47bc2013-01-25 21:47:37 +000034#include "../twrp-functions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040035
36#define TW_FILESELECTOR_UP_A_LEVEL "(Up A Level)"
37
38#define SCROLLING_SPEED_DECREMENT 6
39#define SCROLLING_FLOOR 10
40#define SCROLLING_MULTIPLIER 6
41
42int GUIFileSelector::mSortOrder = 0;
43
44GUIFileSelector::GUIFileSelector(xml_node<>* node)
45{
46 xml_attribute<>* attr;
47 xml_node<>* child;
48 int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
49
50 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
51 mIconWidth = mIconHeight = mFolderIconHeight = mFileIconHeight = mFolderIconWidth = mFileIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
52 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
53 mFolderIcon = mFileIcon = mBackground = mFont = mHeaderIcon = NULL;
54 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
55 mShowFolders = mShowFiles = mShowNavFolders = 1;
56 mUpdate = 0;
57 touchDebounce = 6;
58 mPathVar = "cwd";
59 ConvertStrToColor("black", &mBackgroundColor);
60 ConvertStrToColor("black", &mHeaderBackgroundColor);
61 ConvertStrToColor("black", &mSeparatorColor);
62 ConvertStrToColor("black", &mHeaderSeparatorColor);
63 ConvertStrToColor("white", &mFontColor);
64 ConvertStrToColor("white", &mHeaderFontColor);
65
66 // Load header text
67 child = node->first_node("header");
68 if (child)
69 {
70 attr = child->first_attribute("icon");
71 if (attr)
72 mHeaderIcon = PageManager::FindResource(attr->value());
73
74 attr = child->first_attribute("background");
75 if (attr)
76 {
77 std::string color = attr->value();
78 ConvertStrToColor(color, &mHeaderBackgroundColor);
79 header_background_color_specified = -1;
80 }
81 attr = child->first_attribute("textcolor");
82 if (attr)
83 {
84 std::string color = attr->value();
85 ConvertStrToColor(color, &mHeaderFontColor);
86 header_text_color_specified = -1;
87 }
88 attr = child->first_attribute("separatorcolor");
89 if (attr)
90 {
91 std::string color = attr->value();
92 ConvertStrToColor(color, &mHeaderSeparatorColor);
93 header_separator_color_specified = -1;
94 }
95 attr = child->first_attribute("separatorheight");
96 if (attr) {
97 string parsevalue = gui_parse_text(attr->value());
98 mHeaderSeparatorH = atoi(parsevalue.c_str());
99 header_separator_height_specified = -1;
100 }
101 }
102 child = node->first_node("text");
103 if (child) mHeaderText = child->value();
104
105 // Simple way to check for static state
106 mLastValue = gui_parse_text(mHeaderText);
107 if (mLastValue != mHeaderText)
108 mHeaderIsStatic = 0;
109 else
110 mHeaderIsStatic = -1;
111
112 child = node->first_node("icon");
113 if (child)
114 {
115 attr = child->first_attribute("folder");
116 if (attr)
117 mFolderIcon = PageManager::FindResource(attr->value());
118 attr = child->first_attribute("file");
119 if (attr)
120 mFileIcon = PageManager::FindResource(attr->value());
121 }
122 child = node->first_node("background");
123 if (child)
124 {
125 attr = child->first_attribute("resource");
126 if (attr)
127 mBackground = PageManager::FindResource(attr->value());
128 attr = child->first_attribute("color");
129 if (attr)
130 {
131 std::string color = attr->value();
132 ConvertStrToColor(color, &mBackgroundColor);
133 if (!header_background_color_specified)
134 ConvertStrToColor(color, &mHeaderBackgroundColor);
135 }
136 }
137
138 // Load the placement
139 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
140 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
141
142 // Load the font, and possibly override the color
143 child = node->first_node("font");
144 if (child)
145 {
146 attr = child->first_attribute("resource");
147 if (attr)
148 mFont = PageManager::FindResource(attr->value());
149
150 attr = child->first_attribute("color");
151 if (attr)
152 {
153 std::string color = attr->value();
154 ConvertStrToColor(color, &mFontColor);
155 if (!header_text_color_specified)
156 ConvertStrToColor(color, &mHeaderFontColor);
157 }
158
159 attr = child->first_attribute("spacing");
160 if (attr) {
161 string parsevalue = gui_parse_text(attr->value());
162 mLineSpacing = atoi(parsevalue.c_str());
163 }
164 }
165
166 // Load the separator if it exists
167 child = node->first_node("separator");
168 if (child)
169 {
170 attr = child->first_attribute("color");
171 if (attr)
172 {
173 std::string color = attr->value();
174 ConvertStrToColor(color, &mSeparatorColor);
175 if (!header_separator_color_specified)
176 ConvertStrToColor(color, &mHeaderSeparatorColor);
177 }
178
179 attr = child->first_attribute("height");
180 if (attr) {
181 string parsevalue = gui_parse_text(attr->value());
182 mSeparatorH = atoi(parsevalue.c_str());
183 if (!header_separator_height_specified)
184 mHeaderSeparatorH = mSeparatorH;
185 }
186 }
187
188 child = node->first_node("filter");
189 if (child)
190 {
191 attr = child->first_attribute("extn");
192 if (attr)
193 mExtn = attr->value();
194 attr = child->first_attribute("folders");
195 if (attr)
196 mShowFolders = atoi(attr->value());
197 attr = child->first_attribute("files");
198 if (attr)
199 mShowFiles = atoi(attr->value());
200 attr = child->first_attribute("nav");
201 if (attr)
202 mShowNavFolders = atoi(attr->value());
203 }
204
205 // Handle the path variable
206 child = node->first_node("path");
207 if (child)
208 {
209 attr = child->first_attribute("name");
210 if (attr)
211 mPathVar = attr->value();
212 attr = child->first_attribute("default");
213 if (attr)
214 DataManager::SetValue(mPathVar, attr->value());
215 }
216
217 // Handle the result variable
218 child = node->first_node("data");
219 if (child)
220 {
221 attr = child->first_attribute("name");
222 if (attr)
223 mVariable = attr->value();
224 attr = child->first_attribute("default");
225 if (attr)
226 DataManager::SetValue(mVariable, attr->value());
227 }
228
229 // Handle the sort variable
230 child = node->first_node("sort");
231 if (child)
232 {
233 attr = child->first_attribute("name");
234 if (attr)
235 mSortVariable = attr->value();
236 attr = child->first_attribute("default");
237 if (attr)
238 DataManager::SetValue(mSortVariable, attr->value());
239
240 DataManager::GetValue(mSortVariable, mSortOrder);
241 }
242
243 // Handle the selection variable
244 child = node->first_node("selection");
245 if (child)
246 {
247 attr = child->first_attribute("name");
248 if (attr)
249 mSelection = attr->value();
250 else
251 mSelection = "0";
252 } else
253 mSelection = "0";
254
255 // Retrieve the line height
256 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
257 mLineHeight = mFontHeight;
258 mHeaderH = mFontHeight;
259
260 if (mFolderIcon && mFolderIcon->GetResource())
261 {
262 mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
263 mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
264 if (mFolderIconHeight > (int)mLineHeight)
265 mLineHeight = mFolderIconHeight;
266 mIconWidth = mFolderIconWidth;
267 }
268
269 if (mFileIcon && mFileIcon->GetResource())
270 {
271 mFileIconWidth = gr_get_width(mFileIcon->GetResource());
272 mFileIconHeight = gr_get_height(mFileIcon->GetResource());
273 if (mFileIconHeight > (int)mLineHeight)
274 mLineHeight = mFileIconHeight;
275 if (mFileIconWidth > mIconWidth)
276 mIconWidth = mFileIconWidth;
277 }
278
279 if (mHeaderIcon && mHeaderIcon->GetResource())
280 {
281 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
282 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
283 if (mHeaderIconHeight > mHeaderH)
284 mHeaderH = mHeaderIconHeight;
285 if (mHeaderIconWidth > mIconWidth)
286 mIconWidth = mHeaderIconWidth;
287 }
288
289 mHeaderH += mLineSpacing + mHeaderSeparatorH;
290 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
291 if (mHeaderH < actualLineHeight)
292 mHeaderH = actualLineHeight;
293
294 if (actualLineHeight / 3 > 6)
295 touchDebounce = actualLineHeight / 3;
296
297 if (mBackground && mBackground->GetResource())
298 {
299 mBackgroundW = gr_get_width(mBackground->GetResource());
300 mBackgroundH = gr_get_height(mBackground->GetResource());
301 }
302
303 // Fetch the file/folder list
304 std::string value;
305 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000306 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400307}
308
309GUIFileSelector::~GUIFileSelector()
310{
311}
312
313int GUIFileSelector::Render(void)
314{
315 // First step, fill background
316 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
317 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
318
319 // Next, render the background resource (if it exists)
320 if (mBackground && mBackground->GetResource())
321 {
322 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
323 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
324 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
325 }
326
327 // This tells us how many lines we can actually render
328 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
329 int line;
330
331 int folderSize = mShowFolders ? mFolderList.size() : 0;
332 int fileSize = mShowFiles ? mFileList.size() : 0;
333
334 if (folderSize + fileSize < lines) {
335 lines = folderSize + fileSize;
336 scrollingY = 0;
337 } else {
338 lines++;
339 if (lines < folderSize + fileSize)
340 lines++;
341 }
342
343 void* fontResource = NULL;
344 if (mFont) fontResource = mFont->GetResource();
345
346 int yPos = mRenderY + mHeaderH + scrollingY;
347 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
348 int currentIconHeight = 0, currentIconWidth = 0;
349 int currentIconOffsetY = 0, currentIconOffsetX = 0;
350 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
351 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
352
353 for (line = 0; line < lines; line++)
354 {
355 Resource* icon;
356 std::string label;
357
358 // Set the color for the font
359 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
360
361 if (line + mStart < folderSize)
362 {
363 icon = mFolderIcon;
364 label = mFolderList.at(line + mStart).fileName;
365 currentIconHeight = mFolderIconHeight;
366 currentIconWidth = mFolderIconWidth;
367 currentIconOffsetY = folderIconOffsetY;
368 currentIconOffsetX = folderIconOffsetX;
369 }
370 else if (line + mStart < folderSize + fileSize)
371 {
372 icon = mFileIcon;
373 label = mFileList.at((line + mStart) - folderSize).fileName;
374 currentIconHeight = mFileIconHeight;
375 currentIconWidth = mFileIconWidth;
376 currentIconOffsetY = fileIconOffsetY;
377 currentIconOffsetX = fileIconOffsetX;
378 } else {
379 continue;
380 }
381
382 if (icon && icon->GetResource())
383 {
384 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
385 if (image_y + currentIconHeight > mRenderY + mRenderH)
386 rect_y = mRenderY + mRenderH - image_y;
387 else
388 rect_y = currentIconHeight;
389 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
390 }
391 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
392
393 // Add the separator
394 if (yPos + actualLineHeight < mRenderH + mRenderY) {
395 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
396 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, mRenderW, mSeparatorH);
397 }
398
399 // Move the yPos
400 yPos += actualLineHeight;
401 }
402
403 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
404 // First step, fill background
405 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
406 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
407
408 // Now, we need the header (icon + text)
409 yPos = mRenderY;
410 {
411 Resource* headerIcon;
412 int mIconOffsetX = 0;
413
414 // render the icon if it exists
415 headerIcon = mHeaderIcon;
416 if (headerIcon && headerIcon->GetResource())
417 {
418 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
419 mIconOffsetX = mIconWidth;
420 }
421
422 // render the text
423 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
424 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
425
426 // Add the separator
427 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
428 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
429 }
430
431 mUpdate = 0;
432 return 0;
433}
434
435int GUIFileSelector::Update(void)
436{
437 if (!mHeaderIsStatic) {
438 std::string newValue = gui_parse_text(mHeaderText);
439 if (mLastValue != newValue) {
440 mLastValue = newValue;
441 mUpdate = 1;
442 }
443 }
444
445 if (mUpdate)
446 {
447 mUpdate = 0;
448 if (Render() == 0)
449 return 2;
450 }
451
452 // Handle kinetic scrolling
453 if (scrollingSpeed == 0) {
454 // Do nothing
455 } else if (scrollingSpeed > 0) {
456 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
457 scrollingY += scrollingSpeed;
458 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
459 } else {
460 scrollingY += ((int) (actualLineHeight * 2.5));
461 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
462 }
463 while (mStart && scrollingY > 0) {
464 mStart--;
465 scrollingY -= actualLineHeight;
466 }
467 if (mStart == 0 && scrollingY > 0) {
468 scrollingY = 0;
469 scrollingSpeed = 0;
470 } else if (scrollingSpeed < SCROLLING_FLOOR)
471 scrollingSpeed = 0;
472 mUpdate = 1;
473 } else if (scrollingSpeed < 0) {
474 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
475 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
476
477 if (totalSize > lines) {
478 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
479
480 bottom_offset -= actualLineHeight;
481
482 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
483 scrollingY += scrollingSpeed;
484 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
485 } else {
486 scrollingY -= ((int) (actualLineHeight * 2.5));
487 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
488 }
489 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
490 mStart++;
491 scrollingY += actualLineHeight;
492 }
493 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
494 mStart = totalSize - lines - 1;
495 scrollingY = bottom_offset;
496 } else if (mStart + lines >= totalSize && scrollingY < 0) {
497 mStart = totalSize - lines;
498 scrollingY = 0;
499 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
500 scrollingSpeed = 0;
501 mUpdate = 1;
502 }
503 }
504
505 return 0;
506}
507
508int GUIFileSelector::GetSelection(int x, int y)
509{
510 // We only care about y position
511 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
512 return (y - mRenderY - mHeaderH);
513}
514
515int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
516{
517 static int startSelection = -1;
518 static int lastY = 0, last2Y = 0;
519 int selection = 0;
520
521 switch (state)
522 {
523 case TOUCH_START:
524 if (scrollingSpeed != 0)
525 startSelection = -1;
526 else
527 startSelection = GetSelection(x,y);
528 startY = lastY = last2Y = y;
529 scrollingSpeed = 0;
530 break;
531
532 case TOUCH_DRAG:
533 // Check if we dragged out of the selection window
534 if (GetSelection(x, y) == -1) {
535 last2Y = lastY = 0;
536 break;
537 }
538
539 // Provide some debounce on initial touches
540 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
541 break;
542 }
543
544 last2Y = lastY;
545 lastY = y;
546 startSelection = -1;
547
548 // Handle scrolling
549 scrollingY += y - startY;
550 startY = y;
551 while(mStart && scrollingY > 0) {
552 mStart--;
553 scrollingY -= actualLineHeight;
554 }
555 if (mStart == 0 && scrollingY > 0)
556 scrollingY = 0;
557 {
558 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
559 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
560
561 if (totalSize > lines) {
562 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
563
564 bottom_offset -= actualLineHeight;
565
566 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
567 mStart++;
568 scrollingY += actualLineHeight;
569 }
570 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
571 mStart = totalSize - lines - 1;
572 scrollingY = bottom_offset;
573 } else if (mStart + lines >= totalSize && scrollingY < 0) {
574 mStart = totalSize - lines;
575 scrollingY = 0;
576 }
577 } else
578 scrollingY = 0;
579 }
580 mUpdate = 1;
581 break;
582
583 case TOUCH_RELEASE:
584 if (startSelection >= 0)
585 {
586 // We've selected an item!
587 std::string str;
588
589 int folderSize = mShowFolders ? mFolderList.size() : 0;
590 int fileSize = mShowFiles ? mFileList.size() : 0;
591 int selectY = scrollingY, actualSelection = mStart;
592
593 // Move the selection to the proper place in the array
594 while (selectY + actualLineHeight < startSelection) {
595 selectY += actualLineHeight;
596 actualSelection++;
597 }
598 startSelection = actualSelection;
599
600 if (startSelection < folderSize + fileSize)
601 {
602 if (startSelection < folderSize)
603 {
604 std::string oldcwd;
605 std::string cwd;
606
607 str = mFolderList.at(startSelection).fileName;
608 if (mSelection != "0")
609 DataManager::SetValue(mSelection, str);
610 DataManager::GetValue(mPathVar, cwd);
611
612 oldcwd = cwd;
613 // Ignore requests to do nothing
614 if (str == ".") return 0;
615 if (str == TW_FILESELECTOR_UP_A_LEVEL)
616 {
617 if (cwd != "/")
618 {
619 size_t found;
620 found = cwd.find_last_of('/');
621 cwd = cwd.substr(0,found);
622
623 if (cwd.length() < 2) cwd = "/";
624 }
625 }
626 else
627 {
628 // Add a slash if we're not the root folder
629 if (cwd != "/") cwd += "/";
630 cwd += str;
631 }
632
633 if (mShowNavFolders == 0 && mShowFiles == 0)
634 {
635 // This is a "folder" selection
636 DataManager::SetValue(mVariable, cwd);
637 }
638 else
639 {
640 DataManager::SetValue(mPathVar, cwd);
Dees_Troy80a11d92013-01-25 16:36:07 +0000641 GetFileList(cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400642 mStart = 0;
643 scrollingY = 0;
644 mUpdate = 1;
645 }
646 }
647 else if (!mVariable.empty())
648 {
649 str = mFileList.at(startSelection - folderSize).fileName;
650 if (mSelection != "0")
651 DataManager::SetValue(mSelection, str);
652
653 std::string cwd;
654 DataManager::GetValue(mPathVar, cwd);
655 if (cwd != "/") cwd += "/";
656 DataManager::SetValue(mVariable, cwd + str);
657 }
658 }
659 } else {
660 // This is for kinetic scrolling
661 scrollingSpeed = lastY - last2Y;
662 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
663 scrollingSpeed *= SCROLLING_MULTIPLIER;
664 else
665 scrollingSpeed = 0;
666 }
667 case TOUCH_REPEAT:
668 case TOUCH_HOLD:
669 break;
670 }
671 return 0;
672}
673
674int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
675{
676 if (varName.empty())
677 {
678 // Always clear the data variable so we know to use it
679 DataManager::SetValue(mVariable, "");
680 }
681 if (!mHeaderIsStatic) {
682 std::string newValue = gui_parse_text(mHeaderText);
683 if (mLastValue != newValue) {
684 mLastValue = newValue;
685 mStart = 0;
686 scrollingY = 0;
687 scrollingSpeed = 0;
688 mUpdate = 1;
689 }
690 }
691 if (varName == mPathVar || varName == mSortVariable)
692 {
693 DataManager::GetValue(mPathVar, value); // sometimes the value will be the sort order instead of the path, so we read the path everytime
694 DataManager::GetValue(mSortVariable, mSortOrder);
695 mStart = 0;
696 scrollingY = 0;
697 scrollingSpeed = 0;
698 GetFileList(value);
699 mUpdate = 1;
700 return 0;
701 }
702 return 0;
703}
704
705int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
706{
707 mRenderX = x;
708 mRenderY = y;
709 if (w || h)
710 {
711 mRenderW = w;
712 mRenderH = h;
713 }
714 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
715 mUpdate = 1;
716 return 0;
717}
718
719bool GUIFileSelector::fileSort(FileData d1, FileData d2)
720{
721 if (d1.fileName == ".")
722 return -1;
723 if (d2.fileName == ".")
724 return 0;
725 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
726 return -1;
727 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
728 return 0;
729
730 switch (mSortOrder) {
731 case 3: // by size largest first
732 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
733 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
734 return d1.fileSize > d2.fileSize;
735 case -3: // by size smallest first
736 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
737 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
738 return d1.fileSize < d2.fileSize;
739 case 2: // by last modified date newest first
740 if (d1.lastModified == d2.lastModified)
741 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
742 return d1.lastModified > d2.lastModified;
743 case -2: // by date oldest first
744 if (d1.lastModified == d2.lastModified)
745 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
746 return d1.lastModified < d2.lastModified;
747 case -1: // by name descending
748 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
749 default: // should be a 1 - sort by name ascending
750 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
751 }
752}
753
754int GUIFileSelector::GetFileList(const std::string folder)
755{
756 DIR* d;
757 struct dirent* de;
758 struct stat st;
759
760 // Clear all data
761 mFolderList.clear();
762 mFileList.clear();
763
764 d = opendir(folder.c_str());
765 if (d == NULL)
766 {
767 LOGI("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000768 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
769 size_t found;
770 found = folder.find_last_of('/');
771 if (found != string::npos) {
772 string new_folder = folder.substr(0, found);
773
774 if (new_folder.length() < 2)
775 new_folder = "/";
776 DataManager::SetValue(mPathVar, new_folder);
777 }
778 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400779 return -1;
780 }
781
782 while ((de = readdir(d)) != NULL)
783 {
784 FileData data;
785
786 data.fileName = de->d_name;
787 if (data.fileName == ".")
788 continue;
789 if (data.fileName == ".." && folder == "/")
790 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000791 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400792 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000793 data.fileType = DT_DIR;
794 } else {
795 data.fileType = de->d_type;
796 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400797
798 std::string path = folder + "/" + data.fileName;
799 stat(path.c_str(), &st);
800 data.protection = st.st_mode;
801 data.userId = st.st_uid;
802 data.groupId = st.st_gid;
803 data.fileSize = st.st_size;
804 data.lastAccess = st.st_atime;
805 data.lastModified = st.st_mtime;
806 data.lastStatChange = st.st_ctime;
807
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000808 if (data.fileType == DT_UNKNOWN) {
809 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
810 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400811 if (data.fileType == DT_DIR)
812 {
813 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
814 mFolderList.push_back(data);
815 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -0400816 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -0400817 {
818 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
819 {
820 mFileList.push_back(data);
821 }
822 }
823 }
824 closedir(d);
825
826 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
827 std::sort(mFileList.begin(), mFileList.end(), fileSort);
828 return 0;
829}
830
831void GUIFileSelector::SetPageFocus(int inFocus)
832{
833 if (inFocus)
834 {
835 std::string value;
836 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000837 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400838 }
839}
840