blob: 910a6a3995f68622037d9429bc9eed5a1e5816cb [file] [log] [blame]
Dees_Troya13d74f2013-03-24 08:54:55 -05001/*
2 Copyright 2013 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees_Troy51a0e822012-09-05 15:24:24 -040018
19#include <linux/input.h>
20#include <pthread.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <fcntl.h>
26#include <sys/reboot.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <sys/mman.h>
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdlib.h>
35#include <dirent.h>
36#include <ctype.h>
37
38#include <algorithm>
39
40extern "C" {
41#include "../common.h"
42#include "../roots.h"
43#include "../minuitwrp/minui.h"
44#include "../recovery_ui.h"
45}
46
47#include "rapidxml.hpp"
48#include "objects.hpp"
49#include "../data.hpp"
Dees_Troyeead9852013-02-15 14:31:06 -060050#include "../twrp-functions.hpp"
51
52#define SCROLLING_SPEED_DECREMENT 6
53#define SCROLLING_FLOOR 10
54#define SCROLLING_MULTIPLIER 6
Dees_Troy51a0e822012-09-05 15:24:24 -040055
56GUIListBox::GUIListBox(xml_node<>* node)
57{
Dees_Troyeead9852013-02-15 14:31:06 -060058 xml_attribute<>* attr;
59 xml_node<>* child;
60 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 -040061
Dees_Troyeead9852013-02-15 14:31:06 -060062 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
Dees_Troye4284592013-02-19 16:59:35 +000063 mIconWidth = mIconHeight = mSelectedIconHeight = mSelectedIconWidth = mUnselectedIconHeight = mUnselectedIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
Dees_Troyeead9852013-02-15 14:31:06 -060064 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
65 mIconSelected = mIconUnselected = mBackground = mFont = mHeaderIcon = NULL;
66 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
Dees_Troy58f5cf02013-02-27 22:21:41 +000067 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
68 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troyeead9852013-02-15 14:31:06 -060069 mUpdate = 0;
70 touchDebounce = 6;
71 ConvertStrToColor("black", &mBackgroundColor);
72 ConvertStrToColor("black", &mHeaderBackgroundColor);
73 ConvertStrToColor("black", &mSeparatorColor);
74 ConvertStrToColor("black", &mHeaderSeparatorColor);
75 ConvertStrToColor("white", &mFontColor);
76 ConvertStrToColor("white", &mHeaderFontColor);
Dees_Troy58f5cf02013-02-27 22:21:41 +000077 ConvertStrToColor("white", &mFastScrollLineColor);
78 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troyeead9852013-02-15 14:31:06 -060079 hasHighlightColor = false;
80 hasFontHighlightColor = false;
81 isHighlighted = false;
82 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040083
Dees_Troyeead9852013-02-15 14:31:06 -060084 // Load header text
85 child = node->first_node("header");
86 if (child)
87 {
88 attr = child->first_attribute("icon");
89 if (attr)
90 mHeaderIcon = PageManager::FindResource(attr->value());
Dees_Troy51a0e822012-09-05 15:24:24 -040091
Dees_Troyeead9852013-02-15 14:31:06 -060092 attr = child->first_attribute("background");
93 if (attr)
94 {
95 std::string color = attr->value();
96 ConvertStrToColor(color, &mHeaderBackgroundColor);
97 header_background_color_specified = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040098 }
Dees_Troyeead9852013-02-15 14:31:06 -060099 attr = child->first_attribute("textcolor");
100 if (attr)
101 {
102 std::string color = attr->value();
103 ConvertStrToColor(color, &mHeaderFontColor);
104 header_text_color_specified = -1;
105 }
106 attr = child->first_attribute("separatorcolor");
107 if (attr)
108 {
109 std::string color = attr->value();
110 ConvertStrToColor(color, &mHeaderSeparatorColor);
111 header_separator_color_specified = -1;
112 }
113 attr = child->first_attribute("separatorheight");
114 if (attr) {
115 string parsevalue = gui_parse_text(attr->value());
116 mHeaderSeparatorH = atoi(parsevalue.c_str());
117 header_separator_height_specified = -1;
118 }
119 }
120 child = node->first_node("text");
121 if (child) mHeaderText = child->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400122
Dees_Troyeead9852013-02-15 14:31:06 -0600123 memset(&mHighlightColor, 0, sizeof(COLOR));
124 child = node->first_node("highlight");
125 if (child) {
126 attr = child->first_attribute("color");
127 if (attr) {
128 hasHighlightColor = true;
129 std::string color = attr->value();
130 ConvertStrToColor(color, &mHighlightColor);
131 }
132 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400133
Dees_Troyeead9852013-02-15 14:31:06 -0600134 // Simple way to check for static state
135 mLastValue = gui_parse_text(mHeaderText);
136 if (mLastValue != mHeaderText)
137 mHeaderIsStatic = 0;
138 else
139 mHeaderIsStatic = -1;
140
141 child = node->first_node("icon");
142 if (child)
143 {
144 attr = child->first_attribute("selected");
145 if (attr)
146 mIconSelected = PageManager::FindResource(attr->value());
147 attr = child->first_attribute("unselected");
148 if (attr)
149 mIconUnselected = PageManager::FindResource(attr->value());
150 }
151 child = node->first_node("background");
152 if (child)
153 {
154 attr = child->first_attribute("resource");
155 if (attr)
156 mBackground = PageManager::FindResource(attr->value());
157 attr = child->first_attribute("color");
158 if (attr)
159 {
160 std::string color = attr->value();
161 ConvertStrToColor(color, &mBackgroundColor);
162 if (!header_background_color_specified)
163 ConvertStrToColor(color, &mHeaderBackgroundColor);
164 }
165 }
166
167 // Load the placement
168 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
169 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
170
171 // Load the font, and possibly override the color
172 child = node->first_node("font");
173 if (child)
174 {
175 attr = child->first_attribute("resource");
176 if (attr)
177 mFont = PageManager::FindResource(attr->value());
178
179 attr = child->first_attribute("color");
180 if (attr)
181 {
182 std::string color = attr->value();
183 ConvertStrToColor(color, &mFontColor);
184 if (!header_text_color_specified)
185 ConvertStrToColor(color, &mHeaderFontColor);
186 }
187
188 attr = child->first_attribute("spacing");
189 if (attr) {
190 string parsevalue = gui_parse_text(attr->value());
191 mLineSpacing = atoi(parsevalue.c_str());
192 }
193
194 attr = child->first_attribute("highlightcolor");
195 memset(&mFontHighlightColor, 0, sizeof(COLOR));
196 if (attr)
197 {
198 std::string color = attr->value();
199 ConvertStrToColor(color, &mFontHighlightColor);
200 hasFontHighlightColor = true;
201 }
202 }
203
204 // Load the separator if it exists
205 child = node->first_node("separator");
206 if (child)
207 {
208 attr = child->first_attribute("color");
209 if (attr)
210 {
211 std::string color = attr->value();
212 ConvertStrToColor(color, &mSeparatorColor);
213 if (!header_separator_color_specified)
214 ConvertStrToColor(color, &mHeaderSeparatorColor);
215 }
216
217 attr = child->first_attribute("height");
218 if (attr) {
219 string parsevalue = gui_parse_text(attr->value());
220 mSeparatorH = atoi(parsevalue.c_str());
221 if (!header_separator_height_specified)
222 mHeaderSeparatorH = mSeparatorH;
223 }
224 }
225
226 // Handle the result variable
227 child = node->first_node("data");
228 if (child)
229 {
230 attr = child->first_attribute("name");
231 if (attr)
232 mVariable = attr->value();
233 attr = child->first_attribute("default");
234 if (attr)
235 DataManager::SetValue(mVariable, attr->value());
236 }
237
Dees_Troy58f5cf02013-02-27 22:21:41 +0000238 // Fast scroll colors
239 child = node->first_node("fastscroll");
240 if (child)
241 {
242 attr = child->first_attribute("linecolor");
243 if(attr)
244 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
245
246 attr = child->first_attribute("rectcolor");
247 if(attr)
248 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
249
250 attr = child->first_attribute("w");
251 if (attr) {
252 string parsevalue = gui_parse_text(attr->value());
253 mFastScrollW = atoi(parsevalue.c_str());
254 }
255
256 attr = child->first_attribute("linew");
257 if (attr) {
258 string parsevalue = gui_parse_text(attr->value());
259 mFastScrollLineW = atoi(parsevalue.c_str());
260 }
261
262 attr = child->first_attribute("rectw");
263 if (attr) {
264 string parsevalue = gui_parse_text(attr->value());
265 mFastScrollRectW = atoi(parsevalue.c_str());
266 }
267
268 attr = child->first_attribute("recth");
269 if (attr) {
270 string parsevalue = gui_parse_text(attr->value());
271 mFastScrollRectH = atoi(parsevalue.c_str());
272 }
273 }
274
Dees_Troyeead9852013-02-15 14:31:06 -0600275 // Retrieve the line height
276 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
277 mLineHeight = mFontHeight;
278 mHeaderH = mFontHeight;
279
280 if (mIconSelected && mIconSelected->GetResource())
281 {
282 mSelectedIconWidth = gr_get_width(mIconSelected->GetResource());
283 mSelectedIconHeight = gr_get_height(mIconSelected->GetResource());
284 if (mSelectedIconHeight > (int)mLineHeight)
285 mLineHeight = mSelectedIconHeight;
286 mIconWidth = mSelectedIconWidth;
287 }
288
289 if (mIconUnselected && mIconUnselected->GetResource())
290 {
291 mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
292 mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
293 if (mUnselectedIconHeight > (int)mLineHeight)
294 mLineHeight = mUnselectedIconHeight;
295 if (mUnselectedIconWidth > mIconWidth)
296 mIconWidth = mUnselectedIconWidth;
297 }
298
299 if (mHeaderIcon && mHeaderIcon->GetResource())
300 {
301 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
302 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
303 if (mHeaderIconHeight > mHeaderH)
304 mHeaderH = mHeaderIconHeight;
305 if (mHeaderIconWidth > mIconWidth)
306 mIconWidth = mHeaderIconWidth;
307 }
308
309 mHeaderH += mLineSpacing + mHeaderSeparatorH;
310 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
311 if (mHeaderH < actualLineHeight)
312 mHeaderH = actualLineHeight;
313
314 if (actualLineHeight / 3 > 6)
315 touchDebounce = actualLineHeight / 3;
316
317 if (mBackground && mBackground->GetResource())
318 {
319 mBackgroundW = gr_get_width(mBackground->GetResource());
320 mBackgroundH = gr_get_height(mBackground->GetResource());
321 }
322
Dees_Troy51a0e822012-09-05 15:24:24 -0400323 // Get the currently selected value for the list
324 DataManager::GetValue(mVariable, currentValue);
325
326 // Get the data for the list
327 child = node->first_node("listitem");
328 if (!child) return;
329
330 while (child)
331 {
332 ListData data;
333
334 attr = child->first_attribute("name");
335 if (!attr) return;
336 data.displayName = attr->value();
337
338 data.variableValue = child->value();
Dees_Troyeead9852013-02-15 14:31:06 -0600339 if (child->value() == currentValue) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400340 data.selected = 1;
Dees_Troyeead9852013-02-15 14:31:06 -0600341 } else {
Dees_Troy51a0e822012-09-05 15:24:24 -0400342 data.selected = 0;
Dees_Troyeead9852013-02-15 14:31:06 -0600343 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400344
345 mList.push_back(data);
346
347 child = child->next_sibling("listitem");
348 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400349}
350
351GUIListBox::~GUIListBox()
352{
353}
354
355int GUIListBox::Render(void)
Dees_Troyeead9852013-02-15 14:31:06 -0600356{
Dees_Troy51a0e822012-09-05 15:24:24 -0400357 // First step, fill background
Dees_Troyeead9852013-02-15 14:31:06 -0600358 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
359 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400360
Dees_Troyeead9852013-02-15 14:31:06 -0600361 // Next, render the background resource (if it exists)
362 if (mBackground && mBackground->GetResource())
363 {
364 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
365 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
366 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
367 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400368
Dees_Troyeead9852013-02-15 14:31:06 -0600369 // This tells us how many lines we can actually render
370 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
371 int line;
Dees_Troy51a0e822012-09-05 15:24:24 -0400372
Dees_Troyeead9852013-02-15 14:31:06 -0600373 int listSize = mList.size();
Dees_Troy58f5cf02013-02-27 22:21:41 +0000374 int listW = mRenderW;
Dees_Troy51a0e822012-09-05 15:24:24 -0400375
Dees_Troyeead9852013-02-15 14:31:06 -0600376 if (listSize < lines) {
377 lines = listSize;
378 scrollingY = 0;
Dees_Troy58f5cf02013-02-27 22:21:41 +0000379 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troyeead9852013-02-15 14:31:06 -0600380 } else {
Dees_Troy58f5cf02013-02-27 22:21:41 +0000381 listW -= mFastScrollW; // space for fast scroll
Dees_Troyeead9852013-02-15 14:31:06 -0600382 lines++;
383 if (lines < listSize)
384 lines++;
385 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400386
Dees_Troyeead9852013-02-15 14:31:06 -0600387 void* fontResource = NULL;
388 if (mFont) fontResource = mFont->GetResource();
Dees_Troy51a0e822012-09-05 15:24:24 -0400389
Dees_Troyeead9852013-02-15 14:31:06 -0600390 int yPos = mRenderY + mHeaderH + scrollingY;
391 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
392 int currentIconHeight = 0, currentIconWidth = 0;
393 int currentIconOffsetY = 0, currentIconOffsetX = 0;
394 int UnselectedIconOffsetY = (int)((actualLineHeight - mUnselectedIconHeight) / 2), SelectedIconOffsetY = (int)((actualLineHeight - mSelectedIconHeight) / 2);
395 int UnselectedIconOffsetX = (mIconWidth - mUnselectedIconWidth) / 2, SelectedIconOffsetX = (mIconWidth - mSelectedIconWidth) / 2;
396 int actualSelection = mStart;
Dees_Troy51a0e822012-09-05 15:24:24 -0400397
Dees_Troyeead9852013-02-15 14:31:06 -0600398 if (isHighlighted) {
399 int selectY = scrollingY;
Dees_Troy51a0e822012-09-05 15:24:24 -0400400
Dees_Troyeead9852013-02-15 14:31:06 -0600401 // Locate the correct line for highlighting
402 while (selectY + actualLineHeight < startSelection) {
403 selectY += actualLineHeight;
404 actualSelection++;
405 }
406 if (hasHighlightColor) {
407 // Highlight the area
408 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
409 int HighlightHeight = actualLineHeight;
410 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
411 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
412 }
413 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
414 }
415 }
416
417 for (line = 0; line < lines; line++)
418 {
419 Resource* icon;
420 std::string label;
421
422 if (line + mStart >= listSize)
423 continue;
424
425 label = mList.at(line + mStart).displayName;
426 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
427 // Use the highlight color for the font
428 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
429 } else {
430 // Set the color for the font
431 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
432 }
433
Dees_Troy51a0e822012-09-05 15:24:24 -0400434 if (mList.at(line + mStart).selected != 0)
435 {
436 icon = mIconSelected;
Dees_Troyeead9852013-02-15 14:31:06 -0600437 currentIconHeight = mSelectedIconHeight;
438 currentIconWidth = mSelectedIconWidth;
439 currentIconOffsetY = SelectedIconOffsetY;
440 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400441 }
442 else
443 {
444 icon = mIconUnselected;
Dees_Troyeead9852013-02-15 14:31:06 -0600445 currentIconHeight = mSelectedIconHeight;
446 currentIconWidth = mSelectedIconWidth;
447 currentIconOffsetY = SelectedIconOffsetY;
448 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400449 }
450
Dees_Troyeead9852013-02-15 14:31:06 -0600451 if (icon && icon->GetResource())
452 {
453 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
454 if (image_y + currentIconHeight > mRenderY + mRenderH)
455 rect_y = mRenderY + mRenderH - image_y;
456 else
457 rect_y = currentIconHeight;
458 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
459 }
Dees_Troy58f5cf02013-02-27 22:21:41 +0000460 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400461
Dees_Troyeead9852013-02-15 14:31:06 -0600462 // Add the separator
463 if (yPos + actualLineHeight < mRenderH + mRenderY) {
464 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Dees_Troy58f5cf02013-02-27 22:21:41 +0000465 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troyeead9852013-02-15 14:31:06 -0600466 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400467
Dees_Troyeead9852013-02-15 14:31:06 -0600468 // Move the yPos
469 yPos += actualLineHeight;
470 }
471
472 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
473 // First step, fill background
474 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
475 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
476
477 // Now, we need the header (icon + text)
478 yPos = mRenderY;
479 {
480 Resource* headerIcon;
481 int mIconOffsetX = 0;
482
483 // render the icon if it exists
484 headerIcon = mHeaderIcon;
485 if (headerIcon && headerIcon->GetResource())
486 {
487 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
488 mIconOffsetX = mIconWidth;
489 }
490
491 // render the text
492 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
493 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
494
495 // Add the separator
496 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
497 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
498 }
499
Dees_Troy58f5cf02013-02-27 22:21:41 +0000500 // render fast scroll
501 lines = (mRenderH - mHeaderH) / (actualLineHeight);
502 if(mFastScrollW > 0 && listSize > lines)
503 {
504 int startX = listW + mRenderX;
505 int fWidth = mRenderW - listW;
506 int fHeight = mRenderH - mHeaderH;
507
508 // line
509 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
510 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
511
512 // rect
513 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((listSize)*actualLineHeight-lines*actualLineHeight);
514 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
515 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
516
517 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
518 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
519 }
520
Dees_Troyeead9852013-02-15 14:31:06 -0600521 mUpdate = 0;
522 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400523}
524
525int GUIListBox::Update(void)
526{
Dees_Troyeead9852013-02-15 14:31:06 -0600527 if (!mHeaderIsStatic) {
528 std::string newValue = gui_parse_text(mHeaderText);
529 if (mLastValue != newValue) {
530 mLastValue = newValue;
531 mUpdate = 1;
532 }
533 }
534
535 if (mUpdate)
536 {
537 mUpdate = 0;
538 if (Render() == 0)
Dees_Troy51a0e822012-09-05 15:24:24 -0400539 return 2;
Dees_Troyeead9852013-02-15 14:31:06 -0600540 }
541
542 // Handle kinetic scrolling
543 if (scrollingSpeed == 0) {
544 // Do nothing
545 } else if (scrollingSpeed > 0) {
546 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
547 scrollingY += scrollingSpeed;
548 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
549 } else {
550 scrollingY += ((int) (actualLineHeight * 2.5));
551 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
552 }
553 while (mStart && scrollingY > 0) {
554 mStart--;
555 scrollingY -= actualLineHeight;
556 }
557 if (mStart == 0 && scrollingY > 0) {
558 scrollingY = 0;
559 scrollingSpeed = 0;
560 } else if (scrollingSpeed < SCROLLING_FLOOR)
561 scrollingSpeed = 0;
562 mUpdate = 1;
563 } else if (scrollingSpeed < 0) {
564 int totalSize = mList.size();
565 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
566
567 if (totalSize > lines) {
568 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
569
570 bottom_offset -= actualLineHeight;
571
572 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
573 scrollingY += scrollingSpeed;
574 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
575 } else {
576 scrollingY -= ((int) (actualLineHeight * 2.5));
577 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
578 }
579 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
580 mStart++;
581 scrollingY += actualLineHeight;
582 }
583 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
584 mStart = totalSize - lines - 1;
585 scrollingY = bottom_offset;
586 } else if (mStart + lines >= totalSize && scrollingY < 0) {
587 mStart = totalSize - lines;
588 scrollingY = 0;
589 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
590 scrollingSpeed = 0;
591 mUpdate = 1;
592 }
593 }
594
595 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400596}
597
598int GUIListBox::GetSelection(int x, int y)
599{
Dees_Troyeead9852013-02-15 14:31:06 -0600600 // We only care about y position
601 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
602 return (y - mRenderY - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400603}
604
605int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
606{
Dees_Troyeead9852013-02-15 14:31:06 -0600607 static int lastY = 0, last2Y = 0;
608 int selection = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400609
Dees_Troyeead9852013-02-15 14:31:06 -0600610 switch (state)
611 {
612 case TOUCH_START:
613 if (scrollingSpeed != 0)
614 startSelection = -1;
615 else
616 startSelection = GetSelection(x,y);
617 isHighlighted = (startSelection > -1);
618 if (isHighlighted)
619 mUpdate = 1;
620 startY = lastY = last2Y = y;
621 scrollingSpeed = 0;
622 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400623
Dees_Troyeead9852013-02-15 14:31:06 -0600624 case TOUCH_DRAG:
625 // Check if we dragged out of the selection window
626 if (GetSelection(x, y) == -1) {
627 last2Y = lastY = 0;
628 if (isHighlighted) {
629 isHighlighted = false;
630 mUpdate = 1;
631 }
632 break;
633 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400634
Dees_Troy58f5cf02013-02-27 22:21:41 +0000635 // Fast scroll
636 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
637 {
638 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
639 int totalSize = mList.size();
640 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
641
642 float l = float((totalSize-lines)*pct)/100;
643 if(l + lines >= totalSize)
644 {
645 mStart = totalSize - lines;
646 scrollingY = 0;
647 }
648 else
649 {
650 mStart = l;
651 scrollingY = -(l - int(l))*actualLineHeight;
652 }
653
654 startSelection = -1;
655 mUpdate = 1;
656 scrollingSpeed = 0;
657 isHighlighted = false;
658 break;
659 }
660
Dees_Troyeead9852013-02-15 14:31:06 -0600661 // Provide some debounce on initial touches
662 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
663 isHighlighted = true;
664 mUpdate = 1;
665 break;
666 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400667
Dees_Troyeead9852013-02-15 14:31:06 -0600668 isHighlighted = false;
669 last2Y = lastY;
670 lastY = y;
671 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400672
Dees_Troyeead9852013-02-15 14:31:06 -0600673 // Handle scrolling
674 scrollingY += y - startY;
675 startY = y;
676 while(mStart && scrollingY > 0) {
677 mStart--;
678 scrollingY -= actualLineHeight;
679 }
680 if (mStart == 0 && scrollingY > 0)
681 scrollingY = 0;
682 {
683 int totalSize = mList.size();
684 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400685
Dees_Troyeead9852013-02-15 14:31:06 -0600686 if (totalSize > lines) {
687 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400688
Dees_Troyeead9852013-02-15 14:31:06 -0600689 bottom_offset -= actualLineHeight;
Dees_Troy51a0e822012-09-05 15:24:24 -0400690
Dees_Troyeead9852013-02-15 14:31:06 -0600691 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
692 mStart++;
693 scrollingY += actualLineHeight;
694 }
695 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
696 mStart = totalSize - lines - 1;
697 scrollingY = bottom_offset;
698 } else if (mStart + lines >= totalSize && scrollingY < 0) {
699 mStart = totalSize - lines;
700 scrollingY = 0;
701 }
702 } else
703 scrollingY = 0;
704 }
705 mUpdate = 1;
706 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400707
Dees_Troyeead9852013-02-15 14:31:06 -0600708 case TOUCH_RELEASE:
709 isHighlighted = false;
710 if (startSelection >= 0)
711 {
712 // We've selected an item!
713 std::string str;
714
715 int listSize = mList.size();
716 int selectY = scrollingY, actualSelection = mStart;
717
718 // Move the selection to the proper place in the array
719 while (selectY + actualLineHeight < startSelection) {
720 selectY += actualLineHeight;
721 actualSelection++;
722 }
723
724 if (actualSelection < listSize && !mVariable.empty())
725 {
726 int i;
727 for (i=0; i<listSize; i++)
728 mList.at(i).selected = 0;
729
730 str = mList.at(actualSelection).variableValue;
731 mList.at(actualSelection).selected = 1;
732 DataManager::SetValue(mVariable, str);
733 mUpdate = 1;
734 }
735 } else {
736 // This is for kinetic scrolling
737 scrollingSpeed = lastY - last2Y;
738 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
739 scrollingSpeed *= SCROLLING_MULTIPLIER;
740 else
741 scrollingSpeed = 0;
742 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400743 case TOUCH_REPEAT:
Dees_Troyeead9852013-02-15 14:31:06 -0600744 case TOUCH_HOLD:
745 break;
746 }
747 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400748}
749
750int GUIListBox::NotifyVarChange(std::string varName, std::string value)
751{
Dees_Troyeead9852013-02-15 14:31:06 -0600752 if (!mHeaderIsStatic) {
753 std::string newValue = gui_parse_text(mHeaderText);
754 if (mLastValue != newValue) {
755 mLastValue = newValue;
756 mStart = 0;
757 scrollingY = 0;
758 scrollingSpeed = 0;
759 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400760 }
Dees_Troyeead9852013-02-15 14:31:06 -0600761 }
762 if (varName == mVariable)
Dees_Troy51a0e822012-09-05 15:24:24 -0400763 {
764 int i, listSize = mList.size(), selected_index = 0;
765
766 currentValue = value;
767
768 for (i=0; i<listSize; i++) {
769 if (mList.at(i).variableValue == currentValue) {
770 mList.at(i).selected = 1;
771 selected_index = i;
772 } else
773 mList.at(i).selected = 0;
774 }
775
776 int lines = mRenderH / (mLineHeight + mLineSpacing);
777 int line;
778
779 if (selected_index > mStart + lines - 1)
780 mStart = selected_index;
781 if (mStart > listSize - lines) {
782 mStart = listSize - lines;
783 } else if (selected_index < mStart) {
784 mStart = selected_index;
785 }
786
787 mUpdate = 1;
788 return 0;
789 }
Dees_Troyeead9852013-02-15 14:31:06 -0600790 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400791}
792
793int GUIListBox::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
794{
Dees_Troyeead9852013-02-15 14:31:06 -0600795 mRenderX = x;
796 mRenderY = y;
797 if (w || h)
798 {
799 mRenderW = w;
800 mRenderH = h;
801 }
802 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
803 mUpdate = 1;
804 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400805}
806
807void GUIListBox::SetPageFocus(int inFocus)
808{
Dees_Troyeead9852013-02-15 14:31:06 -0600809 if (inFocus)
810 {
811 DataManager::GetValue(mVariable, currentValue);
812 NotifyVarChange(mVariable, currentValue);
813 mUpdate = 1;
814 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400815}