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