blob: 263f82f90a783e8d94fd77c10331c81696bb725b [file] [log] [blame]
Dees_Troyeead9852013-02-15 14:31:06 -06001// FileSelector.cpp - GUIFileSelector object
Dees_Troy51a0e822012-09-05 15:24:24 -04002
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_Troyeead9852013-02-15 14:31:06 -060034#include "../twrp-functions.hpp"
35
36#define SCROLLING_SPEED_DECREMENT 6
37#define SCROLLING_FLOOR 10
38#define SCROLLING_MULTIPLIER 6
Dees_Troy51a0e822012-09-05 15:24:24 -040039
40GUIListBox::GUIListBox(xml_node<>* node)
41{
Dees_Troyeead9852013-02-15 14:31:06 -060042 xml_attribute<>* attr;
43 xml_node<>* child;
44 int header_separator_color_specified = 0, header_separator_height_specified = 0, header_text_color_specified = 0, header_background_color_specified = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040045
Dees_Troyeead9852013-02-15 14:31:06 -060046 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
Dees_Troye4284592013-02-19 16:59:35 +000047 mIconWidth = mIconHeight = mSelectedIconHeight = mSelectedIconWidth = mUnselectedIconHeight = mUnselectedIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
Dees_Troyeead9852013-02-15 14:31:06 -060048 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
49 mIconSelected = mIconUnselected = mBackground = mFont = mHeaderIcon = NULL;
50 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
51 mUpdate = 0;
52 touchDebounce = 6;
53 ConvertStrToColor("black", &mBackgroundColor);
54 ConvertStrToColor("black", &mHeaderBackgroundColor);
55 ConvertStrToColor("black", &mSeparatorColor);
56 ConvertStrToColor("black", &mHeaderSeparatorColor);
57 ConvertStrToColor("white", &mFontColor);
58 ConvertStrToColor("white", &mHeaderFontColor);
59 hasHighlightColor = false;
60 hasFontHighlightColor = false;
61 isHighlighted = false;
62 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040063
Dees_Troyeead9852013-02-15 14:31:06 -060064 // Load header text
65 child = node->first_node("header");
66 if (child)
67 {
68 attr = child->first_attribute("icon");
69 if (attr)
70 mHeaderIcon = PageManager::FindResource(attr->value());
Dees_Troy51a0e822012-09-05 15:24:24 -040071
Dees_Troyeead9852013-02-15 14:31:06 -060072 attr = child->first_attribute("background");
73 if (attr)
74 {
75 std::string color = attr->value();
76 ConvertStrToColor(color, &mHeaderBackgroundColor);
77 header_background_color_specified = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040078 }
Dees_Troyeead9852013-02-15 14:31:06 -060079 attr = child->first_attribute("textcolor");
80 if (attr)
81 {
82 std::string color = attr->value();
83 ConvertStrToColor(color, &mHeaderFontColor);
84 header_text_color_specified = -1;
85 }
86 attr = child->first_attribute("separatorcolor");
87 if (attr)
88 {
89 std::string color = attr->value();
90 ConvertStrToColor(color, &mHeaderSeparatorColor);
91 header_separator_color_specified = -1;
92 }
93 attr = child->first_attribute("separatorheight");
94 if (attr) {
95 string parsevalue = gui_parse_text(attr->value());
96 mHeaderSeparatorH = atoi(parsevalue.c_str());
97 header_separator_height_specified = -1;
98 }
99 }
100 child = node->first_node("text");
101 if (child) mHeaderText = child->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400102
Dees_Troyeead9852013-02-15 14:31:06 -0600103 memset(&mHighlightColor, 0, sizeof(COLOR));
104 child = node->first_node("highlight");
105 if (child) {
106 attr = child->first_attribute("color");
107 if (attr) {
108 hasHighlightColor = true;
109 std::string color = attr->value();
110 ConvertStrToColor(color, &mHighlightColor);
111 }
112 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400113
Dees_Troyeead9852013-02-15 14:31:06 -0600114 // Simple way to check for static state
115 mLastValue = gui_parse_text(mHeaderText);
116 if (mLastValue != mHeaderText)
117 mHeaderIsStatic = 0;
118 else
119 mHeaderIsStatic = -1;
120
121 child = node->first_node("icon");
122 if (child)
123 {
124 attr = child->first_attribute("selected");
125 if (attr)
126 mIconSelected = PageManager::FindResource(attr->value());
127 attr = child->first_attribute("unselected");
128 if (attr)
129 mIconUnselected = PageManager::FindResource(attr->value());
130 }
131 child = node->first_node("background");
132 if (child)
133 {
134 attr = child->first_attribute("resource");
135 if (attr)
136 mBackground = PageManager::FindResource(attr->value());
137 attr = child->first_attribute("color");
138 if (attr)
139 {
140 std::string color = attr->value();
141 ConvertStrToColor(color, &mBackgroundColor);
142 if (!header_background_color_specified)
143 ConvertStrToColor(color, &mHeaderBackgroundColor);
144 }
145 }
146
147 // Load the placement
148 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
149 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
150
151 // Load the font, and possibly override the color
152 child = node->first_node("font");
153 if (child)
154 {
155 attr = child->first_attribute("resource");
156 if (attr)
157 mFont = PageManager::FindResource(attr->value());
158
159 attr = child->first_attribute("color");
160 if (attr)
161 {
162 std::string color = attr->value();
163 ConvertStrToColor(color, &mFontColor);
164 if (!header_text_color_specified)
165 ConvertStrToColor(color, &mHeaderFontColor);
166 }
167
168 attr = child->first_attribute("spacing");
169 if (attr) {
170 string parsevalue = gui_parse_text(attr->value());
171 mLineSpacing = atoi(parsevalue.c_str());
172 }
173
174 attr = child->first_attribute("highlightcolor");
175 memset(&mFontHighlightColor, 0, sizeof(COLOR));
176 if (attr)
177 {
178 std::string color = attr->value();
179 ConvertStrToColor(color, &mFontHighlightColor);
180 hasFontHighlightColor = true;
181 }
182 }
183
184 // Load the separator if it exists
185 child = node->first_node("separator");
186 if (child)
187 {
188 attr = child->first_attribute("color");
189 if (attr)
190 {
191 std::string color = attr->value();
192 ConvertStrToColor(color, &mSeparatorColor);
193 if (!header_separator_color_specified)
194 ConvertStrToColor(color, &mHeaderSeparatorColor);
195 }
196
197 attr = child->first_attribute("height");
198 if (attr) {
199 string parsevalue = gui_parse_text(attr->value());
200 mSeparatorH = atoi(parsevalue.c_str());
201 if (!header_separator_height_specified)
202 mHeaderSeparatorH = mSeparatorH;
203 }
204 }
205
206 // Handle the result variable
207 child = node->first_node("data");
208 if (child)
209 {
210 attr = child->first_attribute("name");
211 if (attr)
212 mVariable = attr->value();
213 attr = child->first_attribute("default");
214 if (attr)
215 DataManager::SetValue(mVariable, attr->value());
216 }
217
218 // Retrieve the line height
219 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
220 mLineHeight = mFontHeight;
221 mHeaderH = mFontHeight;
222
223 if (mIconSelected && mIconSelected->GetResource())
224 {
225 mSelectedIconWidth = gr_get_width(mIconSelected->GetResource());
226 mSelectedIconHeight = gr_get_height(mIconSelected->GetResource());
227 if (mSelectedIconHeight > (int)mLineHeight)
228 mLineHeight = mSelectedIconHeight;
229 mIconWidth = mSelectedIconWidth;
230 }
231
232 if (mIconUnselected && mIconUnselected->GetResource())
233 {
234 mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
235 mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
236 if (mUnselectedIconHeight > (int)mLineHeight)
237 mLineHeight = mUnselectedIconHeight;
238 if (mUnselectedIconWidth > mIconWidth)
239 mIconWidth = mUnselectedIconWidth;
240 }
241
242 if (mHeaderIcon && mHeaderIcon->GetResource())
243 {
244 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
245 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
246 if (mHeaderIconHeight > mHeaderH)
247 mHeaderH = mHeaderIconHeight;
248 if (mHeaderIconWidth > mIconWidth)
249 mIconWidth = mHeaderIconWidth;
250 }
251
252 mHeaderH += mLineSpacing + mHeaderSeparatorH;
253 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
254 if (mHeaderH < actualLineHeight)
255 mHeaderH = actualLineHeight;
256
257 if (actualLineHeight / 3 > 6)
258 touchDebounce = actualLineHeight / 3;
259
260 if (mBackground && mBackground->GetResource())
261 {
262 mBackgroundW = gr_get_width(mBackground->GetResource());
263 mBackgroundH = gr_get_height(mBackground->GetResource());
264 }
265
Dees_Troy51a0e822012-09-05 15:24:24 -0400266 // Get the currently selected value for the list
267 DataManager::GetValue(mVariable, currentValue);
268
269 // Get the data for the list
270 child = node->first_node("listitem");
271 if (!child) return;
272
273 while (child)
274 {
275 ListData data;
276
277 attr = child->first_attribute("name");
278 if (!attr) return;
279 data.displayName = attr->value();
280
281 data.variableValue = child->value();
Dees_Troyeead9852013-02-15 14:31:06 -0600282 if (child->value() == currentValue) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400283 data.selected = 1;
Dees_Troyeead9852013-02-15 14:31:06 -0600284 } else {
Dees_Troy51a0e822012-09-05 15:24:24 -0400285 data.selected = 0;
Dees_Troyeead9852013-02-15 14:31:06 -0600286 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400287
288 mList.push_back(data);
289
290 child = child->next_sibling("listitem");
291 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400292}
293
294GUIListBox::~GUIListBox()
295{
296}
297
298int GUIListBox::Render(void)
Dees_Troyeead9852013-02-15 14:31:06 -0600299{
Dees_Troy51a0e822012-09-05 15:24:24 -0400300 // First step, fill background
Dees_Troyeead9852013-02-15 14:31:06 -0600301 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
302 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400303
Dees_Troyeead9852013-02-15 14:31:06 -0600304 // Next, render the background resource (if it exists)
305 if (mBackground && mBackground->GetResource())
306 {
307 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
308 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
309 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
310 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400311
Dees_Troyeead9852013-02-15 14:31:06 -0600312 // This tells us how many lines we can actually render
313 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
314 int line;
Dees_Troy51a0e822012-09-05 15:24:24 -0400315
Dees_Troyeead9852013-02-15 14:31:06 -0600316 int listSize = mList.size();
Dees_Troy51a0e822012-09-05 15:24:24 -0400317
Dees_Troyeead9852013-02-15 14:31:06 -0600318 if (listSize < lines) {
319 lines = listSize;
320 scrollingY = 0;
321 } else {
322 lines++;
323 if (lines < listSize)
324 lines++;
325 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400326
Dees_Troyeead9852013-02-15 14:31:06 -0600327 void* fontResource = NULL;
328 if (mFont) fontResource = mFont->GetResource();
Dees_Troy51a0e822012-09-05 15:24:24 -0400329
Dees_Troyeead9852013-02-15 14:31:06 -0600330 int yPos = mRenderY + mHeaderH + scrollingY;
331 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
332 int currentIconHeight = 0, currentIconWidth = 0;
333 int currentIconOffsetY = 0, currentIconOffsetX = 0;
334 int UnselectedIconOffsetY = (int)((actualLineHeight - mUnselectedIconHeight) / 2), SelectedIconOffsetY = (int)((actualLineHeight - mSelectedIconHeight) / 2);
335 int UnselectedIconOffsetX = (mIconWidth - mUnselectedIconWidth) / 2, SelectedIconOffsetX = (mIconWidth - mSelectedIconWidth) / 2;
336 int actualSelection = mStart;
Dees_Troy51a0e822012-09-05 15:24:24 -0400337
Dees_Troyeead9852013-02-15 14:31:06 -0600338 if (isHighlighted) {
339 int selectY = scrollingY;
Dees_Troy51a0e822012-09-05 15:24:24 -0400340
Dees_Troyeead9852013-02-15 14:31:06 -0600341 // Locate the correct line for highlighting
342 while (selectY + actualLineHeight < startSelection) {
343 selectY += actualLineHeight;
344 actualSelection++;
345 }
346 if (hasHighlightColor) {
347 // Highlight the area
348 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
349 int HighlightHeight = actualLineHeight;
350 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
351 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
352 }
353 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
354 }
355 }
356
357 for (line = 0; line < lines; line++)
358 {
359 Resource* icon;
360 std::string label;
361
362 if (line + mStart >= listSize)
363 continue;
364
365 label = mList.at(line + mStart).displayName;
366 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
367 // Use the highlight color for the font
368 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
369 } else {
370 // Set the color for the font
371 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
372 }
373
Dees_Troy51a0e822012-09-05 15:24:24 -0400374 if (mList.at(line + mStart).selected != 0)
375 {
376 icon = mIconSelected;
Dees_Troyeead9852013-02-15 14:31:06 -0600377 currentIconHeight = mSelectedIconHeight;
378 currentIconWidth = mSelectedIconWidth;
379 currentIconOffsetY = SelectedIconOffsetY;
380 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400381 }
382 else
383 {
384 icon = mIconUnselected;
Dees_Troyeead9852013-02-15 14:31:06 -0600385 currentIconHeight = mSelectedIconHeight;
386 currentIconWidth = mSelectedIconWidth;
387 currentIconOffsetY = SelectedIconOffsetY;
388 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400389 }
390
Dees_Troyeead9852013-02-15 14:31:06 -0600391 if (icon && icon->GetResource())
392 {
393 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
394 if (image_y + currentIconHeight > mRenderY + mRenderH)
395 rect_y = mRenderY + mRenderH - image_y;
396 else
397 rect_y = currentIconHeight;
398 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
399 }
400 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400401
Dees_Troyeead9852013-02-15 14:31:06 -0600402 // Add the separator
403 if (yPos + actualLineHeight < mRenderH + mRenderY) {
404 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
405 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, mRenderW, mSeparatorH);
406 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400407
Dees_Troyeead9852013-02-15 14:31:06 -0600408 // Move the yPos
409 yPos += actualLineHeight;
410 }
411
412 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
413 // First step, fill background
414 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
415 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
416
417 // Now, we need the header (icon + text)
418 yPos = mRenderY;
419 {
420 Resource* headerIcon;
421 int mIconOffsetX = 0;
422
423 // render the icon if it exists
424 headerIcon = mHeaderIcon;
425 if (headerIcon && headerIcon->GetResource())
426 {
427 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
428 mIconOffsetX = mIconWidth;
429 }
430
431 // render the text
432 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
433 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
434
435 // Add the separator
436 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
437 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
438 }
439
440 mUpdate = 0;
441 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400442}
443
444int GUIListBox::Update(void)
445{
Dees_Troyeead9852013-02-15 14:31:06 -0600446 if (!mHeaderIsStatic) {
447 std::string newValue = gui_parse_text(mHeaderText);
448 if (mLastValue != newValue) {
449 mLastValue = newValue;
450 mUpdate = 1;
451 }
452 }
453
454 if (mUpdate)
455 {
456 mUpdate = 0;
457 if (Render() == 0)
Dees_Troy51a0e822012-09-05 15:24:24 -0400458 return 2;
Dees_Troyeead9852013-02-15 14:31:06 -0600459 }
460
461 // Handle kinetic scrolling
462 if (scrollingSpeed == 0) {
463 // Do nothing
464 } else if (scrollingSpeed > 0) {
465 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
466 scrollingY += scrollingSpeed;
467 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
468 } else {
469 scrollingY += ((int) (actualLineHeight * 2.5));
470 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
471 }
472 while (mStart && scrollingY > 0) {
473 mStart--;
474 scrollingY -= actualLineHeight;
475 }
476 if (mStart == 0 && scrollingY > 0) {
477 scrollingY = 0;
478 scrollingSpeed = 0;
479 } else if (scrollingSpeed < SCROLLING_FLOOR)
480 scrollingSpeed = 0;
481 mUpdate = 1;
482 } else if (scrollingSpeed < 0) {
483 int totalSize = mList.size();
484 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
485
486 if (totalSize > lines) {
487 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
488
489 bottom_offset -= actualLineHeight;
490
491 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
492 scrollingY += scrollingSpeed;
493 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
494 } else {
495 scrollingY -= ((int) (actualLineHeight * 2.5));
496 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
497 }
498 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
499 mStart++;
500 scrollingY += actualLineHeight;
501 }
502 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
503 mStart = totalSize - lines - 1;
504 scrollingY = bottom_offset;
505 } else if (mStart + lines >= totalSize && scrollingY < 0) {
506 mStart = totalSize - lines;
507 scrollingY = 0;
508 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
509 scrollingSpeed = 0;
510 mUpdate = 1;
511 }
512 }
513
514 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400515}
516
517int GUIListBox::GetSelection(int x, int y)
518{
Dees_Troyeead9852013-02-15 14:31:06 -0600519 // We only care about y position
520 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
521 return (y - mRenderY - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400522}
523
524int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
525{
Dees_Troyeead9852013-02-15 14:31:06 -0600526 static int lastY = 0, last2Y = 0;
527 int selection = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400528
Dees_Troyeead9852013-02-15 14:31:06 -0600529 switch (state)
530 {
531 case TOUCH_START:
532 if (scrollingSpeed != 0)
533 startSelection = -1;
534 else
535 startSelection = GetSelection(x,y);
536 isHighlighted = (startSelection > -1);
537 if (isHighlighted)
538 mUpdate = 1;
539 startY = lastY = last2Y = y;
540 scrollingSpeed = 0;
541 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400542
Dees_Troyeead9852013-02-15 14:31:06 -0600543 case TOUCH_DRAG:
544 // Check if we dragged out of the selection window
545 if (GetSelection(x, y) == -1) {
546 last2Y = lastY = 0;
547 if (isHighlighted) {
548 isHighlighted = false;
549 mUpdate = 1;
550 }
551 break;
552 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400553
Dees_Troyeead9852013-02-15 14:31:06 -0600554 // Provide some debounce on initial touches
555 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
556 isHighlighted = true;
557 mUpdate = 1;
558 break;
559 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400560
Dees_Troyeead9852013-02-15 14:31:06 -0600561 isHighlighted = false;
562 last2Y = lastY;
563 lastY = y;
564 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400565
Dees_Troyeead9852013-02-15 14:31:06 -0600566 // Handle scrolling
567 scrollingY += y - startY;
568 startY = y;
569 while(mStart && scrollingY > 0) {
570 mStart--;
571 scrollingY -= actualLineHeight;
572 }
573 if (mStart == 0 && scrollingY > 0)
574 scrollingY = 0;
575 {
576 int totalSize = mList.size();
577 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400578
Dees_Troyeead9852013-02-15 14:31:06 -0600579 if (totalSize > lines) {
580 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400581
Dees_Troyeead9852013-02-15 14:31:06 -0600582 bottom_offset -= actualLineHeight;
Dees_Troy51a0e822012-09-05 15:24:24 -0400583
Dees_Troyeead9852013-02-15 14:31:06 -0600584 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
585 mStart++;
586 scrollingY += actualLineHeight;
587 }
588 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
589 mStart = totalSize - lines - 1;
590 scrollingY = bottom_offset;
591 } else if (mStart + lines >= totalSize && scrollingY < 0) {
592 mStart = totalSize - lines;
593 scrollingY = 0;
594 }
595 } else
596 scrollingY = 0;
597 }
598 mUpdate = 1;
599 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400600
Dees_Troyeead9852013-02-15 14:31:06 -0600601 case TOUCH_RELEASE:
602 isHighlighted = false;
603 if (startSelection >= 0)
604 {
605 // We've selected an item!
606 std::string str;
607
608 int listSize = mList.size();
609 int selectY = scrollingY, actualSelection = mStart;
610
611 // Move the selection to the proper place in the array
612 while (selectY + actualLineHeight < startSelection) {
613 selectY += actualLineHeight;
614 actualSelection++;
615 }
616
617 if (actualSelection < listSize && !mVariable.empty())
618 {
619 int i;
620 for (i=0; i<listSize; i++)
621 mList.at(i).selected = 0;
622
623 str = mList.at(actualSelection).variableValue;
624 mList.at(actualSelection).selected = 1;
625 DataManager::SetValue(mVariable, str);
626 mUpdate = 1;
627 }
628 } else {
629 // This is for kinetic scrolling
630 scrollingSpeed = lastY - last2Y;
631 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
632 scrollingSpeed *= SCROLLING_MULTIPLIER;
633 else
634 scrollingSpeed = 0;
635 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400636 case TOUCH_REPEAT:
Dees_Troyeead9852013-02-15 14:31:06 -0600637 case TOUCH_HOLD:
638 break;
639 }
640 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400641}
642
643int GUIListBox::NotifyVarChange(std::string varName, std::string value)
644{
Dees_Troyeead9852013-02-15 14:31:06 -0600645 if (!mHeaderIsStatic) {
646 std::string newValue = gui_parse_text(mHeaderText);
647 if (mLastValue != newValue) {
648 mLastValue = newValue;
649 mStart = 0;
650 scrollingY = 0;
651 scrollingSpeed = 0;
652 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400653 }
Dees_Troyeead9852013-02-15 14:31:06 -0600654 }
655 if (varName == mVariable)
Dees_Troy51a0e822012-09-05 15:24:24 -0400656 {
657 int i, listSize = mList.size(), selected_index = 0;
658
659 currentValue = value;
660
661 for (i=0; i<listSize; i++) {
662 if (mList.at(i).variableValue == currentValue) {
663 mList.at(i).selected = 1;
664 selected_index = i;
665 } else
666 mList.at(i).selected = 0;
667 }
668
669 int lines = mRenderH / (mLineHeight + mLineSpacing);
670 int line;
671
672 if (selected_index > mStart + lines - 1)
673 mStart = selected_index;
674 if (mStart > listSize - lines) {
675 mStart = listSize - lines;
676 } else if (selected_index < mStart) {
677 mStart = selected_index;
678 }
679
680 mUpdate = 1;
681 return 0;
682 }
Dees_Troyeead9852013-02-15 14:31:06 -0600683 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400684}
685
686int GUIListBox::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
687{
Dees_Troyeead9852013-02-15 14:31:06 -0600688 mRenderX = x;
689 mRenderY = y;
690 if (w || h)
691 {
692 mRenderW = w;
693 mRenderH = h;
694 }
695 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
696 mUpdate = 1;
697 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400698}
699
700void GUIListBox::SetPageFocus(int inFocus)
701{
Dees_Troyeead9852013-02-15 14:31:06 -0600702 if (inFocus)
703 {
704 DataManager::GetValue(mVariable, currentValue);
705 NotifyVarChange(mVariable, currentValue);
706 mUpdate = 1;
707 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400708}