blob: 4da72d8273b731027f1bc601f4a576f4bb9c2581 [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;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010056 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
57 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040058 mUpdate = 0;
59 touchDebounce = 6;
60 mPathVar = "cwd";
61 ConvertStrToColor("black", &mBackgroundColor);
62 ConvertStrToColor("black", &mHeaderBackgroundColor);
63 ConvertStrToColor("black", &mSeparatorColor);
64 ConvertStrToColor("black", &mHeaderSeparatorColor);
65 ConvertStrToColor("white", &mFontColor);
66 ConvertStrToColor("white", &mHeaderFontColor);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010067 ConvertStrToColor("white", &mFastScrollLineColor);
68 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troye7585ca2013-02-15 11:42:29 -060069 hasHighlightColor = false;
70 hasFontHighlightColor = false;
71 isHighlighted = false;
Dees_Troyc0583f52013-02-28 11:19:57 -060072 updateFileList = false;
Dees_Troye7585ca2013-02-15 11:42:29 -060073 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040074
75 // Load header text
76 child = node->first_node("header");
77 if (child)
78 {
79 attr = child->first_attribute("icon");
80 if (attr)
81 mHeaderIcon = PageManager::FindResource(attr->value());
82
83 attr = child->first_attribute("background");
84 if (attr)
85 {
86 std::string color = attr->value();
87 ConvertStrToColor(color, &mHeaderBackgroundColor);
88 header_background_color_specified = -1;
89 }
90 attr = child->first_attribute("textcolor");
91 if (attr)
92 {
93 std::string color = attr->value();
94 ConvertStrToColor(color, &mHeaderFontColor);
95 header_text_color_specified = -1;
96 }
97 attr = child->first_attribute("separatorcolor");
98 if (attr)
99 {
100 std::string color = attr->value();
101 ConvertStrToColor(color, &mHeaderSeparatorColor);
102 header_separator_color_specified = -1;
103 }
104 attr = child->first_attribute("separatorheight");
105 if (attr) {
106 string parsevalue = gui_parse_text(attr->value());
107 mHeaderSeparatorH = atoi(parsevalue.c_str());
108 header_separator_height_specified = -1;
109 }
110 }
111 child = node->first_node("text");
112 if (child) mHeaderText = child->value();
113
Dees_Troye7585ca2013-02-15 11:42:29 -0600114 memset(&mHighlightColor, 0, sizeof(COLOR));
115 child = node->first_node("highlight");
116 if (child) {
117 attr = child->first_attribute("color");
118 if (attr) {
119 hasHighlightColor = true;
120 std::string color = attr->value();
121 ConvertStrToColor(color, &mHighlightColor);
122 }
123 }
124
Dees_Troy51a0e822012-09-05 15:24:24 -0400125 // Simple way to check for static state
126 mLastValue = gui_parse_text(mHeaderText);
127 if (mLastValue != mHeaderText)
128 mHeaderIsStatic = 0;
129 else
130 mHeaderIsStatic = -1;
131
132 child = node->first_node("icon");
133 if (child)
134 {
135 attr = child->first_attribute("folder");
136 if (attr)
137 mFolderIcon = PageManager::FindResource(attr->value());
138 attr = child->first_attribute("file");
139 if (attr)
140 mFileIcon = PageManager::FindResource(attr->value());
141 }
142 child = node->first_node("background");
143 if (child)
144 {
145 attr = child->first_attribute("resource");
146 if (attr)
147 mBackground = PageManager::FindResource(attr->value());
148 attr = child->first_attribute("color");
149 if (attr)
150 {
151 std::string color = attr->value();
152 ConvertStrToColor(color, &mBackgroundColor);
153 if (!header_background_color_specified)
154 ConvertStrToColor(color, &mHeaderBackgroundColor);
155 }
156 }
157
158 // Load the placement
159 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
160 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
161
162 // Load the font, and possibly override the color
163 child = node->first_node("font");
164 if (child)
165 {
166 attr = child->first_attribute("resource");
167 if (attr)
168 mFont = PageManager::FindResource(attr->value());
169
170 attr = child->first_attribute("color");
171 if (attr)
172 {
173 std::string color = attr->value();
174 ConvertStrToColor(color, &mFontColor);
175 if (!header_text_color_specified)
176 ConvertStrToColor(color, &mHeaderFontColor);
177 }
178
179 attr = child->first_attribute("spacing");
180 if (attr) {
181 string parsevalue = gui_parse_text(attr->value());
182 mLineSpacing = atoi(parsevalue.c_str());
183 }
Dees_Troye7585ca2013-02-15 11:42:29 -0600184
185 attr = child->first_attribute("highlightcolor");
186 memset(&mFontHighlightColor, 0, sizeof(COLOR));
187 if (attr)
188 {
189 std::string color = attr->value();
190 ConvertStrToColor(color, &mFontHighlightColor);
191 hasFontHighlightColor = true;
192 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400193 }
194
195 // Load the separator if it exists
196 child = node->first_node("separator");
197 if (child)
198 {
199 attr = child->first_attribute("color");
200 if (attr)
201 {
202 std::string color = attr->value();
203 ConvertStrToColor(color, &mSeparatorColor);
204 if (!header_separator_color_specified)
205 ConvertStrToColor(color, &mHeaderSeparatorColor);
206 }
207
208 attr = child->first_attribute("height");
209 if (attr) {
210 string parsevalue = gui_parse_text(attr->value());
211 mSeparatorH = atoi(parsevalue.c_str());
212 if (!header_separator_height_specified)
213 mHeaderSeparatorH = mSeparatorH;
214 }
215 }
216
217 child = node->first_node("filter");
218 if (child)
219 {
220 attr = child->first_attribute("extn");
221 if (attr)
222 mExtn = attr->value();
223 attr = child->first_attribute("folders");
224 if (attr)
225 mShowFolders = atoi(attr->value());
226 attr = child->first_attribute("files");
227 if (attr)
228 mShowFiles = atoi(attr->value());
229 attr = child->first_attribute("nav");
230 if (attr)
231 mShowNavFolders = atoi(attr->value());
232 }
233
234 // Handle the path variable
235 child = node->first_node("path");
236 if (child)
237 {
238 attr = child->first_attribute("name");
239 if (attr)
240 mPathVar = attr->value();
241 attr = child->first_attribute("default");
242 if (attr)
243 DataManager::SetValue(mPathVar, attr->value());
244 }
245
246 // Handle the result variable
247 child = node->first_node("data");
248 if (child)
249 {
250 attr = child->first_attribute("name");
251 if (attr)
252 mVariable = attr->value();
253 attr = child->first_attribute("default");
254 if (attr)
255 DataManager::SetValue(mVariable, attr->value());
256 }
257
258 // Handle the sort variable
259 child = node->first_node("sort");
260 if (child)
261 {
262 attr = child->first_attribute("name");
263 if (attr)
264 mSortVariable = attr->value();
265 attr = child->first_attribute("default");
266 if (attr)
267 DataManager::SetValue(mSortVariable, attr->value());
268
269 DataManager::GetValue(mSortVariable, mSortOrder);
270 }
271
272 // Handle the selection variable
273 child = node->first_node("selection");
274 if (child)
275 {
276 attr = child->first_attribute("name");
277 if (attr)
278 mSelection = attr->value();
279 else
280 mSelection = "0";
281 } else
282 mSelection = "0";
283
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100284 // Fast scroll colors
285 child = node->first_node("fastscroll");
286 if (child)
287 {
288 attr = child->first_attribute("linecolor");
289 if(attr)
290 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
291
292 attr = child->first_attribute("rectcolor");
293 if(attr)
294 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
295
296 attr = child->first_attribute("w");
297 if (attr) {
298 string parsevalue = gui_parse_text(attr->value());
299 mFastScrollW = atoi(parsevalue.c_str());
300 }
301
302 attr = child->first_attribute("linew");
303 if (attr) {
304 string parsevalue = gui_parse_text(attr->value());
305 mFastScrollLineW = atoi(parsevalue.c_str());
306 }
307
308 attr = child->first_attribute("rectw");
309 if (attr) {
310 string parsevalue = gui_parse_text(attr->value());
311 mFastScrollRectW = atoi(parsevalue.c_str());
312 }
313
314 attr = child->first_attribute("recth");
315 if (attr) {
316 string parsevalue = gui_parse_text(attr->value());
317 mFastScrollRectH = atoi(parsevalue.c_str());
318 }
319 }
320
Dees_Troy51a0e822012-09-05 15:24:24 -0400321 // Retrieve the line height
322 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
323 mLineHeight = mFontHeight;
324 mHeaderH = mFontHeight;
325
326 if (mFolderIcon && mFolderIcon->GetResource())
327 {
328 mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
329 mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
330 if (mFolderIconHeight > (int)mLineHeight)
331 mLineHeight = mFolderIconHeight;
332 mIconWidth = mFolderIconWidth;
333 }
334
335 if (mFileIcon && mFileIcon->GetResource())
336 {
337 mFileIconWidth = gr_get_width(mFileIcon->GetResource());
338 mFileIconHeight = gr_get_height(mFileIcon->GetResource());
339 if (mFileIconHeight > (int)mLineHeight)
340 mLineHeight = mFileIconHeight;
341 if (mFileIconWidth > mIconWidth)
342 mIconWidth = mFileIconWidth;
343 }
344
345 if (mHeaderIcon && mHeaderIcon->GetResource())
346 {
347 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
348 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
349 if (mHeaderIconHeight > mHeaderH)
350 mHeaderH = mHeaderIconHeight;
351 if (mHeaderIconWidth > mIconWidth)
352 mIconWidth = mHeaderIconWidth;
353 }
354
355 mHeaderH += mLineSpacing + mHeaderSeparatorH;
356 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
357 if (mHeaderH < actualLineHeight)
358 mHeaderH = actualLineHeight;
359
360 if (actualLineHeight / 3 > 6)
361 touchDebounce = actualLineHeight / 3;
362
363 if (mBackground && mBackground->GetResource())
364 {
365 mBackgroundW = gr_get_width(mBackground->GetResource());
366 mBackgroundH = gr_get_height(mBackground->GetResource());
367 }
368
369 // Fetch the file/folder list
370 std::string value;
371 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000372 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400373}
374
375GUIFileSelector::~GUIFileSelector()
376{
377}
378
379int GUIFileSelector::Render(void)
380{
Dees_Troyc0583f52013-02-28 11:19:57 -0600381 // Update the file list if needed
382 if (updateFileList) {
383 string value;
384 DataManager::GetValue(mPathVar, value);
385 GetFileList(value);
386 updateFileList = false;
387 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400388 // First step, fill background
389 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
390 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
391
392 // Next, render the background resource (if it exists)
393 if (mBackground && mBackground->GetResource())
394 {
395 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
396 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
397 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
398 }
399
400 // This tells us how many lines we can actually render
401 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
402 int line;
403
404 int folderSize = mShowFolders ? mFolderList.size() : 0;
405 int fileSize = mShowFiles ? mFileList.size() : 0;
406
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100407 int listW = mRenderW;
408
Dees_Troy51a0e822012-09-05 15:24:24 -0400409 if (folderSize + fileSize < lines) {
410 lines = folderSize + fileSize;
411 scrollingY = 0;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100412 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400413 } else {
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100414 listW -= mFastScrollW; // space for fast scroll
Dees_Troy51a0e822012-09-05 15:24:24 -0400415 lines++;
416 if (lines < folderSize + fileSize)
417 lines++;
418 }
419
420 void* fontResource = NULL;
421 if (mFont) fontResource = mFont->GetResource();
422
423 int yPos = mRenderY + mHeaderH + scrollingY;
424 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
425 int currentIconHeight = 0, currentIconWidth = 0;
426 int currentIconOffsetY = 0, currentIconOffsetX = 0;
427 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
428 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
Dees_Troye7585ca2013-02-15 11:42:29 -0600429 int actualSelection = mStart;
430
431 if (isHighlighted) {
432 int selectY = scrollingY;
433
434 // Locate the correct line for highlighting
435 while (selectY + actualLineHeight < startSelection) {
436 selectY += actualLineHeight;
437 actualSelection++;
438 }
439 if (hasHighlightColor) {
440 // Highlight the area
441 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
442 int HighlightHeight = actualLineHeight;
443 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
444 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
445 }
446 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
447 }
448 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400449
450 for (line = 0; line < lines; line++)
451 {
452 Resource* icon;
453 std::string label;
454
Dees_Troye7585ca2013-02-15 11:42:29 -0600455 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
456 // Use the highlight color for the font
457 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
458 } else {
459 // Set the color for the font
460 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
461 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400462
463 if (line + mStart < folderSize)
464 {
465 icon = mFolderIcon;
466 label = mFolderList.at(line + mStart).fileName;
467 currentIconHeight = mFolderIconHeight;
468 currentIconWidth = mFolderIconWidth;
469 currentIconOffsetY = folderIconOffsetY;
470 currentIconOffsetX = folderIconOffsetX;
471 }
472 else if (line + mStart < folderSize + fileSize)
473 {
474 icon = mFileIcon;
475 label = mFileList.at((line + mStart) - folderSize).fileName;
476 currentIconHeight = mFileIconHeight;
477 currentIconWidth = mFileIconWidth;
478 currentIconOffsetY = fileIconOffsetY;
479 currentIconOffsetX = fileIconOffsetX;
480 } else {
481 continue;
482 }
483
484 if (icon && icon->GetResource())
485 {
486 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
487 if (image_y + currentIconHeight > mRenderY + mRenderH)
488 rect_y = mRenderY + mRenderH - image_y;
489 else
490 rect_y = currentIconHeight;
491 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
492 }
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100493 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400494
495 // Add the separator
496 if (yPos + actualLineHeight < mRenderH + mRenderY) {
497 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100498 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400499 }
500
501 // Move the yPos
502 yPos += actualLineHeight;
503 }
504
505 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
506 // First step, fill background
507 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
508 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
509
510 // Now, we need the header (icon + text)
511 yPos = mRenderY;
512 {
513 Resource* headerIcon;
514 int mIconOffsetX = 0;
515
516 // render the icon if it exists
517 headerIcon = mHeaderIcon;
518 if (headerIcon && headerIcon->GetResource())
519 {
520 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
521 mIconOffsetX = mIconWidth;
522 }
523
524 // render the text
525 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
526 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
527
528 // Add the separator
529 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
530 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
531 }
532
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100533 // render fast scroll
534 lines = (mRenderH - mHeaderH) / (actualLineHeight);
535 if(mFastScrollW > 0 && folderSize + fileSize > lines)
536 {
537 int startX = listW + mRenderX;
538 int fWidth = mRenderW - listW;
539 int fHeight = mRenderH - mHeaderH;
540
541 // line
542 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
543 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
544
545 // rect
546 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((folderSize + fileSize)*actualLineHeight-lines*actualLineHeight);
547 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
548 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
549
550 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
551 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
552 }
553
Dees_Troy51a0e822012-09-05 15:24:24 -0400554 mUpdate = 0;
555 return 0;
556}
557
558int GUIFileSelector::Update(void)
559{
560 if (!mHeaderIsStatic) {
561 std::string newValue = gui_parse_text(mHeaderText);
562 if (mLastValue != newValue) {
563 mLastValue = newValue;
564 mUpdate = 1;
565 }
566 }
567
568 if (mUpdate)
569 {
570 mUpdate = 0;
571 if (Render() == 0)
572 return 2;
573 }
574
575 // Handle kinetic scrolling
576 if (scrollingSpeed == 0) {
577 // Do nothing
578 } else if (scrollingSpeed > 0) {
579 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
580 scrollingY += scrollingSpeed;
581 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
582 } else {
583 scrollingY += ((int) (actualLineHeight * 2.5));
584 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
585 }
586 while (mStart && scrollingY > 0) {
587 mStart--;
588 scrollingY -= actualLineHeight;
589 }
590 if (mStart == 0 && scrollingY > 0) {
591 scrollingY = 0;
592 scrollingSpeed = 0;
593 } else if (scrollingSpeed < SCROLLING_FLOOR)
594 scrollingSpeed = 0;
595 mUpdate = 1;
596 } else if (scrollingSpeed < 0) {
597 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
598 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
599
600 if (totalSize > lines) {
601 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
602
603 bottom_offset -= actualLineHeight;
604
605 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
606 scrollingY += scrollingSpeed;
607 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
608 } else {
609 scrollingY -= ((int) (actualLineHeight * 2.5));
610 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
611 }
612 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
613 mStart++;
614 scrollingY += actualLineHeight;
615 }
616 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
617 mStart = totalSize - lines - 1;
618 scrollingY = bottom_offset;
619 } else if (mStart + lines >= totalSize && scrollingY < 0) {
620 mStart = totalSize - lines;
621 scrollingY = 0;
622 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
623 scrollingSpeed = 0;
624 mUpdate = 1;
625 }
626 }
627
628 return 0;
629}
630
631int GUIFileSelector::GetSelection(int x, int y)
632{
633 // We only care about y position
634 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
635 return (y - mRenderY - mHeaderH);
636}
637
638int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
639{
Dees_Troy51a0e822012-09-05 15:24:24 -0400640 static int lastY = 0, last2Y = 0;
641 int selection = 0;
642
643 switch (state)
644 {
645 case TOUCH_START:
646 if (scrollingSpeed != 0)
647 startSelection = -1;
648 else
649 startSelection = GetSelection(x,y);
Dees_Troye7585ca2013-02-15 11:42:29 -0600650 isHighlighted = (startSelection > -1);
651 if (isHighlighted)
652 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400653 startY = lastY = last2Y = y;
654 scrollingSpeed = 0;
655 break;
656
657 case TOUCH_DRAG:
658 // Check if we dragged out of the selection window
659 if (GetSelection(x, y) == -1) {
660 last2Y = lastY = 0;
Dees_Troye7585ca2013-02-15 11:42:29 -0600661 if (isHighlighted) {
662 isHighlighted = false;
663 mUpdate = 1;
664 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400665 break;
666 }
667
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100668 // Fast scroll
669 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
670 {
671 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
672 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
673 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
674
675 float l = float((totalSize-lines)*pct)/100;
676 if(l + lines >= totalSize)
677 {
678 mStart = totalSize - lines;
679 scrollingY = 0;
680 }
681 else
682 {
683 mStart = l;
684 scrollingY = -(l - int(l))*actualLineHeight;
685 }
686
687 startSelection = -1;
688 mUpdate = 1;
689 scrollingSpeed = 0;
690 isHighlighted = false;
691 break;
692 }
693
Dees_Troy51a0e822012-09-05 15:24:24 -0400694 // Provide some debounce on initial touches
695 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
Dees_Troye7585ca2013-02-15 11:42:29 -0600696 isHighlighted = true;
697 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400698 break;
699 }
700
Dees_Troye7585ca2013-02-15 11:42:29 -0600701 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400702 last2Y = lastY;
703 lastY = y;
704 startSelection = -1;
705
706 // Handle scrolling
707 scrollingY += y - startY;
708 startY = y;
709 while(mStart && scrollingY > 0) {
710 mStart--;
711 scrollingY -= actualLineHeight;
712 }
713 if (mStart == 0 && scrollingY > 0)
714 scrollingY = 0;
715 {
716 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
717 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
718
719 if (totalSize > lines) {
720 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
721
722 bottom_offset -= actualLineHeight;
723
724 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
725 mStart++;
726 scrollingY += actualLineHeight;
727 }
728 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
729 mStart = totalSize - lines - 1;
730 scrollingY = bottom_offset;
731 } else if (mStart + lines >= totalSize && scrollingY < 0) {
732 mStart = totalSize - lines;
733 scrollingY = 0;
734 }
735 } else
736 scrollingY = 0;
737 }
738 mUpdate = 1;
739 break;
740
741 case TOUCH_RELEASE:
Dees_Troye7585ca2013-02-15 11:42:29 -0600742 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400743 if (startSelection >= 0)
744 {
745 // We've selected an item!
746 std::string str;
747
748 int folderSize = mShowFolders ? mFolderList.size() : 0;
749 int fileSize = mShowFiles ? mFileList.size() : 0;
750 int selectY = scrollingY, actualSelection = mStart;
751
752 // Move the selection to the proper place in the array
753 while (selectY + actualLineHeight < startSelection) {
754 selectY += actualLineHeight;
755 actualSelection++;
756 }
757 startSelection = actualSelection;
758
759 if (startSelection < folderSize + fileSize)
760 {
761 if (startSelection < folderSize)
762 {
763 std::string oldcwd;
764 std::string cwd;
765
766 str = mFolderList.at(startSelection).fileName;
767 if (mSelection != "0")
768 DataManager::SetValue(mSelection, str);
769 DataManager::GetValue(mPathVar, cwd);
770
771 oldcwd = cwd;
772 // Ignore requests to do nothing
773 if (str == ".") return 0;
774 if (str == TW_FILESELECTOR_UP_A_LEVEL)
775 {
776 if (cwd != "/")
777 {
778 size_t found;
779 found = cwd.find_last_of('/');
780 cwd = cwd.substr(0,found);
781
782 if (cwd.length() < 2) cwd = "/";
783 }
784 }
785 else
786 {
787 // Add a slash if we're not the root folder
788 if (cwd != "/") cwd += "/";
789 cwd += str;
790 }
791
792 if (mShowNavFolders == 0 && mShowFiles == 0)
793 {
794 // This is a "folder" selection
795 DataManager::SetValue(mVariable, cwd);
796 }
797 else
798 {
799 DataManager::SetValue(mPathVar, cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400800 mStart = 0;
801 scrollingY = 0;
802 mUpdate = 1;
803 }
804 }
805 else if (!mVariable.empty())
806 {
807 str = mFileList.at(startSelection - folderSize).fileName;
808 if (mSelection != "0")
809 DataManager::SetValue(mSelection, str);
810
811 std::string cwd;
812 DataManager::GetValue(mPathVar, cwd);
813 if (cwd != "/") cwd += "/";
814 DataManager::SetValue(mVariable, cwd + str);
815 }
816 }
817 } else {
818 // This is for kinetic scrolling
819 scrollingSpeed = lastY - last2Y;
820 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
821 scrollingSpeed *= SCROLLING_MULTIPLIER;
822 else
823 scrollingSpeed = 0;
824 }
825 case TOUCH_REPEAT:
826 case TOUCH_HOLD:
827 break;
828 }
829 return 0;
830}
831
832int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
833{
Dees_Troy51a0e822012-09-05 15:24:24 -0400834 if (!mHeaderIsStatic) {
835 std::string newValue = gui_parse_text(mHeaderText);
836 if (mLastValue != newValue) {
837 mLastValue = newValue;
838 mStart = 0;
839 scrollingY = 0;
840 scrollingSpeed = 0;
841 mUpdate = 1;
842 }
843 }
844 if (varName == mPathVar || varName == mSortVariable)
845 {
Dees_Troyc0583f52013-02-28 11:19:57 -0600846 // If needed, wait for render to finish before continuing or the list change may not register
847 while (updateFileList || mUpdate) {
848 usleep(500);
849 }
850 updateFileList = true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400851 mStart = 0;
852 scrollingY = 0;
853 scrollingSpeed = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400854 mUpdate = 1;
855 return 0;
856 }
857 return 0;
858}
859
860int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
861{
862 mRenderX = x;
863 mRenderY = y;
864 if (w || h)
865 {
866 mRenderW = w;
867 mRenderH = h;
868 }
869 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
870 mUpdate = 1;
871 return 0;
872}
873
874bool GUIFileSelector::fileSort(FileData d1, FileData d2)
875{
876 if (d1.fileName == ".")
877 return -1;
878 if (d2.fileName == ".")
879 return 0;
880 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
881 return -1;
882 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
883 return 0;
884
885 switch (mSortOrder) {
886 case 3: // by size largest first
887 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
888 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600889 return d1.fileSize < d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400890 case -3: // by size smallest first
891 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
892 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600893 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400894 case 2: // by last modified date newest first
895 if (d1.lastModified == d2.lastModified)
896 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600897 return d1.lastModified < d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400898 case -2: // by date oldest first
899 if (d1.lastModified == d2.lastModified)
900 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600901 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400902 case -1: // by name descending
903 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
904 default: // should be a 1 - sort by name ascending
905 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
906 }
907}
908
909int GUIFileSelector::GetFileList(const std::string folder)
910{
911 DIR* d;
912 struct dirent* de;
913 struct stat st;
914
915 // Clear all data
916 mFolderList.clear();
917 mFileList.clear();
918
919 d = opendir(folder.c_str());
920 if (d == NULL)
921 {
922 LOGI("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000923 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
924 size_t found;
925 found = folder.find_last_of('/');
926 if (found != string::npos) {
927 string new_folder = folder.substr(0, found);
928
929 if (new_folder.length() < 2)
930 new_folder = "/";
931 DataManager::SetValue(mPathVar, new_folder);
932 }
933 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400934 return -1;
935 }
936
937 while ((de = readdir(d)) != NULL)
938 {
939 FileData data;
940
941 data.fileName = de->d_name;
942 if (data.fileName == ".")
943 continue;
944 if (data.fileName == ".." && folder == "/")
945 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000946 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400947 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000948 data.fileType = DT_DIR;
949 } else {
950 data.fileType = de->d_type;
951 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400952
953 std::string path = folder + "/" + data.fileName;
954 stat(path.c_str(), &st);
955 data.protection = st.st_mode;
956 data.userId = st.st_uid;
957 data.groupId = st.st_gid;
958 data.fileSize = st.st_size;
959 data.lastAccess = st.st_atime;
960 data.lastModified = st.st_mtime;
961 data.lastStatChange = st.st_ctime;
962
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000963 if (data.fileType == DT_UNKNOWN) {
964 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
965 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400966 if (data.fileType == DT_DIR)
967 {
968 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
969 mFolderList.push_back(data);
970 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -0400971 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -0400972 {
973 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
974 {
975 mFileList.push_back(data);
976 }
977 }
978 }
979 closedir(d);
980
981 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
982 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -0600983
Dees_Troy51a0e822012-09-05 15:24:24 -0400984 return 0;
985}
986
987void GUIFileSelector::SetPageFocus(int inFocus)
988{
989 if (inFocus)
990 {
Dees_Troyc0583f52013-02-28 11:19:57 -0600991 updateFileList = true;
992 scrollingY = 0;
993 scrollingSpeed = 0;
994 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400995 }
996}