blob: 1c2a8ccf0325ea0f7d6d712284b03966cea8c629 [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" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040043}
44
45#include "rapidxml.hpp"
46#include "objects.hpp"
47#include "../data.hpp"
Dees_Troy3ee47bc2013-01-25 21:47:37 +000048#include "../twrp-functions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040049
50#define TW_FILESELECTOR_UP_A_LEVEL "(Up A Level)"
51
52#define SCROLLING_SPEED_DECREMENT 6
53#define SCROLLING_FLOOR 10
54#define SCROLLING_MULTIPLIER 6
55
56int GUIFileSelector::mSortOrder = 0;
57
58GUIFileSelector::GUIFileSelector(xml_node<>* node)
59{
60 xml_attribute<>* attr;
61 xml_node<>* child;
62 int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
63
64 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
65 mIconWidth = mIconHeight = mFolderIconHeight = mFileIconHeight = mFolderIconWidth = mFileIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
66 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
67 mFolderIcon = mFileIcon = mBackground = mFont = mHeaderIcon = NULL;
68 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
69 mShowFolders = mShowFiles = mShowNavFolders = 1;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010070 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
71 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040072 mUpdate = 0;
73 touchDebounce = 6;
74 mPathVar = "cwd";
75 ConvertStrToColor("black", &mBackgroundColor);
76 ConvertStrToColor("black", &mHeaderBackgroundColor);
77 ConvertStrToColor("black", &mSeparatorColor);
78 ConvertStrToColor("black", &mHeaderSeparatorColor);
79 ConvertStrToColor("white", &mFontColor);
80 ConvertStrToColor("white", &mHeaderFontColor);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010081 ConvertStrToColor("white", &mFastScrollLineColor);
82 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troye7585ca2013-02-15 11:42:29 -060083 hasHighlightColor = false;
84 hasFontHighlightColor = false;
85 isHighlighted = false;
Dees_Troyc0583f52013-02-28 11:19:57 -060086 updateFileList = false;
Dees_Troye7585ca2013-02-15 11:42:29 -060087 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040088
89 // Load header text
90 child = node->first_node("header");
91 if (child)
92 {
93 attr = child->first_attribute("icon");
94 if (attr)
95 mHeaderIcon = PageManager::FindResource(attr->value());
96
97 attr = child->first_attribute("background");
98 if (attr)
99 {
100 std::string color = attr->value();
101 ConvertStrToColor(color, &mHeaderBackgroundColor);
102 header_background_color_specified = -1;
103 }
104 attr = child->first_attribute("textcolor");
105 if (attr)
106 {
107 std::string color = attr->value();
108 ConvertStrToColor(color, &mHeaderFontColor);
109 header_text_color_specified = -1;
110 }
111 attr = child->first_attribute("separatorcolor");
112 if (attr)
113 {
114 std::string color = attr->value();
115 ConvertStrToColor(color, &mHeaderSeparatorColor);
116 header_separator_color_specified = -1;
117 }
118 attr = child->first_attribute("separatorheight");
119 if (attr) {
120 string parsevalue = gui_parse_text(attr->value());
121 mHeaderSeparatorH = atoi(parsevalue.c_str());
122 header_separator_height_specified = -1;
123 }
124 }
125 child = node->first_node("text");
126 if (child) mHeaderText = child->value();
127
Dees_Troye7585ca2013-02-15 11:42:29 -0600128 memset(&mHighlightColor, 0, sizeof(COLOR));
129 child = node->first_node("highlight");
130 if (child) {
131 attr = child->first_attribute("color");
132 if (attr) {
133 hasHighlightColor = true;
134 std::string color = attr->value();
135 ConvertStrToColor(color, &mHighlightColor);
136 }
137 }
138
Dees_Troy51a0e822012-09-05 15:24:24 -0400139 // Simple way to check for static state
140 mLastValue = gui_parse_text(mHeaderText);
141 if (mLastValue != mHeaderText)
142 mHeaderIsStatic = 0;
143 else
144 mHeaderIsStatic = -1;
145
146 child = node->first_node("icon");
147 if (child)
148 {
149 attr = child->first_attribute("folder");
150 if (attr)
151 mFolderIcon = PageManager::FindResource(attr->value());
152 attr = child->first_attribute("file");
153 if (attr)
154 mFileIcon = PageManager::FindResource(attr->value());
155 }
156 child = node->first_node("background");
157 if (child)
158 {
159 attr = child->first_attribute("resource");
160 if (attr)
161 mBackground = PageManager::FindResource(attr->value());
162 attr = child->first_attribute("color");
163 if (attr)
164 {
165 std::string color = attr->value();
166 ConvertStrToColor(color, &mBackgroundColor);
167 if (!header_background_color_specified)
168 ConvertStrToColor(color, &mHeaderBackgroundColor);
169 }
170 }
171
172 // Load the placement
173 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
174 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
175
176 // Load the font, and possibly override the color
177 child = node->first_node("font");
178 if (child)
179 {
180 attr = child->first_attribute("resource");
181 if (attr)
182 mFont = PageManager::FindResource(attr->value());
183
184 attr = child->first_attribute("color");
185 if (attr)
186 {
187 std::string color = attr->value();
188 ConvertStrToColor(color, &mFontColor);
189 if (!header_text_color_specified)
190 ConvertStrToColor(color, &mHeaderFontColor);
191 }
192
193 attr = child->first_attribute("spacing");
194 if (attr) {
195 string parsevalue = gui_parse_text(attr->value());
196 mLineSpacing = atoi(parsevalue.c_str());
197 }
Dees_Troye7585ca2013-02-15 11:42:29 -0600198
199 attr = child->first_attribute("highlightcolor");
200 memset(&mFontHighlightColor, 0, sizeof(COLOR));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200201 if (attr)
202 {
203 std::string color = attr->value();
Dees_Troye7585ca2013-02-15 11:42:29 -0600204 ConvertStrToColor(color, &mFontHighlightColor);
205 hasFontHighlightColor = true;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200206 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400207 }
208
209 // Load the separator if it exists
210 child = node->first_node("separator");
211 if (child)
212 {
213 attr = child->first_attribute("color");
214 if (attr)
215 {
216 std::string color = attr->value();
217 ConvertStrToColor(color, &mSeparatorColor);
218 if (!header_separator_color_specified)
219 ConvertStrToColor(color, &mHeaderSeparatorColor);
220 }
221
222 attr = child->first_attribute("height");
223 if (attr) {
224 string parsevalue = gui_parse_text(attr->value());
225 mSeparatorH = atoi(parsevalue.c_str());
226 if (!header_separator_height_specified)
227 mHeaderSeparatorH = mSeparatorH;
228 }
229 }
230
231 child = node->first_node("filter");
232 if (child)
233 {
234 attr = child->first_attribute("extn");
235 if (attr)
236 mExtn = attr->value();
237 attr = child->first_attribute("folders");
238 if (attr)
239 mShowFolders = atoi(attr->value());
240 attr = child->first_attribute("files");
241 if (attr)
242 mShowFiles = atoi(attr->value());
243 attr = child->first_attribute("nav");
244 if (attr)
245 mShowNavFolders = atoi(attr->value());
246 }
247
248 // Handle the path variable
249 child = node->first_node("path");
250 if (child)
251 {
252 attr = child->first_attribute("name");
253 if (attr)
254 mPathVar = attr->value();
255 attr = child->first_attribute("default");
256 if (attr)
257 DataManager::SetValue(mPathVar, attr->value());
258 }
259
260 // Handle the result variable
261 child = node->first_node("data");
262 if (child)
263 {
264 attr = child->first_attribute("name");
265 if (attr)
266 mVariable = attr->value();
267 attr = child->first_attribute("default");
268 if (attr)
269 DataManager::SetValue(mVariable, attr->value());
270 }
271
272 // Handle the sort variable
273 child = node->first_node("sort");
274 if (child)
275 {
276 attr = child->first_attribute("name");
277 if (attr)
278 mSortVariable = attr->value();
279 attr = child->first_attribute("default");
280 if (attr)
281 DataManager::SetValue(mSortVariable, attr->value());
282
283 DataManager::GetValue(mSortVariable, mSortOrder);
284 }
285
286 // Handle the selection variable
287 child = node->first_node("selection");
288 if (child)
289 {
290 attr = child->first_attribute("name");
291 if (attr)
292 mSelection = attr->value();
293 else
294 mSelection = "0";
295 } else
296 mSelection = "0";
297
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100298 // Fast scroll colors
299 child = node->first_node("fastscroll");
300 if (child)
301 {
302 attr = child->first_attribute("linecolor");
303 if(attr)
304 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
305
306 attr = child->first_attribute("rectcolor");
307 if(attr)
308 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
309
310 attr = child->first_attribute("w");
311 if (attr) {
312 string parsevalue = gui_parse_text(attr->value());
313 mFastScrollW = atoi(parsevalue.c_str());
314 }
315
316 attr = child->first_attribute("linew");
317 if (attr) {
318 string parsevalue = gui_parse_text(attr->value());
319 mFastScrollLineW = atoi(parsevalue.c_str());
320 }
321
322 attr = child->first_attribute("rectw");
323 if (attr) {
324 string parsevalue = gui_parse_text(attr->value());
325 mFastScrollRectW = atoi(parsevalue.c_str());
326 }
327
328 attr = child->first_attribute("recth");
329 if (attr) {
330 string parsevalue = gui_parse_text(attr->value());
331 mFastScrollRectH = atoi(parsevalue.c_str());
332 }
333 }
334
Dees_Troy51a0e822012-09-05 15:24:24 -0400335 // Retrieve the line height
336 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
337 mLineHeight = mFontHeight;
338 mHeaderH = mFontHeight;
339
340 if (mFolderIcon && mFolderIcon->GetResource())
341 {
342 mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
343 mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
344 if (mFolderIconHeight > (int)mLineHeight)
345 mLineHeight = mFolderIconHeight;
346 mIconWidth = mFolderIconWidth;
347 }
348
349 if (mFileIcon && mFileIcon->GetResource())
350 {
351 mFileIconWidth = gr_get_width(mFileIcon->GetResource());
352 mFileIconHeight = gr_get_height(mFileIcon->GetResource());
353 if (mFileIconHeight > (int)mLineHeight)
354 mLineHeight = mFileIconHeight;
355 if (mFileIconWidth > mIconWidth)
356 mIconWidth = mFileIconWidth;
357 }
358
359 if (mHeaderIcon && mHeaderIcon->GetResource())
360 {
361 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
362 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
363 if (mHeaderIconHeight > mHeaderH)
364 mHeaderH = mHeaderIconHeight;
365 if (mHeaderIconWidth > mIconWidth)
366 mIconWidth = mHeaderIconWidth;
367 }
368
369 mHeaderH += mLineSpacing + mHeaderSeparatorH;
370 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
371 if (mHeaderH < actualLineHeight)
372 mHeaderH = actualLineHeight;
373
374 if (actualLineHeight / 3 > 6)
375 touchDebounce = actualLineHeight / 3;
376
377 if (mBackground && mBackground->GetResource())
378 {
379 mBackgroundW = gr_get_width(mBackground->GetResource());
380 mBackgroundH = gr_get_height(mBackground->GetResource());
381 }
382
383 // Fetch the file/folder list
384 std::string value;
385 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000386 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400387}
388
389GUIFileSelector::~GUIFileSelector()
390{
391}
392
393int GUIFileSelector::Render(void)
394{
395 // First step, fill background
396 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
397 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
398
399 // Next, render the background resource (if it exists)
400 if (mBackground && mBackground->GetResource())
401 {
402 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
403 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
404 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
405 }
406
Dees_Troy4622cf92013-03-01 15:29:36 -0600407 // Update the file list if needed
Dees_Troy4622cf92013-03-01 15:29:36 -0600408 if (updateFileList) {
Dees_Troy4622cf92013-03-01 15:29:36 -0600409 string value;
410 DataManager::GetValue(mPathVar, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200411 if (GetFileList(value) == 0)
Dees_Troy4622cf92013-03-01 15:29:36 -0600412 updateFileList = false;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 else
Dees_Troy4622cf92013-03-01 15:29:36 -0600414 return 0;
Dees_Troy4622cf92013-03-01 15:29:36 -0600415 }
416
Dees_Troy51a0e822012-09-05 15:24:24 -0400417 // This tells us how many lines we can actually render
418 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
419 int line;
420
421 int folderSize = mShowFolders ? mFolderList.size() : 0;
422 int fileSize = mShowFiles ? mFileList.size() : 0;
423
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100424 int listW = mRenderW;
425
Dees_Troy51a0e822012-09-05 15:24:24 -0400426 if (folderSize + fileSize < lines) {
427 lines = folderSize + fileSize;
428 scrollingY = 0;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100429 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400430 } else {
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100431 listW -= mFastScrollW; // space for fast scroll
Dees_Troy51a0e822012-09-05 15:24:24 -0400432 lines++;
433 if (lines < folderSize + fileSize)
434 lines++;
435 }
436
437 void* fontResource = NULL;
438 if (mFont) fontResource = mFont->GetResource();
439
440 int yPos = mRenderY + mHeaderH + scrollingY;
441 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
442 int currentIconHeight = 0, currentIconWidth = 0;
443 int currentIconOffsetY = 0, currentIconOffsetX = 0;
444 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
445 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
Dees_Troye7585ca2013-02-15 11:42:29 -0600446 int actualSelection = mStart;
447
448 if (isHighlighted) {
449 int selectY = scrollingY;
450
451 // Locate the correct line for highlighting
452 while (selectY + actualLineHeight < startSelection) {
453 selectY += actualLineHeight;
454 actualSelection++;
455 }
456 if (hasHighlightColor) {
457 // Highlight the area
458 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
459 int HighlightHeight = actualLineHeight;
460 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
461 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
462 }
463 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
464 }
465 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400466
467 for (line = 0; line < lines; line++)
468 {
469 Resource* icon;
470 std::string label;
471
Dees_Troye7585ca2013-02-15 11:42:29 -0600472 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
473 // Use the highlight color for the font
474 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
475 } else {
476 // Set the color for the font
477 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
478 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400479
480 if (line + mStart < folderSize)
481 {
482 icon = mFolderIcon;
483 label = mFolderList.at(line + mStart).fileName;
484 currentIconHeight = mFolderIconHeight;
485 currentIconWidth = mFolderIconWidth;
486 currentIconOffsetY = folderIconOffsetY;
487 currentIconOffsetX = folderIconOffsetX;
488 }
489 else if (line + mStart < folderSize + fileSize)
490 {
491 icon = mFileIcon;
492 label = mFileList.at((line + mStart) - folderSize).fileName;
493 currentIconHeight = mFileIconHeight;
494 currentIconWidth = mFileIconWidth;
495 currentIconOffsetY = fileIconOffsetY;
496 currentIconOffsetX = fileIconOffsetX;
497 } else {
498 continue;
499 }
500
501 if (icon && icon->GetResource())
502 {
503 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
504 if (image_y + currentIconHeight > mRenderY + mRenderH)
505 rect_y = mRenderY + mRenderH - image_y;
506 else
507 rect_y = currentIconHeight;
508 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
509 }
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100510 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400511
512 // Add the separator
513 if (yPos + actualLineHeight < mRenderH + mRenderY) {
514 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100515 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400516 }
517
518 // Move the yPos
519 yPos += actualLineHeight;
520 }
521
522 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
523 // First step, fill background
524 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
525 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
526
527 // Now, we need the header (icon + text)
528 yPos = mRenderY;
529 {
530 Resource* headerIcon;
531 int mIconOffsetX = 0;
532
533 // render the icon if it exists
534 headerIcon = mHeaderIcon;
535 if (headerIcon && headerIcon->GetResource())
536 {
537 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
538 mIconOffsetX = mIconWidth;
539 }
540
541 // render the text
542 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
543 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
544
545 // Add the separator
546 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
547 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
548 }
549
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100550 // render fast scroll
551 lines = (mRenderH - mHeaderH) / (actualLineHeight);
552 if(mFastScrollW > 0 && folderSize + fileSize > lines)
553 {
554 int startX = listW + mRenderX;
555 int fWidth = mRenderW - listW;
556 int fHeight = mRenderH - mHeaderH;
557
558 // line
559 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
560 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
561
562 // rect
563 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((folderSize + fileSize)*actualLineHeight-lines*actualLineHeight);
564 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
565 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
566
567 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
568 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
569 }
570
Dees_Troy4622cf92013-03-01 15:29:36 -0600571 // 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 -0600572 if (!updateFileList) {
573 mUpdate = 0;
574 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400575 return 0;
576}
577
578int GUIFileSelector::Update(void)
579{
580 if (!mHeaderIsStatic) {
581 std::string newValue = gui_parse_text(mHeaderText);
582 if (mLastValue != newValue) {
583 mLastValue = newValue;
584 mUpdate = 1;
585 }
586 }
587
588 if (mUpdate)
589 {
590 mUpdate = 0;
591 if (Render() == 0)
592 return 2;
593 }
594
595 // Handle kinetic scrolling
596 if (scrollingSpeed == 0) {
597 // Do nothing
598 } else if (scrollingSpeed > 0) {
599 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
600 scrollingY += scrollingSpeed;
601 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
602 } else {
603 scrollingY += ((int) (actualLineHeight * 2.5));
604 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
605 }
606 while (mStart && scrollingY > 0) {
607 mStart--;
608 scrollingY -= actualLineHeight;
609 }
610 if (mStart == 0 && scrollingY > 0) {
611 scrollingY = 0;
612 scrollingSpeed = 0;
613 } else if (scrollingSpeed < SCROLLING_FLOOR)
614 scrollingSpeed = 0;
615 mUpdate = 1;
616 } else if (scrollingSpeed < 0) {
617 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
618 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
619
620 if (totalSize > lines) {
621 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
622
623 bottom_offset -= actualLineHeight;
624
625 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
626 scrollingY += scrollingSpeed;
627 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
628 } else {
629 scrollingY -= ((int) (actualLineHeight * 2.5));
630 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
631 }
632 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
633 mStart++;
634 scrollingY += actualLineHeight;
635 }
636 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
637 mStart = totalSize - lines - 1;
638 scrollingY = bottom_offset;
639 } else if (mStart + lines >= totalSize && scrollingY < 0) {
640 mStart = totalSize - lines;
641 scrollingY = 0;
642 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
643 scrollingSpeed = 0;
644 mUpdate = 1;
645 }
646 }
647
648 return 0;
649}
650
651int GUIFileSelector::GetSelection(int x, int y)
652{
653 // We only care about y position
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200654 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH)
655 return -1;
656
Dees_Troy51a0e822012-09-05 15:24:24 -0400657 return (y - mRenderY - mHeaderH);
658}
659
660int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
661{
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100662 static int lastY = 0, last2Y = 0, fastScroll = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400663 int selection = 0;
664
665 switch (state)
666 {
667 case TOUCH_START:
668 if (scrollingSpeed != 0)
669 startSelection = -1;
670 else
671 startSelection = GetSelection(x,y);
Dees_Troye7585ca2013-02-15 11:42:29 -0600672 isHighlighted = (startSelection > -1);
673 if (isHighlighted)
674 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400675 startY = lastY = last2Y = y;
676 scrollingSpeed = 0;
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100677
678 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
679 fastScroll = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400680 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400681 case TOUCH_DRAG:
682 // Check if we dragged out of the selection window
683 if (GetSelection(x, y) == -1) {
684 last2Y = lastY = 0;
Dees_Troye7585ca2013-02-15 11:42:29 -0600685 if (isHighlighted) {
686 isHighlighted = false;
687 mUpdate = 1;
688 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400689 break;
690 }
691
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100692 // Fast scroll
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100693 if(fastScroll)
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100694 {
695 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
696 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
697 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
698
699 float l = float((totalSize-lines)*pct)/100;
700 if(l + lines >= totalSize)
701 {
702 mStart = totalSize - lines;
703 scrollingY = 0;
704 }
705 else
706 {
707 mStart = l;
708 scrollingY = -(l - int(l))*actualLineHeight;
709 }
710
711 startSelection = -1;
712 mUpdate = 1;
713 scrollingSpeed = 0;
714 isHighlighted = false;
715 break;
716 }
717
Dees_Troy51a0e822012-09-05 15:24:24 -0400718 // Provide some debounce on initial touches
719 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
Dees_Troye7585ca2013-02-15 11:42:29 -0600720 isHighlighted = true;
721 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400722 break;
723 }
724
Dees_Troye7585ca2013-02-15 11:42:29 -0600725 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400726 last2Y = lastY;
727 lastY = y;
728 startSelection = -1;
729
730 // Handle scrolling
731 scrollingY += y - startY;
732 startY = y;
733 while(mStart && scrollingY > 0) {
734 mStart--;
735 scrollingY -= actualLineHeight;
736 }
737 if (mStart == 0 && scrollingY > 0)
738 scrollingY = 0;
739 {
740 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
741 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
742
743 if (totalSize > lines) {
744 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
745
746 bottom_offset -= actualLineHeight;
747
748 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
749 mStart++;
750 scrollingY += actualLineHeight;
751 }
752 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
753 mStart = totalSize - lines - 1;
754 scrollingY = bottom_offset;
755 } else if (mStart + lines >= totalSize && scrollingY < 0) {
756 mStart = totalSize - lines;
757 scrollingY = 0;
758 }
759 } else
760 scrollingY = 0;
761 }
762 mUpdate = 1;
763 break;
764
765 case TOUCH_RELEASE:
Dees_Troye7585ca2013-02-15 11:42:29 -0600766 isHighlighted = false;
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100767 fastScroll = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400768 if (startSelection >= 0)
769 {
770 // We've selected an item!
771 std::string str;
772
773 int folderSize = mShowFolders ? mFolderList.size() : 0;
774 int fileSize = mShowFiles ? mFileList.size() : 0;
775 int selectY = scrollingY, actualSelection = mStart;
776
777 // Move the selection to the proper place in the array
778 while (selectY + actualLineHeight < startSelection) {
779 selectY += actualLineHeight;
780 actualSelection++;
781 }
782 startSelection = actualSelection;
783
784 if (startSelection < folderSize + fileSize)
785 {
Vojtech Bocek5af8f3f2014-02-08 02:21:23 +0100786 DataManager::Vibrate("tw_button_vibrate");
787
Dees_Troy51a0e822012-09-05 15:24:24 -0400788 if (startSelection < folderSize)
789 {
790 std::string oldcwd;
791 std::string cwd;
792
793 str = mFolderList.at(startSelection).fileName;
794 if (mSelection != "0")
795 DataManager::SetValue(mSelection, str);
796 DataManager::GetValue(mPathVar, cwd);
797
798 oldcwd = cwd;
799 // Ignore requests to do nothing
800 if (str == ".") return 0;
801 if (str == TW_FILESELECTOR_UP_A_LEVEL)
802 {
803 if (cwd != "/")
804 {
805 size_t found;
806 found = cwd.find_last_of('/');
807 cwd = cwd.substr(0,found);
808
809 if (cwd.length() < 2) cwd = "/";
810 }
811 }
812 else
813 {
814 // Add a slash if we're not the root folder
815 if (cwd != "/") cwd += "/";
816 cwd += str;
817 }
818
819 if (mShowNavFolders == 0 && mShowFiles == 0)
820 {
821 // This is a "folder" selection
822 DataManager::SetValue(mVariable, cwd);
823 }
824 else
825 {
826 DataManager::SetValue(mPathVar, cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400827 mStart = 0;
828 scrollingY = 0;
829 mUpdate = 1;
830 }
831 }
832 else if (!mVariable.empty())
833 {
834 str = mFileList.at(startSelection - folderSize).fileName;
835 if (mSelection != "0")
836 DataManager::SetValue(mSelection, str);
837
838 std::string cwd;
839 DataManager::GetValue(mPathVar, cwd);
840 if (cwd != "/") cwd += "/";
841 DataManager::SetValue(mVariable, cwd + str);
842 }
843 }
844 } else {
845 // This is for kinetic scrolling
846 scrollingSpeed = lastY - last2Y;
847 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
848 scrollingSpeed *= SCROLLING_MULTIPLIER;
849 else
850 scrollingSpeed = 0;
851 }
852 case TOUCH_REPEAT:
853 case TOUCH_HOLD:
854 break;
855 }
856 return 0;
857}
858
859int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
860{
Dees_Troy146d72a2013-03-11 17:46:19 +0000861 if (varName.empty()) {
862 // Always clear the data variable so we know to use it
863 DataManager::SetValue(mVariable, "");
864 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400865 if (!mHeaderIsStatic) {
866 std::string newValue = gui_parse_text(mHeaderText);
867 if (mLastValue != newValue) {
868 mLastValue = newValue;
869 mStart = 0;
870 scrollingY = 0;
871 scrollingSpeed = 0;
872 mUpdate = 1;
873 }
874 }
875 if (varName == mPathVar || varName == mSortVariable)
876 {
Dees_Troy4622cf92013-03-01 15:29:36 -0600877 if (varName == mSortVariable) {
878 DataManager::GetValue(mSortVariable, mSortOrder);
Dees_Troyc0583f52013-02-28 11:19:57 -0600879 }
880 updateFileList = true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400881 mStart = 0;
882 scrollingY = 0;
883 scrollingSpeed = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400884 mUpdate = 1;
885 return 0;
886 }
887 return 0;
888}
889
890int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
891{
892 mRenderX = x;
893 mRenderY = y;
894 if (w || h)
895 {
896 mRenderW = w;
897 mRenderH = h;
898 }
899 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
900 mUpdate = 1;
901 return 0;
902}
903
904bool GUIFileSelector::fileSort(FileData d1, FileData d2)
905{
906 if (d1.fileName == ".")
907 return -1;
908 if (d2.fileName == ".")
909 return 0;
910 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
911 return -1;
912 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
913 return 0;
914
915 switch (mSortOrder) {
916 case 3: // by size largest 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 -3: // by size smallest first
921 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
922 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600923 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400924 case 2: // by last modified date newest 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 -2: // by date oldest first
929 if (d1.lastModified == d2.lastModified)
930 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600931 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400932 case -1: // by name descending
933 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
934 default: // should be a 1 - sort by name ascending
935 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
936 }
937}
938
939int GUIFileSelector::GetFileList(const std::string folder)
940{
941 DIR* d;
942 struct dirent* de;
943 struct stat st;
944
945 // Clear all data
946 mFolderList.clear();
947 mFileList.clear();
948
949 d = opendir(folder.c_str());
950 if (d == NULL)
951 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000952 LOGINFO("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000953 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
954 size_t found;
955 found = folder.find_last_of('/');
956 if (found != string::npos) {
957 string new_folder = folder.substr(0, found);
958
959 if (new_folder.length() < 2)
960 new_folder = "/";
961 DataManager::SetValue(mPathVar, new_folder);
962 }
963 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400964 return -1;
965 }
966
967 while ((de = readdir(d)) != NULL)
968 {
969 FileData data;
970
971 data.fileName = de->d_name;
972 if (data.fileName == ".")
973 continue;
974 if (data.fileName == ".." && folder == "/")
975 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000976 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400977 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000978 data.fileType = DT_DIR;
979 } else {
980 data.fileType = de->d_type;
981 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400982
983 std::string path = folder + "/" + data.fileName;
984 stat(path.c_str(), &st);
985 data.protection = st.st_mode;
986 data.userId = st.st_uid;
987 data.groupId = st.st_gid;
988 data.fileSize = st.st_size;
989 data.lastAccess = st.st_atime;
990 data.lastModified = st.st_mtime;
991 data.lastStatChange = st.st_ctime;
992
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000993 if (data.fileType == DT_UNKNOWN) {
994 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
995 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400996 if (data.fileType == DT_DIR)
997 {
998 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
999 mFolderList.push_back(data);
1000 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -04001001 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -04001002 {
1003 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
1004 {
1005 mFileList.push_back(data);
1006 }
1007 }
1008 }
1009 closedir(d);
1010
1011 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
1012 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -06001013
Dees_Troy51a0e822012-09-05 15:24:24 -04001014 return 0;
1015}
1016
1017void GUIFileSelector::SetPageFocus(int inFocus)
1018{
1019 if (inFocus)
1020 {
Dees_Troyc0583f52013-02-28 11:19:57 -06001021 updateFileList = true;
1022 scrollingY = 0;
1023 scrollingSpeed = 0;
1024 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001025 }
Dees_Troya13d74f2013-03-24 08:54:55 -05001026}