blob: 3af40ed5b38bb5d7459514e8d08dd9349890f053 [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" {
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_Troyeead9852013-02-15 14:31:06 -060048#include "../twrp-functions.hpp"
49
50#define SCROLLING_SPEED_DECREMENT 6
51#define SCROLLING_FLOOR 10
52#define SCROLLING_MULTIPLIER 6
Dees_Troy51a0e822012-09-05 15:24:24 -040053
54GUIListBox::GUIListBox(xml_node<>* node)
55{
Dees_Troyeead9852013-02-15 14:31:06 -060056 xml_attribute<>* attr;
57 xml_node<>* child;
58 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 -040059
Dees_Troyeead9852013-02-15 14:31:06 -060060 mStart = mLineSpacing = startY = mFontHeight = mSeparatorH = scrollingY = scrollingSpeed = 0;
Dees_Troye4284592013-02-19 16:59:35 +000061 mIconWidth = mIconHeight = mSelectedIconHeight = mSelectedIconWidth = mUnselectedIconHeight = mUnselectedIconWidth = mHeaderIconHeight = mHeaderIconWidth = 0;
Dees_Troyeead9852013-02-15 14:31:06 -060062 mHeaderSeparatorH = mLineHeight = mHeaderIsStatic = mHeaderH = actualLineHeight = 0;
63 mIconSelected = mIconUnselected = mBackground = mFont = mHeaderIcon = NULL;
64 mBackgroundX = mBackgroundY = mBackgroundW = mBackgroundH = 0;
Dees_Troy58f5cf02013-02-27 22:21:41 +000065 mFastScrollW = mFastScrollLineW = mFastScrollRectW = mFastScrollRectH = 0;
66 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troyeead9852013-02-15 14:31:06 -060067 mUpdate = 0;
68 touchDebounce = 6;
69 ConvertStrToColor("black", &mBackgroundColor);
70 ConvertStrToColor("black", &mHeaderBackgroundColor);
71 ConvertStrToColor("black", &mSeparatorColor);
72 ConvertStrToColor("black", &mHeaderSeparatorColor);
73 ConvertStrToColor("white", &mFontColor);
74 ConvertStrToColor("white", &mHeaderFontColor);
Dees_Troy58f5cf02013-02-27 22:21:41 +000075 ConvertStrToColor("white", &mFastScrollLineColor);
76 ConvertStrToColor("white", &mFastScrollRectColor);
Dees_Troyeead9852013-02-15 14:31:06 -060077 hasHighlightColor = false;
78 hasFontHighlightColor = false;
79 isHighlighted = false;
80 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040081
Dees_Troyeead9852013-02-15 14:31:06 -060082 // Load header text
83 child = node->first_node("header");
84 if (child)
85 {
86 attr = child->first_attribute("icon");
87 if (attr)
88 mHeaderIcon = PageManager::FindResource(attr->value());
Dees_Troy51a0e822012-09-05 15:24:24 -040089
Dees_Troyeead9852013-02-15 14:31:06 -060090 attr = child->first_attribute("background");
91 if (attr)
92 {
93 std::string color = attr->value();
94 ConvertStrToColor(color, &mHeaderBackgroundColor);
95 header_background_color_specified = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -040096 }
Dees_Troyeead9852013-02-15 14:31:06 -060097 attr = child->first_attribute("textcolor");
98 if (attr)
99 {
100 std::string color = attr->value();
101 ConvertStrToColor(color, &mHeaderFontColor);
102 header_text_color_specified = -1;
103 }
104 attr = child->first_attribute("separatorcolor");
105 if (attr)
106 {
107 std::string color = attr->value();
108 ConvertStrToColor(color, &mHeaderSeparatorColor);
109 header_separator_color_specified = -1;
110 }
111 attr = child->first_attribute("separatorheight");
112 if (attr) {
113 string parsevalue = gui_parse_text(attr->value());
114 mHeaderSeparatorH = atoi(parsevalue.c_str());
115 header_separator_height_specified = -1;
116 }
117 }
118 child = node->first_node("text");
119 if (child) mHeaderText = child->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400120
Dees_Troyeead9852013-02-15 14:31:06 -0600121 memset(&mHighlightColor, 0, sizeof(COLOR));
122 child = node->first_node("highlight");
123 if (child) {
124 attr = child->first_attribute("color");
125 if (attr) {
126 hasHighlightColor = true;
127 std::string color = attr->value();
128 ConvertStrToColor(color, &mHighlightColor);
129 }
130 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400131
Dees_Troyeead9852013-02-15 14:31:06 -0600132 // Simple way to check for static state
133 mLastValue = gui_parse_text(mHeaderText);
134 if (mLastValue != mHeaderText)
135 mHeaderIsStatic = 0;
136 else
137 mHeaderIsStatic = -1;
138
139 child = node->first_node("icon");
140 if (child)
141 {
142 attr = child->first_attribute("selected");
143 if (attr)
144 mIconSelected = PageManager::FindResource(attr->value());
145 attr = child->first_attribute("unselected");
146 if (attr)
147 mIconUnselected = PageManager::FindResource(attr->value());
148 }
149 child = node->first_node("background");
150 if (child)
151 {
152 attr = child->first_attribute("resource");
153 if (attr)
154 mBackground = PageManager::FindResource(attr->value());
155 attr = child->first_attribute("color");
156 if (attr)
157 {
158 std::string color = attr->value();
159 ConvertStrToColor(color, &mBackgroundColor);
160 if (!header_background_color_specified)
161 ConvertStrToColor(color, &mHeaderBackgroundColor);
162 }
163 }
164
165 // Load the placement
166 LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH);
167 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
168
169 // Load the font, and possibly override the color
170 child = node->first_node("font");
171 if (child)
172 {
173 attr = child->first_attribute("resource");
174 if (attr)
175 mFont = PageManager::FindResource(attr->value());
176
177 attr = child->first_attribute("color");
178 if (attr)
179 {
180 std::string color = attr->value();
181 ConvertStrToColor(color, &mFontColor);
182 if (!header_text_color_specified)
183 ConvertStrToColor(color, &mHeaderFontColor);
184 }
185
186 attr = child->first_attribute("spacing");
187 if (attr) {
188 string parsevalue = gui_parse_text(attr->value());
189 mLineSpacing = atoi(parsevalue.c_str());
190 }
191
192 attr = child->first_attribute("highlightcolor");
193 memset(&mFontHighlightColor, 0, sizeof(COLOR));
194 if (attr)
195 {
196 std::string color = attr->value();
197 ConvertStrToColor(color, &mFontHighlightColor);
198 hasFontHighlightColor = true;
199 }
200 }
201
202 // Load the separator if it exists
203 child = node->first_node("separator");
204 if (child)
205 {
206 attr = child->first_attribute("color");
207 if (attr)
208 {
209 std::string color = attr->value();
210 ConvertStrToColor(color, &mSeparatorColor);
211 if (!header_separator_color_specified)
212 ConvertStrToColor(color, &mHeaderSeparatorColor);
213 }
214
215 attr = child->first_attribute("height");
216 if (attr) {
217 string parsevalue = gui_parse_text(attr->value());
218 mSeparatorH = atoi(parsevalue.c_str());
219 if (!header_separator_height_specified)
220 mHeaderSeparatorH = mSeparatorH;
221 }
222 }
223
224 // Handle the result variable
225 child = node->first_node("data");
226 if (child)
227 {
228 attr = child->first_attribute("name");
229 if (attr)
230 mVariable = attr->value();
231 attr = child->first_attribute("default");
232 if (attr)
233 DataManager::SetValue(mVariable, attr->value());
234 }
235
Dees_Troy58f5cf02013-02-27 22:21:41 +0000236 // Fast scroll colors
237 child = node->first_node("fastscroll");
238 if (child)
239 {
240 attr = child->first_attribute("linecolor");
241 if(attr)
242 ConvertStrToColor(attr->value(), &mFastScrollLineColor);
243
244 attr = child->first_attribute("rectcolor");
245 if(attr)
246 ConvertStrToColor(attr->value(), &mFastScrollRectColor);
247
248 attr = child->first_attribute("w");
249 if (attr) {
250 string parsevalue = gui_parse_text(attr->value());
251 mFastScrollW = atoi(parsevalue.c_str());
252 }
253
254 attr = child->first_attribute("linew");
255 if (attr) {
256 string parsevalue = gui_parse_text(attr->value());
257 mFastScrollLineW = atoi(parsevalue.c_str());
258 }
259
260 attr = child->first_attribute("rectw");
261 if (attr) {
262 string parsevalue = gui_parse_text(attr->value());
263 mFastScrollRectW = atoi(parsevalue.c_str());
264 }
265
266 attr = child->first_attribute("recth");
267 if (attr) {
268 string parsevalue = gui_parse_text(attr->value());
269 mFastScrollRectH = atoi(parsevalue.c_str());
270 }
271 }
272
Dees_Troyeead9852013-02-15 14:31:06 -0600273 // Retrieve the line height
274 gr_getFontDetails(mFont ? mFont->GetResource() : NULL, &mFontHeight, NULL);
275 mLineHeight = mFontHeight;
276 mHeaderH = mFontHeight;
277
278 if (mIconSelected && mIconSelected->GetResource())
279 {
280 mSelectedIconWidth = gr_get_width(mIconSelected->GetResource());
281 mSelectedIconHeight = gr_get_height(mIconSelected->GetResource());
282 if (mSelectedIconHeight > (int)mLineHeight)
283 mLineHeight = mSelectedIconHeight;
284 mIconWidth = mSelectedIconWidth;
285 }
286
287 if (mIconUnselected && mIconUnselected->GetResource())
288 {
289 mUnselectedIconWidth = gr_get_width(mIconUnselected->GetResource());
290 mUnselectedIconHeight = gr_get_height(mIconUnselected->GetResource());
291 if (mUnselectedIconHeight > (int)mLineHeight)
292 mLineHeight = mUnselectedIconHeight;
293 if (mUnselectedIconWidth > mIconWidth)
294 mIconWidth = mUnselectedIconWidth;
295 }
296
297 if (mHeaderIcon && mHeaderIcon->GetResource())
298 {
299 mHeaderIconWidth = gr_get_width(mHeaderIcon->GetResource());
300 mHeaderIconHeight = gr_get_height(mHeaderIcon->GetResource());
301 if (mHeaderIconHeight > mHeaderH)
302 mHeaderH = mHeaderIconHeight;
303 if (mHeaderIconWidth > mIconWidth)
304 mIconWidth = mHeaderIconWidth;
305 }
306
307 mHeaderH += mLineSpacing + mHeaderSeparatorH;
308 actualLineHeight = mLineHeight + mLineSpacing + mSeparatorH;
309 if (mHeaderH < actualLineHeight)
310 mHeaderH = actualLineHeight;
311
312 if (actualLineHeight / 3 > 6)
313 touchDebounce = actualLineHeight / 3;
314
315 if (mBackground && mBackground->GetResource())
316 {
317 mBackgroundW = gr_get_width(mBackground->GetResource());
318 mBackgroundH = gr_get_height(mBackground->GetResource());
319 }
320
Dees_Troy51a0e822012-09-05 15:24:24 -0400321 // Get the currently selected value for the list
322 DataManager::GetValue(mVariable, currentValue);
323
324 // Get the data for the list
325 child = node->first_node("listitem");
326 if (!child) return;
327
328 while (child)
329 {
330 ListData data;
331
332 attr = child->first_attribute("name");
333 if (!attr) return;
334 data.displayName = attr->value();
335
336 data.variableValue = child->value();
Dees_Troyeead9852013-02-15 14:31:06 -0600337 if (child->value() == currentValue) {
Dees_Troy51a0e822012-09-05 15:24:24 -0400338 data.selected = 1;
Dees_Troyeead9852013-02-15 14:31:06 -0600339 } else {
Dees_Troy51a0e822012-09-05 15:24:24 -0400340 data.selected = 0;
Dees_Troyeead9852013-02-15 14:31:06 -0600341 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400342
343 mList.push_back(data);
344
345 child = child->next_sibling("listitem");
346 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400347}
348
349GUIListBox::~GUIListBox()
350{
351}
352
353int GUIListBox::Render(void)
Dees_Troyeead9852013-02-15 14:31:06 -0600354{
Dees_Troy51a0e822012-09-05 15:24:24 -0400355 // First step, fill background
Dees_Troyeead9852013-02-15 14:31:06 -0600356 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
357 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400358
Dees_Troyeead9852013-02-15 14:31:06 -0600359 // Next, render the background resource (if it exists)
360 if (mBackground && mBackground->GetResource())
361 {
362 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
363 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
364 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
365 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400366
Dees_Troyeead9852013-02-15 14:31:06 -0600367 // This tells us how many lines we can actually render
368 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
369 int line;
Dees_Troy51a0e822012-09-05 15:24:24 -0400370
Dees_Troyeead9852013-02-15 14:31:06 -0600371 int listSize = mList.size();
Dees_Troy58f5cf02013-02-27 22:21:41 +0000372 int listW = mRenderW;
Dees_Troy51a0e822012-09-05 15:24:24 -0400373
Dees_Troyeead9852013-02-15 14:31:06 -0600374 if (listSize < lines) {
375 lines = listSize;
376 scrollingY = 0;
Dees_Troy58f5cf02013-02-27 22:21:41 +0000377 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troyeead9852013-02-15 14:31:06 -0600378 } else {
Dees_Troy58f5cf02013-02-27 22:21:41 +0000379 listW -= mFastScrollW; // space for fast scroll
Dees_Troyeead9852013-02-15 14:31:06 -0600380 lines++;
381 if (lines < listSize)
382 lines++;
383 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400384
Dees_Troyeead9852013-02-15 14:31:06 -0600385 void* fontResource = NULL;
386 if (mFont) fontResource = mFont->GetResource();
Dees_Troy51a0e822012-09-05 15:24:24 -0400387
Dees_Troyeead9852013-02-15 14:31:06 -0600388 int yPos = mRenderY + mHeaderH + scrollingY;
389 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
390 int currentIconHeight = 0, currentIconWidth = 0;
391 int currentIconOffsetY = 0, currentIconOffsetX = 0;
392 int UnselectedIconOffsetY = (int)((actualLineHeight - mUnselectedIconHeight) / 2), SelectedIconOffsetY = (int)((actualLineHeight - mSelectedIconHeight) / 2);
393 int UnselectedIconOffsetX = (mIconWidth - mUnselectedIconWidth) / 2, SelectedIconOffsetX = (mIconWidth - mSelectedIconWidth) / 2;
394 int actualSelection = mStart;
Dees_Troy51a0e822012-09-05 15:24:24 -0400395
Dees_Troyeead9852013-02-15 14:31:06 -0600396 if (isHighlighted) {
397 int selectY = scrollingY;
Dees_Troy51a0e822012-09-05 15:24:24 -0400398
Dees_Troyeead9852013-02-15 14:31:06 -0600399 // Locate the correct line for highlighting
400 while (selectY + actualLineHeight < startSelection) {
401 selectY += actualLineHeight;
402 actualSelection++;
403 }
404 if (hasHighlightColor) {
405 // Highlight the area
406 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
407 int HighlightHeight = actualLineHeight;
408 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
409 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
410 }
411 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
412 }
413 }
414
415 for (line = 0; line < lines; line++)
416 {
417 Resource* icon;
418 std::string label;
419
420 if (line + mStart >= listSize)
421 continue;
422
423 label = mList.at(line + mStart).displayName;
424 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
425 // Use the highlight color for the font
426 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
427 } else {
428 // Set the color for the font
429 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
430 }
431
Dees_Troy51a0e822012-09-05 15:24:24 -0400432 if (mList.at(line + mStart).selected != 0)
433 {
434 icon = mIconSelected;
Dees_Troyeead9852013-02-15 14:31:06 -0600435 currentIconHeight = mSelectedIconHeight;
436 currentIconWidth = mSelectedIconWidth;
437 currentIconOffsetY = SelectedIconOffsetY;
438 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400439 }
440 else
441 {
442 icon = mIconUnselected;
Dees_Troyeead9852013-02-15 14:31:06 -0600443 currentIconHeight = mSelectedIconHeight;
444 currentIconWidth = mSelectedIconWidth;
445 currentIconOffsetY = SelectedIconOffsetY;
446 currentIconOffsetX = SelectedIconOffsetX;
Dees_Troy51a0e822012-09-05 15:24:24 -0400447 }
448
Dees_Troyeead9852013-02-15 14:31:06 -0600449 if (icon && icon->GetResource())
450 {
451 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
452 if (image_y + currentIconHeight > mRenderY + mRenderH)
453 rect_y = mRenderY + mRenderH - image_y;
454 else
455 rect_y = currentIconHeight;
456 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
457 }
Dees_Troy58f5cf02013-02-27 22:21:41 +0000458 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400459
Dees_Troyeead9852013-02-15 14:31:06 -0600460 // Add the separator
461 if (yPos + actualLineHeight < mRenderH + mRenderY) {
462 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Dees_Troy58f5cf02013-02-27 22:21:41 +0000463 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troyeead9852013-02-15 14:31:06 -0600464 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400465
Dees_Troyeead9852013-02-15 14:31:06 -0600466 // Move the yPos
467 yPos += actualLineHeight;
468 }
469
470 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
471 // First step, fill background
472 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
473 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
474
475 // Now, we need the header (icon + text)
476 yPos = mRenderY;
477 {
478 Resource* headerIcon;
479 int mIconOffsetX = 0;
480
481 // render the icon if it exists
482 headerIcon = mHeaderIcon;
483 if (headerIcon && headerIcon->GetResource())
484 {
485 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
486 mIconOffsetX = mIconWidth;
487 }
488
489 // render the text
490 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
491 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
492
493 // Add the separator
494 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
495 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
496 }
497
Dees_Troy58f5cf02013-02-27 22:21:41 +0000498 // render fast scroll
499 lines = (mRenderH - mHeaderH) / (actualLineHeight);
500 if(mFastScrollW > 0 && listSize > lines)
501 {
502 int startX = listW + mRenderX;
503 int fWidth = mRenderW - listW;
504 int fHeight = mRenderH - mHeaderH;
505
506 // line
507 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
508 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
509
510 // rect
511 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((listSize)*actualLineHeight-lines*actualLineHeight);
512 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
513 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
514
515 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
516 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
517 }
518
Dees_Troyeead9852013-02-15 14:31:06 -0600519 mUpdate = 0;
520 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400521}
522
523int GUIListBox::Update(void)
524{
Dees_Troyeead9852013-02-15 14:31:06 -0600525 if (!mHeaderIsStatic) {
526 std::string newValue = gui_parse_text(mHeaderText);
527 if (mLastValue != newValue) {
528 mLastValue = newValue;
529 mUpdate = 1;
530 }
531 }
532
533 if (mUpdate)
534 {
535 mUpdate = 0;
536 if (Render() == 0)
Dees_Troy51a0e822012-09-05 15:24:24 -0400537 return 2;
Dees_Troyeead9852013-02-15 14:31:06 -0600538 }
539
540 // Handle kinetic scrolling
541 if (scrollingSpeed == 0) {
542 // Do nothing
543 } else if (scrollingSpeed > 0) {
544 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
545 scrollingY += scrollingSpeed;
546 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
547 } else {
548 scrollingY += ((int) (actualLineHeight * 2.5));
549 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
550 }
551 while (mStart && scrollingY > 0) {
552 mStart--;
553 scrollingY -= actualLineHeight;
554 }
555 if (mStart == 0 && scrollingY > 0) {
556 scrollingY = 0;
557 scrollingSpeed = 0;
558 } else if (scrollingSpeed < SCROLLING_FLOOR)
559 scrollingSpeed = 0;
560 mUpdate = 1;
561 } else if (scrollingSpeed < 0) {
562 int totalSize = mList.size();
563 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
564
565 if (totalSize > lines) {
566 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
567
568 bottom_offset -= actualLineHeight;
569
570 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
571 scrollingY += scrollingSpeed;
572 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
573 } else {
574 scrollingY -= ((int) (actualLineHeight * 2.5));
575 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
576 }
577 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
578 mStart++;
579 scrollingY += actualLineHeight;
580 }
581 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
582 mStart = totalSize - lines - 1;
583 scrollingY = bottom_offset;
584 } else if (mStart + lines >= totalSize && scrollingY < 0) {
585 mStart = totalSize - lines;
586 scrollingY = 0;
587 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
588 scrollingSpeed = 0;
589 mUpdate = 1;
590 }
591 }
592
593 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400594}
595
596int GUIListBox::GetSelection(int x, int y)
597{
Dees_Troyeead9852013-02-15 14:31:06 -0600598 // We only care about y position
599 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
600 return (y - mRenderY - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400601}
602
603int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
604{
Dees_Troyeead9852013-02-15 14:31:06 -0600605 static int lastY = 0, last2Y = 0;
606 int selection = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400607
Dees_Troyeead9852013-02-15 14:31:06 -0600608 switch (state)
609 {
610 case TOUCH_START:
611 if (scrollingSpeed != 0)
612 startSelection = -1;
613 else
614 startSelection = GetSelection(x,y);
615 isHighlighted = (startSelection > -1);
616 if (isHighlighted)
617 mUpdate = 1;
618 startY = lastY = last2Y = y;
619 scrollingSpeed = 0;
620 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400621
Dees_Troyeead9852013-02-15 14:31:06 -0600622 case TOUCH_DRAG:
623 // Check if we dragged out of the selection window
624 if (GetSelection(x, y) == -1) {
625 last2Y = lastY = 0;
626 if (isHighlighted) {
627 isHighlighted = false;
628 mUpdate = 1;
629 }
630 break;
631 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400632
Dees_Troy58f5cf02013-02-27 22:21:41 +0000633 // Fast scroll
634 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
635 {
636 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
637 int totalSize = mList.size();
638 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
639
640 float l = float((totalSize-lines)*pct)/100;
641 if(l + lines >= totalSize)
642 {
643 mStart = totalSize - lines;
644 scrollingY = 0;
645 }
646 else
647 {
648 mStart = l;
649 scrollingY = -(l - int(l))*actualLineHeight;
650 }
651
652 startSelection = -1;
653 mUpdate = 1;
654 scrollingSpeed = 0;
655 isHighlighted = false;
656 break;
657 }
658
Dees_Troyeead9852013-02-15 14:31:06 -0600659 // Provide some debounce on initial touches
660 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
661 isHighlighted = true;
662 mUpdate = 1;
663 break;
664 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400665
Dees_Troyeead9852013-02-15 14:31:06 -0600666 isHighlighted = false;
667 last2Y = lastY;
668 lastY = y;
669 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670
Dees_Troyeead9852013-02-15 14:31:06 -0600671 // Handle scrolling
672 scrollingY += y - startY;
673 startY = y;
674 while(mStart && scrollingY > 0) {
675 mStart--;
676 scrollingY -= actualLineHeight;
677 }
678 if (mStart == 0 && scrollingY > 0)
679 scrollingY = 0;
680 {
681 int totalSize = mList.size();
682 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400683
Dees_Troyeead9852013-02-15 14:31:06 -0600684 if (totalSize > lines) {
685 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400686
Dees_Troyeead9852013-02-15 14:31:06 -0600687 bottom_offset -= actualLineHeight;
Dees_Troy51a0e822012-09-05 15:24:24 -0400688
Dees_Troyeead9852013-02-15 14:31:06 -0600689 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
690 mStart++;
691 scrollingY += actualLineHeight;
692 }
693 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
694 mStart = totalSize - lines - 1;
695 scrollingY = bottom_offset;
696 } else if (mStart + lines >= totalSize && scrollingY < 0) {
697 mStart = totalSize - lines;
698 scrollingY = 0;
699 }
700 } else
701 scrollingY = 0;
702 }
703 mUpdate = 1;
704 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400705
Dees_Troyeead9852013-02-15 14:31:06 -0600706 case TOUCH_RELEASE:
707 isHighlighted = false;
708 if (startSelection >= 0)
709 {
710 // We've selected an item!
711 std::string str;
712
713 int listSize = mList.size();
714 int selectY = scrollingY, actualSelection = mStart;
715
716 // Move the selection to the proper place in the array
717 while (selectY + actualLineHeight < startSelection) {
718 selectY += actualLineHeight;
719 actualSelection++;
720 }
721
722 if (actualSelection < listSize && !mVariable.empty())
723 {
724 int i;
725 for (i=0; i<listSize; i++)
726 mList.at(i).selected = 0;
727
728 str = mList.at(actualSelection).variableValue;
729 mList.at(actualSelection).selected = 1;
730 DataManager::SetValue(mVariable, str);
731 mUpdate = 1;
732 }
733 } else {
734 // This is for kinetic scrolling
735 scrollingSpeed = lastY - last2Y;
736 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
737 scrollingSpeed *= SCROLLING_MULTIPLIER;
738 else
739 scrollingSpeed = 0;
740 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400741 case TOUCH_REPEAT:
Dees_Troyeead9852013-02-15 14:31:06 -0600742 case TOUCH_HOLD:
743 break;
744 }
745 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400746}
747
748int GUIListBox::NotifyVarChange(std::string varName, std::string value)
749{
Dees_Troyeead9852013-02-15 14:31:06 -0600750 if (!mHeaderIsStatic) {
751 std::string newValue = gui_parse_text(mHeaderText);
752 if (mLastValue != newValue) {
753 mLastValue = newValue;
754 mStart = 0;
755 scrollingY = 0;
756 scrollingSpeed = 0;
757 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400758 }
Dees_Troyeead9852013-02-15 14:31:06 -0600759 }
760 if (varName == mVariable)
Dees_Troy51a0e822012-09-05 15:24:24 -0400761 {
762 int i, listSize = mList.size(), selected_index = 0;
763
764 currentValue = value;
765
766 for (i=0; i<listSize; i++) {
767 if (mList.at(i).variableValue == currentValue) {
768 mList.at(i).selected = 1;
769 selected_index = i;
770 } else
771 mList.at(i).selected = 0;
772 }
773
774 int lines = mRenderH / (mLineHeight + mLineSpacing);
775 int line;
776
777 if (selected_index > mStart + lines - 1)
778 mStart = selected_index;
779 if (mStart > listSize - lines) {
780 mStart = listSize - lines;
781 } else if (selected_index < mStart) {
782 mStart = selected_index;
783 }
784
785 mUpdate = 1;
786 return 0;
787 }
Dees_Troyeead9852013-02-15 14:31:06 -0600788 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400789}
790
791int GUIListBox::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
792{
Dees_Troyeead9852013-02-15 14:31:06 -0600793 mRenderX = x;
794 mRenderY = y;
795 if (w || h)
796 {
797 mRenderW = w;
798 mRenderH = h;
799 }
800 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
801 mUpdate = 1;
802 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400803}
804
805void GUIListBox::SetPageFocus(int inFocus)
806{
Dees_Troyeead9852013-02-15 14:31:06 -0600807 if (inFocus)
808 {
809 DataManager::GetValue(mVariable, currentValue);
810 NotifyVarChange(mVariable, currentValue);
811 mUpdate = 1;
812 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400813}