blob: 539bba096539dbad24113713e0e96475eec0e493 [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));
201 if (attr)
202 {
203 std::string color = attr->value();
204 ConvertStrToColor(color, &mFontHighlightColor);
205 hasFontHighlightColor = true;
206 }
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);
411 if (GetFileList(value) == 0) {
Dees_Troy4622cf92013-03-01 15:29:36 -0600412 updateFileList = false;
Dees_Troy4622cf92013-03-01 15:29:36 -0600413 } else {
414 return 0;
415 }
Dees_Troy4622cf92013-03-01 15:29:36 -0600416 }
417
Dees_Troy51a0e822012-09-05 15:24:24 -0400418 // This tells us how many lines we can actually render
419 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
420 int line;
421
422 int folderSize = mShowFolders ? mFolderList.size() : 0;
423 int fileSize = mShowFiles ? mFileList.size() : 0;
424
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100425 int listW = mRenderW;
426
Dees_Troy51a0e822012-09-05 15:24:24 -0400427 if (folderSize + fileSize < lines) {
428 lines = folderSize + fileSize;
429 scrollingY = 0;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100430 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400431 } else {
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100432 listW -= mFastScrollW; // space for fast scroll
Dees_Troy51a0e822012-09-05 15:24:24 -0400433 lines++;
434 if (lines < folderSize + fileSize)
435 lines++;
436 }
437
438 void* fontResource = NULL;
439 if (mFont) fontResource = mFont->GetResource();
440
441 int yPos = mRenderY + mHeaderH + scrollingY;
442 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
443 int currentIconHeight = 0, currentIconWidth = 0;
444 int currentIconOffsetY = 0, currentIconOffsetX = 0;
445 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
446 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
Dees_Troye7585ca2013-02-15 11:42:29 -0600447 int actualSelection = mStart;
448
449 if (isHighlighted) {
450 int selectY = scrollingY;
451
452 // Locate the correct line for highlighting
453 while (selectY + actualLineHeight < startSelection) {
454 selectY += actualLineHeight;
455 actualSelection++;
456 }
457 if (hasHighlightColor) {
458 // Highlight the area
459 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
460 int HighlightHeight = actualLineHeight;
461 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
462 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
463 }
464 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
465 }
466 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400467
468 for (line = 0; line < lines; line++)
469 {
470 Resource* icon;
471 std::string label;
472
Dees_Troye7585ca2013-02-15 11:42:29 -0600473 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
474 // Use the highlight color for the font
475 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
476 } else {
477 // Set the color for the font
478 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
479 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400480
481 if (line + mStart < folderSize)
482 {
483 icon = mFolderIcon;
484 label = mFolderList.at(line + mStart).fileName;
485 currentIconHeight = mFolderIconHeight;
486 currentIconWidth = mFolderIconWidth;
487 currentIconOffsetY = folderIconOffsetY;
488 currentIconOffsetX = folderIconOffsetX;
489 }
490 else if (line + mStart < folderSize + fileSize)
491 {
492 icon = mFileIcon;
493 label = mFileList.at((line + mStart) - folderSize).fileName;
494 currentIconHeight = mFileIconHeight;
495 currentIconWidth = mFileIconWidth;
496 currentIconOffsetY = fileIconOffsetY;
497 currentIconOffsetX = fileIconOffsetX;
498 } else {
499 continue;
500 }
501
502 if (icon && icon->GetResource())
503 {
504 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
505 if (image_y + currentIconHeight > mRenderY + mRenderH)
506 rect_y = mRenderY + mRenderH - image_y;
507 else
508 rect_y = currentIconHeight;
509 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
510 }
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100511 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400512
513 // Add the separator
514 if (yPos + actualLineHeight < mRenderH + mRenderY) {
515 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100516 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400517 }
518
519 // Move the yPos
520 yPos += actualLineHeight;
521 }
522
523 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
524 // First step, fill background
525 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
526 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
527
528 // Now, we need the header (icon + text)
529 yPos = mRenderY;
530 {
531 Resource* headerIcon;
532 int mIconOffsetX = 0;
533
534 // render the icon if it exists
535 headerIcon = mHeaderIcon;
536 if (headerIcon && headerIcon->GetResource())
537 {
538 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
539 mIconOffsetX = mIconWidth;
540 }
541
542 // render the text
543 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
544 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
545
546 // Add the separator
547 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
548 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
549 }
550
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100551 // render fast scroll
552 lines = (mRenderH - mHeaderH) / (actualLineHeight);
553 if(mFastScrollW > 0 && folderSize + fileSize > lines)
554 {
555 int startX = listW + mRenderX;
556 int fWidth = mRenderW - listW;
557 int fHeight = mRenderH - mHeaderH;
558
559 // line
560 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
561 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
562
563 // rect
564 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((folderSize + fileSize)*actualLineHeight-lines*actualLineHeight);
565 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
566 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
567
568 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
569 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
570 }
571
Dees_Troy4622cf92013-03-01 15:29:36 -0600572 // 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 -0600573 if (!updateFileList) {
574 mUpdate = 0;
575 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400576 return 0;
577}
578
579int GUIFileSelector::Update(void)
580{
581 if (!mHeaderIsStatic) {
582 std::string newValue = gui_parse_text(mHeaderText);
583 if (mLastValue != newValue) {
584 mLastValue = newValue;
585 mUpdate = 1;
586 }
587 }
588
589 if (mUpdate)
590 {
591 mUpdate = 0;
592 if (Render() == 0)
593 return 2;
594 }
595
596 // Handle kinetic scrolling
597 if (scrollingSpeed == 0) {
598 // Do nothing
599 } else if (scrollingSpeed > 0) {
600 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
601 scrollingY += scrollingSpeed;
602 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
603 } else {
604 scrollingY += ((int) (actualLineHeight * 2.5));
605 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
606 }
607 while (mStart && scrollingY > 0) {
608 mStart--;
609 scrollingY -= actualLineHeight;
610 }
611 if (mStart == 0 && scrollingY > 0) {
612 scrollingY = 0;
613 scrollingSpeed = 0;
614 } else if (scrollingSpeed < SCROLLING_FLOOR)
615 scrollingSpeed = 0;
616 mUpdate = 1;
617 } else if (scrollingSpeed < 0) {
618 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
619 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
620
621 if (totalSize > lines) {
622 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
623
624 bottom_offset -= actualLineHeight;
625
626 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
627 scrollingY += scrollingSpeed;
628 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
629 } else {
630 scrollingY -= ((int) (actualLineHeight * 2.5));
631 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
632 }
633 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
634 mStart++;
635 scrollingY += actualLineHeight;
636 }
637 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
638 mStart = totalSize - lines - 1;
639 scrollingY = bottom_offset;
640 } else if (mStart + lines >= totalSize && scrollingY < 0) {
641 mStart = totalSize - lines;
642 scrollingY = 0;
643 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
644 scrollingSpeed = 0;
645 mUpdate = 1;
646 }
647 }
648
649 return 0;
650}
651
652int GUIFileSelector::GetSelection(int x, int y)
653{
654 // We only care about y position
655 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
656 return (y - mRenderY - mHeaderH);
657}
658
659int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
660{
Dees_Troy51a0e822012-09-05 15:24:24 -0400661 static int lastY = 0, last2Y = 0;
662 int selection = 0;
663
664 switch (state)
665 {
666 case TOUCH_START:
667 if (scrollingSpeed != 0)
668 startSelection = -1;
669 else
670 startSelection = GetSelection(x,y);
Dees_Troye7585ca2013-02-15 11:42:29 -0600671 isHighlighted = (startSelection > -1);
672 if (isHighlighted)
673 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400674 startY = lastY = last2Y = y;
675 scrollingSpeed = 0;
676 break;
677
678 case TOUCH_DRAG:
679 // Check if we dragged out of the selection window
680 if (GetSelection(x, y) == -1) {
681 last2Y = lastY = 0;
Dees_Troye7585ca2013-02-15 11:42:29 -0600682 if (isHighlighted) {
683 isHighlighted = false;
684 mUpdate = 1;
685 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400686 break;
687 }
688
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100689 // Fast scroll
690 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
691 {
692 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
693 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
694 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
695
696 float l = float((totalSize-lines)*pct)/100;
697 if(l + lines >= totalSize)
698 {
699 mStart = totalSize - lines;
700 scrollingY = 0;
701 }
702 else
703 {
704 mStart = l;
705 scrollingY = -(l - int(l))*actualLineHeight;
706 }
707
708 startSelection = -1;
709 mUpdate = 1;
710 scrollingSpeed = 0;
711 isHighlighted = false;
712 break;
713 }
714
Dees_Troy51a0e822012-09-05 15:24:24 -0400715 // Provide some debounce on initial touches
716 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
Dees_Troye7585ca2013-02-15 11:42:29 -0600717 isHighlighted = true;
718 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400719 break;
720 }
721
Dees_Troye7585ca2013-02-15 11:42:29 -0600722 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400723 last2Y = lastY;
724 lastY = y;
725 startSelection = -1;
726
727 // Handle scrolling
728 scrollingY += y - startY;
729 startY = y;
730 while(mStart && scrollingY > 0) {
731 mStart--;
732 scrollingY -= actualLineHeight;
733 }
734 if (mStart == 0 && scrollingY > 0)
735 scrollingY = 0;
736 {
737 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
738 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
739
740 if (totalSize > lines) {
741 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
742
743 bottom_offset -= actualLineHeight;
744
745 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
746 mStart++;
747 scrollingY += actualLineHeight;
748 }
749 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
750 mStart = totalSize - lines - 1;
751 scrollingY = bottom_offset;
752 } else if (mStart + lines >= totalSize && scrollingY < 0) {
753 mStart = totalSize - lines;
754 scrollingY = 0;
755 }
756 } else
757 scrollingY = 0;
758 }
759 mUpdate = 1;
760 break;
761
762 case TOUCH_RELEASE:
Dees_Troye7585ca2013-02-15 11:42:29 -0600763 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400764 if (startSelection >= 0)
765 {
766 // We've selected an item!
767 std::string str;
768
769 int folderSize = mShowFolders ? mFolderList.size() : 0;
770 int fileSize = mShowFiles ? mFileList.size() : 0;
771 int selectY = scrollingY, actualSelection = mStart;
772
773 // Move the selection to the proper place in the array
774 while (selectY + actualLineHeight < startSelection) {
775 selectY += actualLineHeight;
776 actualSelection++;
777 }
778 startSelection = actualSelection;
779
780 if (startSelection < folderSize + fileSize)
781 {
782 if (startSelection < folderSize)
783 {
784 std::string oldcwd;
785 std::string cwd;
786
787 str = mFolderList.at(startSelection).fileName;
788 if (mSelection != "0")
789 DataManager::SetValue(mSelection, str);
790 DataManager::GetValue(mPathVar, cwd);
791
792 oldcwd = cwd;
793 // Ignore requests to do nothing
794 if (str == ".") return 0;
795 if (str == TW_FILESELECTOR_UP_A_LEVEL)
796 {
797 if (cwd != "/")
798 {
799 size_t found;
800 found = cwd.find_last_of('/');
801 cwd = cwd.substr(0,found);
802
803 if (cwd.length() < 2) cwd = "/";
804 }
805 }
806 else
807 {
808 // Add a slash if we're not the root folder
809 if (cwd != "/") cwd += "/";
810 cwd += str;
811 }
812
813 if (mShowNavFolders == 0 && mShowFiles == 0)
814 {
815 // This is a "folder" selection
816 DataManager::SetValue(mVariable, cwd);
817 }
818 else
819 {
820 DataManager::SetValue(mPathVar, cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400821 mStart = 0;
822 scrollingY = 0;
823 mUpdate = 1;
824 }
825 }
826 else if (!mVariable.empty())
827 {
828 str = mFileList.at(startSelection - folderSize).fileName;
829 if (mSelection != "0")
830 DataManager::SetValue(mSelection, str);
831
832 std::string cwd;
833 DataManager::GetValue(mPathVar, cwd);
834 if (cwd != "/") cwd += "/";
835 DataManager::SetValue(mVariable, cwd + str);
836 }
837 }
838 } else {
839 // This is for kinetic scrolling
840 scrollingSpeed = lastY - last2Y;
841 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
842 scrollingSpeed *= SCROLLING_MULTIPLIER;
843 else
844 scrollingSpeed = 0;
845 }
846 case TOUCH_REPEAT:
847 case TOUCH_HOLD:
848 break;
849 }
850 return 0;
851}
852
853int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
854{
Dees_Troy146d72a2013-03-11 17:46:19 +0000855 if (varName.empty()) {
856 // Always clear the data variable so we know to use it
857 DataManager::SetValue(mVariable, "");
858 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400859 if (!mHeaderIsStatic) {
860 std::string newValue = gui_parse_text(mHeaderText);
861 if (mLastValue != newValue) {
862 mLastValue = newValue;
863 mStart = 0;
864 scrollingY = 0;
865 scrollingSpeed = 0;
866 mUpdate = 1;
867 }
868 }
869 if (varName == mPathVar || varName == mSortVariable)
870 {
Dees_Troy4622cf92013-03-01 15:29:36 -0600871 if (varName == mSortVariable) {
872 DataManager::GetValue(mSortVariable, mSortOrder);
Dees_Troyc0583f52013-02-28 11:19:57 -0600873 }
874 updateFileList = true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400875 mStart = 0;
876 scrollingY = 0;
877 scrollingSpeed = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400878 mUpdate = 1;
879 return 0;
880 }
881 return 0;
882}
883
884int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
885{
886 mRenderX = x;
887 mRenderY = y;
888 if (w || h)
889 {
890 mRenderW = w;
891 mRenderH = h;
892 }
893 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
894 mUpdate = 1;
895 return 0;
896}
897
898bool GUIFileSelector::fileSort(FileData d1, FileData d2)
899{
900 if (d1.fileName == ".")
901 return -1;
902 if (d2.fileName == ".")
903 return 0;
904 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
905 return -1;
906 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
907 return 0;
908
909 switch (mSortOrder) {
910 case 3: // by size largest first
911 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
912 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600913 return d1.fileSize < d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400914 case -3: // by size smallest first
915 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
916 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600917 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400918 case 2: // by last modified date newest first
919 if (d1.lastModified == d2.lastModified)
920 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600921 return d1.lastModified < d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400922 case -2: // by date oldest first
923 if (d1.lastModified == d2.lastModified)
924 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600925 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400926 case -1: // by name descending
927 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
928 default: // should be a 1 - sort by name ascending
929 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
930 }
931}
932
933int GUIFileSelector::GetFileList(const std::string folder)
934{
935 DIR* d;
936 struct dirent* de;
937 struct stat st;
938
939 // Clear all data
940 mFolderList.clear();
941 mFileList.clear();
942
943 d = opendir(folder.c_str());
944 if (d == NULL)
945 {
Dees_Troy2673cec2013-04-02 20:22:16 +0000946 LOGINFO("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000947 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
948 size_t found;
949 found = folder.find_last_of('/');
950 if (found != string::npos) {
951 string new_folder = folder.substr(0, found);
952
953 if (new_folder.length() < 2)
954 new_folder = "/";
955 DataManager::SetValue(mPathVar, new_folder);
956 }
957 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400958 return -1;
959 }
960
961 while ((de = readdir(d)) != NULL)
962 {
963 FileData data;
964
965 data.fileName = de->d_name;
966 if (data.fileName == ".")
967 continue;
968 if (data.fileName == ".." && folder == "/")
969 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000970 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400971 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000972 data.fileType = DT_DIR;
973 } else {
974 data.fileType = de->d_type;
975 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400976
977 std::string path = folder + "/" + data.fileName;
978 stat(path.c_str(), &st);
979 data.protection = st.st_mode;
980 data.userId = st.st_uid;
981 data.groupId = st.st_gid;
982 data.fileSize = st.st_size;
983 data.lastAccess = st.st_atime;
984 data.lastModified = st.st_mtime;
985 data.lastStatChange = st.st_ctime;
986
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000987 if (data.fileType == DT_UNKNOWN) {
988 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
989 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400990 if (data.fileType == DT_DIR)
991 {
992 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
993 mFolderList.push_back(data);
994 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -0400995 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -0400996 {
997 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
998 {
999 mFileList.push_back(data);
1000 }
1001 }
1002 }
1003 closedir(d);
1004
1005 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
1006 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -06001007
Dees_Troy51a0e822012-09-05 15:24:24 -04001008 return 0;
1009}
1010
1011void GUIFileSelector::SetPageFocus(int inFocus)
1012{
1013 if (inFocus)
1014 {
Dees_Troyc0583f52013-02-28 11:19:57 -06001015 updateFileList = true;
1016 scrollingY = 0;
1017 scrollingSpeed = 0;
1018 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001019 }
Dees_Troya13d74f2013-03-24 08:54:55 -05001020}