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