blob: 37eeed2cab25976b0de1971908286d3a1e5d80d8 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001// FileSelector.cpp - GUIFileSelector object
2
3#include <linux/input.h>
4#include <pthread.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <fcntl.h>
10#include <sys/reboot.h>
11#include <sys/stat.h>
12#include <sys/time.h>
13#include <sys/mman.h>
14#include <sys/types.h>
15#include <sys/ioctl.h>
16#include <time.h>
17#include <unistd.h>
18#include <stdlib.h>
19#include <dirent.h>
20#include <ctype.h>
21
22#include <algorithm>
23
24extern "C" {
25#include "../common.h"
26#include "../roots.h"
27#include "../minuitwrp/minui.h"
28#include "../recovery_ui.h"
29}
30
31#include "rapidxml.hpp"
32#include "objects.hpp"
33#include "../data.hpp"
Dees_Troy3ee47bc2013-01-25 21:47:37 +000034#include "../twrp-functions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040035
36#define TW_FILESELECTOR_UP_A_LEVEL "(Up A Level)"
37
38#define SCROLLING_SPEED_DECREMENT 6
39#define SCROLLING_FLOOR 10
40#define SCROLLING_MULTIPLIER 6
41
42int GUIFileSelector::mSortOrder = 0;
43
44GUIFileSelector::GUIFileSelector(xml_node<>* node)
45{
46 xml_attribute<>* attr;
47 xml_node<>* child;
48 int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
49
50 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
51 mIconWidth = mIconHeight = mFolderIconHeight = mFileIconHeight = mFolderIconWidth = mFileIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
52 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
53 mFolderIcon = mFileIcon = mBackground = mFont = mHeaderIcon = NULL;
54 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
55 mShowFolders = mShowFiles = mShowNavFolders = 1;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010056 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
57 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040058 mUpdate = 0;
59 touchDebounce = 6;
60 mPathVar = "cwd";
61 ConvertStrToColor("black", &mBackgroundColor);
62 ConvertStrToColor("black", &mHeaderBackgroundColor);
63 ConvertStrToColor("black", &mSeparatorColor);
64 ConvertStrToColor("black", &mHeaderSeparatorColor);
65 ConvertStrToColor("white", &mFontColor);
66 ConvertStrToColor("white", &mHeaderFontColor);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +010067 ConvertStrToColor("white", &mFastScrollLineColor);
68 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troye7585ca2013-02-15 11:42:29 -060069 hasHighlightColor = false;
70 hasFontHighlightColor = false;
71 isHighlighted = false;
Dees_Troyc0583f52013-02-28 11:19:57 -060072 updateFileList = false;
Dees_Troye7585ca2013-02-15 11:42:29 -060073 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040074
75 // Load header text
76 child = node->first_node("header");
77 if (child)
78 {
79 attr = child->first_attribute("icon");
80 if (attr)
81 mHeaderIcon = PageManager::FindResource(attr->value());
82
83 attr = child->first_attribute("background");
84 if (attr)
85 {
86 std::string color = attr->value();
87 ConvertStrToColor(color, &mHeaderBackgroundColor);
88 header_background_color_specified = -1;
89 }
90 attr = child->first_attribute("textcolor");
91 if (attr)
92 {
93 std::string color = attr->value();
94 ConvertStrToColor(color, &mHeaderFontColor);
95 header_text_color_specified = -1;
96 }
97 attr = child->first_attribute("separatorcolor");
98 if (attr)
99 {
100 std::string color = attr->value();
101 ConvertStrToColor(color, &mHeaderSeparatorColor);
102 header_separator_color_specified = -1;
103 }
104 attr = child->first_attribute("separatorheight");
105 if (attr) {
106 string parsevalue = gui_parse_text(attr->value());
107 mHeaderSeparatorH = atoi(parsevalue.c_str());
108 header_separator_height_specified = -1;
109 }
110 }
111 child = node->first_node("text");
112 if (child) mHeaderText = child->value();
113
Dees_Troye7585ca2013-02-15 11:42:29 -0600114 memset(&mHighlightColor, 0, sizeof(COLOR));
115 child = node->first_node("highlight");
116 if (child) {
117 attr = child->first_attribute("color");
118 if (attr) {
119 hasHighlightColor = true;
120 std::string color = attr->value();
121 ConvertStrToColor(color, &mHighlightColor);
122 }
123 }
124
Dees_Troy51a0e822012-09-05 15:24:24 -0400125 // Simple way to check for static state
126 mLastValue = gui_parse_text(mHeaderText);
127 if (mLastValue != mHeaderText)
128 mHeaderIsStatic = 0;
129 else
130 mHeaderIsStatic = -1;
131
132 child = node->first_node("icon");
133 if (child)
134 {
135 attr = child->first_attribute("folder");
136 if (attr)
137 mFolderIcon = PageManager::FindResource(attr->value());
138 attr = child->first_attribute("file");
139 if (attr)
140 mFileIcon = PageManager::FindResource(attr->value());
141 }
142 child = node->first_node("background");
143 if (child)
144 {
145 attr = child->first_attribute("resource");
146 if (attr)
147 mBackground = PageManager::FindResource(attr->value());
148 attr = child->first_attribute("color");
149 if (attr)
150 {
151 std::string color = attr->value();
152 ConvertStrToColor(color, &mBackgroundColor);
153 if (!header_background_color_specified)
154 ConvertStrToColor(color, &mHeaderBackgroundColor);
155 }
156 }
157
158 // Load the placement
159 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
160 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
161
162 // Load the font, and possibly override the color
163 child = node->first_node("font");
164 if (child)
165 {
166 attr = child->first_attribute("resource");
167 if (attr)
168 mFont = PageManager::FindResource(attr->value());
169
170 attr = child->first_attribute("color");
171 if (attr)
172 {
173 std::string color = attr->value();
174 ConvertStrToColor(color, &mFontColor);
175 if (!header_text_color_specified)
176 ConvertStrToColor(color, &mHeaderFontColor);
177 }
178
179 attr = child->first_attribute("spacing");
180 if (attr) {
181 string parsevalue = gui_parse_text(attr->value());
182 mLineSpacing = atoi(parsevalue.c_str());
183 }
Dees_Troye7585ca2013-02-15 11:42:29 -0600184
185 attr = child->first_attribute("highlightcolor");
186 memset(&mFontHighlightColor, 0, sizeof(COLOR));
187 if (attr)
188 {
189 std::string color = attr->value();
190 ConvertStrToColor(color, &mFontHighlightColor);
191 hasFontHighlightColor = true;
192 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400193 }
194
195 // Load the separator if it exists
196 child = node->first_node("separator");
197 if (child)
198 {
199 attr = child->first_attribute("color");
200 if (attr)
201 {
202 std::string color = attr->value();
203 ConvertStrToColor(color, &mSeparatorColor);
204 if (!header_separator_color_specified)
205 ConvertStrToColor(color, &mHeaderSeparatorColor);
206 }
207
208 attr = child->first_attribute("height");
209 if (attr) {
210 string parsevalue = gui_parse_text(attr->value());
211 mSeparatorH = atoi(parsevalue.c_str());
212 if (!header_separator_height_specified)
213 mHeaderSeparatorH = mSeparatorH;
214 }
215 }
216
217 child = node->first_node("filter");
218 if (child)
219 {
220 attr = child->first_attribute("extn");
221 if (attr)
222 mExtn = attr->value();
223 attr = child->first_attribute("folders");
224 if (attr)
225 mShowFolders = atoi(attr->value());
226 attr = child->first_attribute("files");
227 if (attr)
228 mShowFiles = atoi(attr->value());
229 attr = child->first_attribute("nav");
230 if (attr)
231 mShowNavFolders = atoi(attr->value());
232 }
233
234 // Handle the path variable
235 child = node->first_node("path");
236 if (child)
237 {
238 attr = child->first_attribute("name");
239 if (attr)
240 mPathVar = attr->value();
241 attr = child->first_attribute("default");
242 if (attr)
243 DataManager::SetValue(mPathVar, attr->value());
244 }
245
246 // Handle the result variable
247 child = node->first_node("data");
248 if (child)
249 {
250 attr = child->first_attribute("name");
251 if (attr)
252 mVariable = attr->value();
253 attr = child->first_attribute("default");
254 if (attr)
255 DataManager::SetValue(mVariable, attr->value());
256 }
257
258 // Handle the sort variable
259 child = node->first_node("sort");
260 if (child)
261 {
262 attr = child->first_attribute("name");
263 if (attr)
264 mSortVariable = attr->value();
265 attr = child->first_attribute("default");
266 if (attr)
267 DataManager::SetValue(mSortVariable, attr->value());
268
269 DataManager::GetValue(mSortVariable, mSortOrder);
270 }
271
272 // Handle the selection variable
273 child = node->first_node("selection");
274 if (child)
275 {
276 attr = child->first_attribute("name");
277 if (attr)
278 mSelection = attr->value();
279 else
280 mSelection = "0";
281 } else
282 mSelection = "0";
283
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100284 // Fast scroll colors
285 child = node->first_node("fastscroll");
286 if (child)
287 {
288 attr = child->first_attribute("linecolor");
289 if(attr)
290 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
291
292 attr = child->first_attribute("rectcolor");
293 if(attr)
294 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
295
296 attr = child->first_attribute("w");
297 if (attr) {
298 string parsevalue = gui_parse_text(attr->value());
299 mFastScrollW = atoi(parsevalue.c_str());
300 }
301
302 attr = child->first_attribute("linew");
303 if (attr) {
304 string parsevalue = gui_parse_text(attr->value());
305 mFastScrollLineW = atoi(parsevalue.c_str());
306 }
307
308 attr = child->first_attribute("rectw");
309 if (attr) {
310 string parsevalue = gui_parse_text(attr->value());
311 mFastScrollRectW = atoi(parsevalue.c_str());
312 }
313
314 attr = child->first_attribute("recth");
315 if (attr) {
316 string parsevalue = gui_parse_text(attr->value());
317 mFastScrollRectH = atoi(parsevalue.c_str());
318 }
319 }
320
Dees_Troy51a0e822012-09-05 15:24:24 -0400321 // Retrieve the line height
322 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
323 mLineHeight = mFontHeight;
324 mHeaderH = mFontHeight;
325
326 if (mFolderIcon && mFolderIcon->GetResource())
327 {
328 mFolderIconWidth = gr_get_width(mFolderIcon->GetResource());
329 mFolderIconHeight = gr_get_height(mFolderIcon->GetResource());
330 if (mFolderIconHeight > (int)mLineHeight)
331 mLineHeight = mFolderIconHeight;
332 mIconWidth = mFolderIconWidth;
333 }
334
335 if (mFileIcon && mFileIcon->GetResource())
336 {
337 mFileIconWidth = gr_get_width(mFileIcon->GetResource());
338 mFileIconHeight = gr_get_height(mFileIcon->GetResource());
339 if (mFileIconHeight > (int)mLineHeight)
340 mLineHeight = mFileIconHeight;
341 if (mFileIconWidth > mIconWidth)
342 mIconWidth = mFileIconWidth;
343 }
344
345 if (mHeaderIcon && mHeaderIcon->GetResource())
346 {
347 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
348 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
349 if (mHeaderIconHeight > mHeaderH)
350 mHeaderH = mHeaderIconHeight;
351 if (mHeaderIconWidth > mIconWidth)
352 mIconWidth = mHeaderIconWidth;
353 }
354
355 mHeaderH += mLineSpacing + mHeaderSeparatorH;
356 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
357 if (mHeaderH < actualLineHeight)
358 mHeaderH = actualLineHeight;
359
360 if (actualLineHeight / 3 > 6)
361 touchDebounce = actualLineHeight / 3;
362
363 if (mBackground && mBackground->GetResource())
364 {
365 mBackgroundW = gr_get_width(mBackground->GetResource());
366 mBackgroundH = gr_get_height(mBackground->GetResource());
367 }
368
369 // Fetch the file/folder list
370 std::string value;
371 DataManager::GetValue(mPathVar, value);
Dees_Troy80a11d92013-01-25 16:36:07 +0000372 GetFileList(value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400373}
374
375GUIFileSelector::~GUIFileSelector()
376{
377}
378
379int GUIFileSelector::Render(void)
380{
381 // First step, fill background
382 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
383 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
384
385 // Next, render the background resource (if it exists)
386 if (mBackground && mBackground->GetResource())
387 {
388 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
389 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
390 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
391 }
392
Dees_Troy4622cf92013-03-01 15:29:36 -0600393 // Update the file list if needed
394 pthread_mutex_lock(&updateFileListmutex);
395 if (updateFileList) {
396 pthread_mutex_unlock(&updateFileListmutex);
397 string value;
398 DataManager::GetValue(mPathVar, value);
399 if (GetFileList(value) == 0) {
400 pthread_mutex_lock(&updateFileListmutex);
401 updateFileList = false;
402 pthread_mutex_unlock(&updateFileListmutex);
403 } else {
404 return 0;
405 }
406 } else {
407 pthread_mutex_unlock(&updateFileListmutex);
408 }
409
Dees_Troy51a0e822012-09-05 15:24:24 -0400410 // This tells us how many lines we can actually render
411 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
412 int line;
413
414 int folderSize = mShowFolders ? mFolderList.size() : 0;
415 int fileSize = mShowFiles ? mFileList.size() : 0;
416
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100417 int listW = mRenderW;
418
Dees_Troy51a0e822012-09-05 15:24:24 -0400419 if (folderSize + fileSize < lines) {
420 lines = folderSize + fileSize;
421 scrollingY = 0;
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100422 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400423 } else {
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100424 listW -= mFastScrollW; // space for fast scroll
Dees_Troy51a0e822012-09-05 15:24:24 -0400425 lines++;
426 if (lines < folderSize + fileSize)
427 lines++;
428 }
429
430 void* fontResource = NULL;
431 if (mFont) fontResource = mFont->GetResource();
432
433 int yPos = mRenderY + mHeaderH + scrollingY;
434 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
435 int currentIconHeight = 0, currentIconWidth = 0;
436 int currentIconOffsetY = 0, currentIconOffsetX = 0;
437 int folderIconOffsetY = (int)((actualLineHeight - mFolderIconHeight) / 2), fileIconOffsetY = (int)((actualLineHeight - mFileIconHeight) / 2);
438 int folderIconOffsetX = (mIconWidth - mFolderIconWidth) / 2, fileIconOffsetX = (mIconWidth - mFileIconWidth) / 2;
Dees_Troye7585ca2013-02-15 11:42:29 -0600439 int actualSelection = mStart;
440
441 if (isHighlighted) {
442 int selectY = scrollingY;
443
444 // Locate the correct line for highlighting
445 while (selectY + actualLineHeight < startSelection) {
446 selectY += actualLineHeight;
447 actualSelection++;
448 }
449 if (hasHighlightColor) {
450 // Highlight the area
451 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
452 int HighlightHeight = actualLineHeight;
453 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
454 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
455 }
456 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
457 }
458 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400459
460 for (line = 0; line < lines; line++)
461 {
462 Resource* icon;
463 std::string label;
464
Dees_Troye7585ca2013-02-15 11:42:29 -0600465 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
466 // Use the highlight color for the font
467 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
468 } else {
469 // Set the color for the font
470 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
471 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400472
473 if (line + mStart < folderSize)
474 {
475 icon = mFolderIcon;
476 label = mFolderList.at(line + mStart).fileName;
477 currentIconHeight = mFolderIconHeight;
478 currentIconWidth = mFolderIconWidth;
479 currentIconOffsetY = folderIconOffsetY;
480 currentIconOffsetX = folderIconOffsetX;
481 }
482 else if (line + mStart < folderSize + fileSize)
483 {
484 icon = mFileIcon;
485 label = mFileList.at((line + mStart) - folderSize).fileName;
486 currentIconHeight = mFileIconHeight;
487 currentIconWidth = mFileIconWidth;
488 currentIconOffsetY = fileIconOffsetY;
489 currentIconOffsetX = fileIconOffsetX;
490 } else {
491 continue;
492 }
493
494 if (icon && icon->GetResource())
495 {
496 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
497 if (image_y + currentIconHeight > mRenderY + mRenderH)
498 rect_y = mRenderY + mRenderH - image_y;
499 else
500 rect_y = currentIconHeight;
501 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
502 }
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100503 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400504
505 // Add the separator
506 if (yPos + actualLineHeight < mRenderH + mRenderY) {
507 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100508 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400509 }
510
511 // Move the yPos
512 yPos += actualLineHeight;
513 }
514
515 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
516 // First step, fill background
517 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
518 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
519
520 // Now, we need the header (icon + text)
521 yPos = mRenderY;
522 {
523 Resource* headerIcon;
524 int mIconOffsetX = 0;
525
526 // render the icon if it exists
527 headerIcon = mHeaderIcon;
528 if (headerIcon && headerIcon->GetResource())
529 {
530 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
531 mIconOffsetX = mIconWidth;
532 }
533
534 // render the text
535 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
536 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
537
538 // Add the separator
539 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
540 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
541 }
542
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100543 // render fast scroll
544 lines = (mRenderH - mHeaderH) / (actualLineHeight);
545 if(mFastScrollW > 0 && folderSize + fileSize > lines)
546 {
547 int startX = listW + mRenderX;
548 int fWidth = mRenderW - listW;
549 int fHeight = mRenderH - mHeaderH;
550
551 // line
552 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
553 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
554
555 // rect
556 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((folderSize + fileSize)*actualLineHeight-lines*actualLineHeight);
557 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
558 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
559
560 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
561 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
562 }
563
Dees_Troy4622cf92013-03-01 15:29:36 -0600564 // If a change came in during the render then we need to do another redraw so leave mUpdate alone if updateFileList is true.
565 pthread_mutex_lock(&updateFileListmutex);
566 if (!updateFileList) {
567 mUpdate = 0;
568 }
569 pthread_mutex_unlock(&updateFileListmutex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400570 return 0;
571}
572
573int GUIFileSelector::Update(void)
574{
575 if (!mHeaderIsStatic) {
576 std::string newValue = gui_parse_text(mHeaderText);
577 if (mLastValue != newValue) {
578 mLastValue = newValue;
579 mUpdate = 1;
580 }
581 }
582
583 if (mUpdate)
584 {
585 mUpdate = 0;
586 if (Render() == 0)
587 return 2;
588 }
589
590 // Handle kinetic scrolling
591 if (scrollingSpeed == 0) {
592 // Do nothing
593 } else if (scrollingSpeed > 0) {
594 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
595 scrollingY += scrollingSpeed;
596 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
597 } else {
598 scrollingY += ((int) (actualLineHeight * 2.5));
599 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
600 }
601 while (mStart && scrollingY > 0) {
602 mStart--;
603 scrollingY -= actualLineHeight;
604 }
605 if (mStart == 0 && scrollingY > 0) {
606 scrollingY = 0;
607 scrollingSpeed = 0;
608 } else if (scrollingSpeed < SCROLLING_FLOOR)
609 scrollingSpeed = 0;
610 mUpdate = 1;
611 } else if (scrollingSpeed < 0) {
612 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
613 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
614
615 if (totalSize > lines) {
616 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
617
618 bottom_offset -= actualLineHeight;
619
620 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
621 scrollingY += scrollingSpeed;
622 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
623 } else {
624 scrollingY -= ((int) (actualLineHeight * 2.5));
625 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
626 }
627 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
628 mStart++;
629 scrollingY += actualLineHeight;
630 }
631 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
632 mStart = totalSize - lines - 1;
633 scrollingY = bottom_offset;
634 } else if (mStart + lines >= totalSize && scrollingY < 0) {
635 mStart = totalSize - lines;
636 scrollingY = 0;
637 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
638 scrollingSpeed = 0;
639 mUpdate = 1;
640 }
641 }
642
643 return 0;
644}
645
646int GUIFileSelector::GetSelection(int x, int y)
647{
648 // We only care about y position
649 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
650 return (y - mRenderY - mHeaderH);
651}
652
653int GUIFileSelector::NotifyTouch(TOUCH_STATE state, int x, int y)
654{
Dees_Troy51a0e822012-09-05 15:24:24 -0400655 static int lastY = 0, last2Y = 0;
656 int selection = 0;
657
658 switch (state)
659 {
660 case TOUCH_START:
661 if (scrollingSpeed != 0)
662 startSelection = -1;
663 else
664 startSelection = GetSelection(x,y);
Dees_Troye7585ca2013-02-15 11:42:29 -0600665 isHighlighted = (startSelection > -1);
666 if (isHighlighted)
667 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400668 startY = lastY = last2Y = y;
669 scrollingSpeed = 0;
670 break;
671
672 case TOUCH_DRAG:
673 // Check if we dragged out of the selection window
674 if (GetSelection(x, y) == -1) {
675 last2Y = lastY = 0;
Dees_Troye7585ca2013-02-15 11:42:29 -0600676 if (isHighlighted) {
677 isHighlighted = false;
678 mUpdate = 1;
679 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400680 break;
681 }
682
Vojtech Bocek7cc278b2013-02-24 01:40:19 +0100683 // Fast scroll
684 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
685 {
686 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
687 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
688 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
689
690 float l = float((totalSize-lines)*pct)/100;
691 if(l + lines >= totalSize)
692 {
693 mStart = totalSize - lines;
694 scrollingY = 0;
695 }
696 else
697 {
698 mStart = l;
699 scrollingY = -(l - int(l))*actualLineHeight;
700 }
701
702 startSelection = -1;
703 mUpdate = 1;
704 scrollingSpeed = 0;
705 isHighlighted = false;
706 break;
707 }
708
Dees_Troy51a0e822012-09-05 15:24:24 -0400709 // Provide some debounce on initial touches
710 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
Dees_Troye7585ca2013-02-15 11:42:29 -0600711 isHighlighted = true;
712 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400713 break;
714 }
715
Dees_Troye7585ca2013-02-15 11:42:29 -0600716 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400717 last2Y = lastY;
718 lastY = y;
719 startSelection = -1;
720
721 // Handle scrolling
722 scrollingY += y - startY;
723 startY = y;
724 while(mStart && scrollingY > 0) {
725 mStart--;
726 scrollingY -= actualLineHeight;
727 }
728 if (mStart == 0 && scrollingY > 0)
729 scrollingY = 0;
730 {
731 int totalSize = (mShowFolders ? mFolderList.size() : 0) + (mShowFiles ? mFileList.size() : 0);
732 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
733
734 if (totalSize > lines) {
735 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
736
737 bottom_offset -= actualLineHeight;
738
739 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
740 mStart++;
741 scrollingY += actualLineHeight;
742 }
743 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
744 mStart = totalSize - lines - 1;
745 scrollingY = bottom_offset;
746 } else if (mStart + lines >= totalSize && scrollingY < 0) {
747 mStart = totalSize - lines;
748 scrollingY = 0;
749 }
750 } else
751 scrollingY = 0;
752 }
753 mUpdate = 1;
754 break;
755
756 case TOUCH_RELEASE:
Dees_Troye7585ca2013-02-15 11:42:29 -0600757 isHighlighted = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400758 if (startSelection >= 0)
759 {
760 // We've selected an item!
761 std::string str;
762
763 int folderSize = mShowFolders ? mFolderList.size() : 0;
764 int fileSize = mShowFiles ? mFileList.size() : 0;
765 int selectY = scrollingY, actualSelection = mStart;
766
767 // Move the selection to the proper place in the array
768 while (selectY + actualLineHeight < startSelection) {
769 selectY += actualLineHeight;
770 actualSelection++;
771 }
772 startSelection = actualSelection;
773
774 if (startSelection < folderSize + fileSize)
775 {
776 if (startSelection < folderSize)
777 {
778 std::string oldcwd;
779 std::string cwd;
780
781 str = mFolderList.at(startSelection).fileName;
782 if (mSelection != "0")
783 DataManager::SetValue(mSelection, str);
784 DataManager::GetValue(mPathVar, cwd);
785
786 oldcwd = cwd;
787 // Ignore requests to do nothing
788 if (str == ".") return 0;
789 if (str == TW_FILESELECTOR_UP_A_LEVEL)
790 {
791 if (cwd != "/")
792 {
793 size_t found;
794 found = cwd.find_last_of('/');
795 cwd = cwd.substr(0,found);
796
797 if (cwd.length() < 2) cwd = "/";
798 }
799 }
800 else
801 {
802 // Add a slash if we're not the root folder
803 if (cwd != "/") cwd += "/";
804 cwd += str;
805 }
806
807 if (mShowNavFolders == 0 && mShowFiles == 0)
808 {
809 // This is a "folder" selection
810 DataManager::SetValue(mVariable, cwd);
811 }
812 else
813 {
814 DataManager::SetValue(mPathVar, cwd);
Dees_Troy51a0e822012-09-05 15:24:24 -0400815 mStart = 0;
816 scrollingY = 0;
817 mUpdate = 1;
818 }
819 }
820 else if (!mVariable.empty())
821 {
822 str = mFileList.at(startSelection - folderSize).fileName;
823 if (mSelection != "0")
824 DataManager::SetValue(mSelection, str);
825
826 std::string cwd;
827 DataManager::GetValue(mPathVar, cwd);
828 if (cwd != "/") cwd += "/";
829 DataManager::SetValue(mVariable, cwd + str);
830 }
831 }
832 } else {
833 // This is for kinetic scrolling
834 scrollingSpeed = lastY - last2Y;
835 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
836 scrollingSpeed *= SCROLLING_MULTIPLIER;
837 else
838 scrollingSpeed = 0;
839 }
840 case TOUCH_REPEAT:
841 case TOUCH_HOLD:
842 break;
843 }
844 return 0;
845}
846
847int GUIFileSelector::NotifyVarChange(std::string varName, std::string value)
848{
Dees_Troy51a0e822012-09-05 15:24:24 -0400849 if (!mHeaderIsStatic) {
850 std::string newValue = gui_parse_text(mHeaderText);
851 if (mLastValue != newValue) {
852 mLastValue = newValue;
853 mStart = 0;
854 scrollingY = 0;
855 scrollingSpeed = 0;
856 mUpdate = 1;
857 }
858 }
859 if (varName == mPathVar || varName == mSortVariable)
860 {
Dees_Troy4622cf92013-03-01 15:29:36 -0600861 if (varName == mSortVariable) {
862 DataManager::GetValue(mSortVariable, mSortOrder);
Dees_Troyc0583f52013-02-28 11:19:57 -0600863 }
Dees_Troy4622cf92013-03-01 15:29:36 -0600864 pthread_mutex_lock(&updateFileListmutex);
Dees_Troyc0583f52013-02-28 11:19:57 -0600865 updateFileList = true;
Dees_Troy4622cf92013-03-01 15:29:36 -0600866 pthread_mutex_unlock(&updateFileListmutex);
Dees_Troy51a0e822012-09-05 15:24:24 -0400867 mStart = 0;
868 scrollingY = 0;
869 scrollingSpeed = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400870 mUpdate = 1;
871 return 0;
872 }
873 return 0;
874}
875
876int GUIFileSelector::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
877{
878 mRenderX = x;
879 mRenderY = y;
880 if (w || h)
881 {
882 mRenderW = w;
883 mRenderH = h;
884 }
885 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
886 mUpdate = 1;
887 return 0;
888}
889
890bool GUIFileSelector::fileSort(FileData d1, FileData d2)
891{
892 if (d1.fileName == ".")
893 return -1;
894 if (d2.fileName == ".")
895 return 0;
896 if (d1.fileName == TW_FILESELECTOR_UP_A_LEVEL)
897 return -1;
898 if (d2.fileName == TW_FILESELECTOR_UP_A_LEVEL)
899 return 0;
900
901 switch (mSortOrder) {
902 case 3: // by size largest first
903 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
904 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600905 return d1.fileSize < d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400906 case -3: // by size smallest first
907 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
908 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600909 return d1.fileSize > d2.fileSize;
Dees_Troy51a0e822012-09-05 15:24:24 -0400910 case 2: // by last modified date newest first
911 if (d1.lastModified == d2.lastModified)
912 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600913 return d1.lastModified < d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400914 case -2: // by date oldest first
915 if (d1.lastModified == d2.lastModified)
916 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
Dees_Troy6ef66352013-02-21 08:26:57 -0600917 return d1.lastModified > d2.lastModified;
Dees_Troy51a0e822012-09-05 15:24:24 -0400918 case -1: // by name descending
919 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) > 0);
920 default: // should be a 1 - sort by name ascending
921 return (strcasecmp(d1.fileName.c_str(), d2.fileName.c_str()) < 0);
922 }
923}
924
925int GUIFileSelector::GetFileList(const std::string folder)
926{
927 DIR* d;
928 struct dirent* de;
929 struct stat st;
930
931 // Clear all data
932 mFolderList.clear();
933 mFileList.clear();
934
935 d = opendir(folder.c_str());
936 if (d == NULL)
937 {
938 LOGI("Unable to open '%s'\n", folder.c_str());
Dees_Troy80a11d92013-01-25 16:36:07 +0000939 if (folder != "/" && (mShowNavFolders != 0 || mShowFiles != 0)) {
940 size_t found;
941 found = folder.find_last_of('/');
942 if (found != string::npos) {
943 string new_folder = folder.substr(0, found);
944
945 if (new_folder.length() < 2)
946 new_folder = "/";
947 DataManager::SetValue(mPathVar, new_folder);
948 }
949 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400950 return -1;
951 }
952
953 while ((de = readdir(d)) != NULL)
954 {
955 FileData data;
956
957 data.fileName = de->d_name;
958 if (data.fileName == ".")
959 continue;
960 if (data.fileName == ".." && folder == "/")
961 continue;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000962 if (data.fileName == "..") {
Dees_Troy51a0e822012-09-05 15:24:24 -0400963 data.fileName = TW_FILESELECTOR_UP_A_LEVEL;
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000964 data.fileType = DT_DIR;
965 } else {
966 data.fileType = de->d_type;
967 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400968
969 std::string path = folder + "/" + data.fileName;
970 stat(path.c_str(), &st);
971 data.protection = st.st_mode;
972 data.userId = st.st_uid;
973 data.groupId = st.st_gid;
974 data.fileSize = st.st_size;
975 data.lastAccess = st.st_atime;
976 data.lastModified = st.st_mtime;
977 data.lastStatChange = st.st_ctime;
978
Dees_Troy3ee47bc2013-01-25 21:47:37 +0000979 if (data.fileType == DT_UNKNOWN) {
980 data.fileType = TWFunc::Get_D_Type_From_Stat(path);
981 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400982 if (data.fileType == DT_DIR)
983 {
984 if (mShowNavFolders || (data.fileName != "." && data.fileName != TW_FILESELECTOR_UP_A_LEVEL))
985 mFolderList.push_back(data);
986 }
Dees_Troyaf4d0ce2012-09-26 20:19:06 -0400987 else if (data.fileType == DT_REG || data.fileType == DT_LNK || data.fileType == DT_BLK)
Dees_Troy51a0e822012-09-05 15:24:24 -0400988 {
989 if (mExtn.empty() || (data.fileName.length() > mExtn.length() && data.fileName.substr(data.fileName.length() - mExtn.length()) == mExtn))
990 {
991 mFileList.push_back(data);
992 }
993 }
994 }
995 closedir(d);
996
997 std::sort(mFolderList.begin(), mFolderList.end(), fileSort);
998 std::sort(mFileList.begin(), mFileList.end(), fileSort);
Dees_Troyc0583f52013-02-28 11:19:57 -0600999
Dees_Troy51a0e822012-09-05 15:24:24 -04001000 return 0;
1001}
1002
1003void GUIFileSelector::SetPageFocus(int inFocus)
1004{
1005 if (inFocus)
1006 {
Dees_Troy4622cf92013-03-01 15:29:36 -06001007 pthread_mutex_lock(&updateFileListmutex);
Dees_Troyc0583f52013-02-28 11:19:57 -06001008 updateFileList = true;
Dees_Troy4622cf92013-03-01 15:29:36 -06001009 pthread_mutex_unlock(&updateFileListmutex);
Dees_Troyc0583f52013-02-28 11:19:57 -06001010 scrollingY = 0;
1011 scrollingSpeed = 0;
1012 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001013 }
Dees_Troy4622cf92013-03-01 15:29:36 -06001014}