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