blob: bbfc9344a94d39c0bf003929649ff662bfc05dd2 [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
Vojtech Bocekede51c52014-02-07 23:58:09 +010054GUIListBox::GUIListBox(xml_node<>* node) : GUIObject(node)
Dees_Troy51a0e822012-09-05 15:24:24 -040055{
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));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200194 if (attr)
195 {
196 std::string color = attr->value();
Dees_Troyeead9852013-02-15 14:31:06 -0600197 ConvertStrToColor(color, &mFontHighlightColor);
198 hasFontHighlightColor = true;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200199 }
Dees_Troyeead9852013-02-15 14:31:06 -0600200 }
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");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200326 if (!child) return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400327
328 while (child)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200329 {
330 ListData data;
Dees_Troy51a0e822012-09-05 15:24:24 -0400331
332 attr = child->first_attribute("name");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200333 if (!attr) return;
334 data.displayName = attr->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400335
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
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200343 mList.push_back(data);
Dees_Troy51a0e822012-09-05 15:24:24 -0400344
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 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{
Vojtech Bocekede51c52014-02-07 23:58:09 +0100355 if(!isConditionTrue())
356 return 0;
357
Dees_Troy51a0e822012-09-05 15:24:24 -0400358 // First step, fill background
Dees_Troyeead9852013-02-15 14:31:06 -0600359 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
360 gr_fill(mRenderX, mRenderY + mHeaderH, mRenderW, mRenderH - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400361
Dees_Troyeead9852013-02-15 14:31:06 -0600362 // Next, render the background resource (if it exists)
363 if (mBackground && mBackground->GetResource())
364 {
365 mBackgroundX = mRenderX + ((mRenderW - mBackgroundW) / 2);
366 mBackgroundY = mRenderY + ((mRenderH - mBackgroundH) / 2);
367 gr_blit(mBackground->GetResource(), 0, 0, mBackgroundW, mBackgroundH, mBackgroundX, mBackgroundY);
368 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400369
Dees_Troyeead9852013-02-15 14:31:06 -0600370 // This tells us how many lines we can actually render
371 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
372 int line;
Dees_Troy51a0e822012-09-05 15:24:24 -0400373
Dees_Troyeead9852013-02-15 14:31:06 -0600374 int listSize = mList.size();
Dees_Troy58f5cf02013-02-27 22:21:41 +0000375 int listW = mRenderW;
Dees_Troy51a0e822012-09-05 15:24:24 -0400376
Dees_Troyeead9852013-02-15 14:31:06 -0600377 if (listSize < lines) {
378 lines = listSize;
379 scrollingY = 0;
Dees_Troy58f5cf02013-02-27 22:21:41 +0000380 mFastScrollRectX = mFastScrollRectY = -1;
Dees_Troyeead9852013-02-15 14:31:06 -0600381 } else {
Dees_Troy58f5cf02013-02-27 22:21:41 +0000382 listW -= mFastScrollW; // space for fast scroll
Dees_Troyeead9852013-02-15 14:31:06 -0600383 lines++;
384 if (lines < listSize)
385 lines++;
386 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400387
Dees_Troyeead9852013-02-15 14:31:06 -0600388 void* fontResource = NULL;
389 if (mFont) fontResource = mFont->GetResource();
Dees_Troy51a0e822012-09-05 15:24:24 -0400390
Dees_Troyeead9852013-02-15 14:31:06 -0600391 int yPos = mRenderY + mHeaderH + scrollingY;
392 int fontOffsetY = (int)((actualLineHeight - mFontHeight) / 2);
393 int currentIconHeight = 0, currentIconWidth = 0;
394 int currentIconOffsetY = 0, currentIconOffsetX = 0;
395 int UnselectedIconOffsetY = (int)((actualLineHeight - mUnselectedIconHeight) / 2), SelectedIconOffsetY = (int)((actualLineHeight - mSelectedIconHeight) / 2);
396 int UnselectedIconOffsetX = (mIconWidth - mUnselectedIconWidth) / 2, SelectedIconOffsetX = (mIconWidth - mSelectedIconWidth) / 2;
397 int actualSelection = mStart;
Dees_Troy51a0e822012-09-05 15:24:24 -0400398
Dees_Troyeead9852013-02-15 14:31:06 -0600399 if (isHighlighted) {
400 int selectY = scrollingY;
Dees_Troy51a0e822012-09-05 15:24:24 -0400401
Dees_Troyeead9852013-02-15 14:31:06 -0600402 // Locate the correct line for highlighting
403 while (selectY + actualLineHeight < startSelection) {
404 selectY += actualLineHeight;
405 actualSelection++;
406 }
407 if (hasHighlightColor) {
408 // Highlight the area
409 gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, 255);
410 int HighlightHeight = actualLineHeight;
411 if (mRenderY + mHeaderH + selectY + actualLineHeight > mRenderH + mRenderY) {
412 HighlightHeight = actualLineHeight - (mRenderY + mHeaderH + selectY + actualLineHeight - mRenderH - mRenderY);
413 }
414 gr_fill(mRenderX, mRenderY + mHeaderH + selectY, mRenderW, HighlightHeight);
415 }
416 }
417
418 for (line = 0; line < lines; line++)
419 {
420 Resource* icon;
421 std::string label;
422
423 if (line + mStart >= listSize)
424 continue;
425
426 label = mList.at(line + mStart).displayName;
427 if (isHighlighted && hasFontHighlightColor && line + mStart == actualSelection) {
428 // Use the highlight color for the font
429 gr_color(mFontHighlightColor.red, mFontHighlightColor.green, mFontHighlightColor.blue, 255);
430 } else {
431 // Set the color for the font
432 gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, 255);
433 }
434
Dees_Troy51a0e822012-09-05 15:24:24 -0400435 if (mList.at(line + mStart).selected != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200436 {
437 icon = mIconSelected;
Dees_Troyeead9852013-02-15 14:31:06 -0600438 currentIconHeight = mSelectedIconHeight;
439 currentIconWidth = mSelectedIconWidth;
440 currentIconOffsetY = SelectedIconOffsetY;
441 currentIconOffsetX = SelectedIconOffsetX;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200442 }
443 else
444 {
445 icon = mIconUnselected;
Dees_Troyeead9852013-02-15 14:31:06 -0600446 currentIconHeight = mSelectedIconHeight;
447 currentIconWidth = mSelectedIconWidth;
448 currentIconOffsetY = SelectedIconOffsetY;
449 currentIconOffsetX = SelectedIconOffsetX;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200450 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400451
Dees_Troyeead9852013-02-15 14:31:06 -0600452 if (icon && icon->GetResource())
453 {
454 int rect_y = 0, image_y = (yPos + currentIconOffsetY);
455 if (image_y + currentIconHeight > mRenderY + mRenderH)
456 rect_y = mRenderY + mRenderH - image_y;
457 else
458 rect_y = currentIconHeight;
459 gr_blit(icon->GetResource(), 0, 0, currentIconWidth, rect_y, mRenderX + currentIconOffsetX, image_y);
460 }
Dees_Troy58f5cf02013-02-27 22:21:41 +0000461 gr_textExWH(mRenderX + mIconWidth + 5, yPos + fontOffsetY, label.c_str(), fontResource, mRenderX + listW, mRenderY + mRenderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400462
Dees_Troyeead9852013-02-15 14:31:06 -0600463 // Add the separator
464 if (yPos + actualLineHeight < mRenderH + mRenderY) {
465 gr_color(mSeparatorColor.red, mSeparatorColor.green, mSeparatorColor.blue, 255);
Dees_Troy58f5cf02013-02-27 22:21:41 +0000466 gr_fill(mRenderX, yPos + actualLineHeight - mSeparatorH, listW, mSeparatorH);
Dees_Troyeead9852013-02-15 14:31:06 -0600467 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400468
Dees_Troyeead9852013-02-15 14:31:06 -0600469 // Move the yPos
470 yPos += actualLineHeight;
471 }
472
473 // Render the Header (last so that it overwrites the top most row for per pixel scrolling)
474 // First step, fill background
475 gr_color(mHeaderBackgroundColor.red, mHeaderBackgroundColor.green, mHeaderBackgroundColor.blue, 255);
476 gr_fill(mRenderX, mRenderY, mRenderW, mHeaderH);
477
478 // Now, we need the header (icon + text)
479 yPos = mRenderY;
480 {
481 Resource* headerIcon;
482 int mIconOffsetX = 0;
483
484 // render the icon if it exists
485 headerIcon = mHeaderIcon;
486 if (headerIcon && headerIcon->GetResource())
487 {
488 gr_blit(headerIcon->GetResource(), 0, 0, mHeaderIconWidth, mHeaderIconHeight, mRenderX + ((mHeaderIconWidth - mIconWidth) / 2), (yPos + (int)((mHeaderH - mHeaderIconHeight) / 2)));
489 mIconOffsetX = mIconWidth;
490 }
491
492 // render the text
493 gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, 255);
494 gr_textExWH(mRenderX + mIconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastValue.c_str(), fontResource, mRenderX + mRenderW, mRenderY + mRenderH);
495
496 // Add the separator
497 gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, 255);
498 gr_fill(mRenderX, yPos + mHeaderH - mHeaderSeparatorH, mRenderW, mHeaderSeparatorH);
499 }
500
Dees_Troy58f5cf02013-02-27 22:21:41 +0000501 // render fast scroll
502 lines = (mRenderH - mHeaderH) / (actualLineHeight);
503 if(mFastScrollW > 0 && listSize > lines)
504 {
505 int startX = listW + mRenderX;
506 int fWidth = mRenderW - listW;
507 int fHeight = mRenderH - mHeaderH;
508
509 // line
510 gr_color(mFastScrollLineColor.red, mFastScrollLineColor.green, mFastScrollLineColor.blue, 255);
511 gr_fill(startX + fWidth/2, mRenderY + mHeaderH, mFastScrollLineW, mRenderH - mHeaderH);
512
513 // rect
514 int pct = ((mStart*actualLineHeight - scrollingY)*100)/((listSize)*actualLineHeight-lines*actualLineHeight);
515 mFastScrollRectX = startX + (fWidth - mFastScrollRectW)/2;
516 mFastScrollRectY = mRenderY+mHeaderH + ((fHeight - mFastScrollRectH)*pct)/100;
517
518 gr_color(mFastScrollRectColor.red, mFastScrollRectColor.green, mFastScrollRectColor.blue, 255);
519 gr_fill(mFastScrollRectX, mFastScrollRectY, mFastScrollRectW, mFastScrollRectH);
520 }
521
Dees_Troyeead9852013-02-15 14:31:06 -0600522 mUpdate = 0;
523 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400524}
525
526int GUIListBox::Update(void)
527{
Vojtech Bocekede51c52014-02-07 23:58:09 +0100528 if(!isConditionTrue())
529 return 0;
530
Dees_Troyeead9852013-02-15 14:31:06 -0600531 if (!mHeaderIsStatic) {
532 std::string newValue = gui_parse_text(mHeaderText);
533 if (mLastValue != newValue) {
534 mLastValue = newValue;
535 mUpdate = 1;
536 }
537 }
538
539 if (mUpdate)
540 {
541 mUpdate = 0;
542 if (Render() == 0)
Dees_Troy51a0e822012-09-05 15:24:24 -0400543 return 2;
Dees_Troyeead9852013-02-15 14:31:06 -0600544 }
545
546 // Handle kinetic scrolling
547 if (scrollingSpeed == 0) {
548 // Do nothing
549 } else if (scrollingSpeed > 0) {
550 if (scrollingSpeed < ((int) (actualLineHeight * 2.5))) {
551 scrollingY += scrollingSpeed;
552 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
553 } else {
554 scrollingY += ((int) (actualLineHeight * 2.5));
555 scrollingSpeed -= SCROLLING_SPEED_DECREMENT;
556 }
557 while (mStart && scrollingY > 0) {
558 mStart--;
559 scrollingY -= actualLineHeight;
560 }
561 if (mStart == 0 && scrollingY > 0) {
562 scrollingY = 0;
563 scrollingSpeed = 0;
564 } else if (scrollingSpeed < SCROLLING_FLOOR)
565 scrollingSpeed = 0;
566 mUpdate = 1;
567 } else if (scrollingSpeed < 0) {
568 int totalSize = mList.size();
569 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
570
571 if (totalSize > lines) {
572 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
573
574 bottom_offset -= actualLineHeight;
575
576 if (abs(scrollingSpeed) < ((int) (actualLineHeight * 2.5))) {
577 scrollingY += scrollingSpeed;
578 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
579 } else {
580 scrollingY -= ((int) (actualLineHeight * 2.5));
581 scrollingSpeed += SCROLLING_SPEED_DECREMENT;
582 }
583 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
584 mStart++;
585 scrollingY += actualLineHeight;
586 }
587 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
588 mStart = totalSize - lines - 1;
589 scrollingY = bottom_offset;
590 } else if (mStart + lines >= totalSize && scrollingY < 0) {
591 mStart = totalSize - lines;
592 scrollingY = 0;
593 } else if (scrollingSpeed * -1 < SCROLLING_FLOOR)
594 scrollingSpeed = 0;
595 mUpdate = 1;
596 }
597 }
598
599 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400600}
601
602int GUIListBox::GetSelection(int x, int y)
603{
Dees_Troyeead9852013-02-15 14:31:06 -0600604 // We only care about y position
605 if (y < mRenderY || y - mRenderY <= mHeaderH || y - mRenderY > mRenderH) return -1;
606 return (y - mRenderY - mHeaderH);
Dees_Troy51a0e822012-09-05 15:24:24 -0400607}
608
609int GUIListBox::NotifyTouch(TOUCH_STATE state, int x, int y)
610{
Vojtech Bocekede51c52014-02-07 23:58:09 +0100611 if(!isConditionTrue())
612 return -1;
613
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100614 static int lastY = 0, last2Y = 0, fastScroll = 0;
Dees_Troyeead9852013-02-15 14:31:06 -0600615 int selection = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400616
Dees_Troyeead9852013-02-15 14:31:06 -0600617 switch (state)
618 {
619 case TOUCH_START:
620 if (scrollingSpeed != 0)
621 startSelection = -1;
622 else
623 startSelection = GetSelection(x,y);
624 isHighlighted = (startSelection > -1);
625 if (isHighlighted)
626 mUpdate = 1;
627 startY = lastY = last2Y = y;
628 scrollingSpeed = 0;
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100629
630 if(mFastScrollRectX != -1 && x >= mRenderX + mRenderW - mFastScrollW)
631 fastScroll = 1;
Dees_Troyeead9852013-02-15 14:31:06 -0600632 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400633
Dees_Troyeead9852013-02-15 14:31:06 -0600634 case TOUCH_DRAG:
635 // Check if we dragged out of the selection window
636 if (GetSelection(x, y) == -1) {
637 last2Y = lastY = 0;
638 if (isHighlighted) {
639 isHighlighted = false;
640 mUpdate = 1;
641 }
642 break;
643 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400644
Dees_Troy58f5cf02013-02-27 22:21:41 +0000645 // Fast scroll
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100646 if(fastScroll)
Dees_Troy58f5cf02013-02-27 22:21:41 +0000647 {
648 int pct = ((y-mRenderY-mHeaderH)*100)/(mRenderH-mHeaderH);
649 int totalSize = mList.size();
650 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
651
652 float l = float((totalSize-lines)*pct)/100;
653 if(l + lines >= totalSize)
654 {
655 mStart = totalSize - lines;
656 scrollingY = 0;
657 }
658 else
659 {
660 mStart = l;
661 scrollingY = -(l - int(l))*actualLineHeight;
662 }
663
664 startSelection = -1;
665 mUpdate = 1;
666 scrollingSpeed = 0;
667 isHighlighted = false;
668 break;
669 }
670
Dees_Troyeead9852013-02-15 14:31:06 -0600671 // Provide some debounce on initial touches
672 if (startSelection != -1 && abs(y - startY) < touchDebounce) {
673 isHighlighted = true;
674 mUpdate = 1;
675 break;
676 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400677
Dees_Troyeead9852013-02-15 14:31:06 -0600678 isHighlighted = false;
679 last2Y = lastY;
680 lastY = y;
681 startSelection = -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400682
Dees_Troyeead9852013-02-15 14:31:06 -0600683 // Handle scrolling
684 scrollingY += y - startY;
685 startY = y;
686 while(mStart && scrollingY > 0) {
687 mStart--;
688 scrollingY -= actualLineHeight;
689 }
690 if (mStart == 0 && scrollingY > 0)
691 scrollingY = 0;
692 {
693 int totalSize = mList.size();
694 int lines = (mRenderH - mHeaderH) / (actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400695
Dees_Troyeead9852013-02-15 14:31:06 -0600696 if (totalSize > lines) {
697 int bottom_offset = ((int)(mRenderH) - mHeaderH) - (lines * actualLineHeight);
Dees_Troy51a0e822012-09-05 15:24:24 -0400698
Dees_Troyeead9852013-02-15 14:31:06 -0600699 bottom_offset -= actualLineHeight;
Dees_Troy51a0e822012-09-05 15:24:24 -0400700
Dees_Troyeead9852013-02-15 14:31:06 -0600701 while (mStart + lines + (bottom_offset ? 1 : 0) < totalSize && abs(scrollingY) > actualLineHeight) {
702 mStart++;
703 scrollingY += actualLineHeight;
704 }
705 if (bottom_offset != 0 && mStart + lines + 1 >= totalSize && scrollingY <= bottom_offset) {
706 mStart = totalSize - lines - 1;
707 scrollingY = bottom_offset;
708 } else if (mStart + lines >= totalSize && scrollingY < 0) {
709 mStart = totalSize - lines;
710 scrollingY = 0;
711 }
712 } else
713 scrollingY = 0;
714 }
715 mUpdate = 1;
716 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400717
Dees_Troyeead9852013-02-15 14:31:06 -0600718 case TOUCH_RELEASE:
719 isHighlighted = false;
Vojtech Bocek59e51a42014-01-29 19:11:15 +0100720 fastScroll = 0;
Dees_Troyeead9852013-02-15 14:31:06 -0600721 if (startSelection >= 0)
722 {
723 // We've selected an item!
724 std::string str;
725
726 int listSize = mList.size();
727 int selectY = scrollingY, actualSelection = mStart;
728
729 // Move the selection to the proper place in the array
730 while (selectY + actualLineHeight < startSelection) {
731 selectY += actualLineHeight;
732 actualSelection++;
733 }
734
735 if (actualSelection < listSize && !mVariable.empty())
736 {
737 int i;
738 for (i=0; i<listSize; i++)
739 mList.at(i).selected = 0;
740
741 str = mList.at(actualSelection).variableValue;
742 mList.at(actualSelection).selected = 1;
743 DataManager::SetValue(mVariable, str);
744 mUpdate = 1;
Vojtech Bocek5af8f3f2014-02-08 02:21:23 +0100745
746 DataManager::Vibrate("tw_button_vibrate");
Dees_Troyeead9852013-02-15 14:31:06 -0600747 }
748 } else {
749 // This is for kinetic scrolling
750 scrollingSpeed = lastY - last2Y;
751 if (abs(scrollingSpeed) > SCROLLING_FLOOR)
752 scrollingSpeed *= SCROLLING_MULTIPLIER;
753 else
754 scrollingSpeed = 0;
755 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400756 case TOUCH_REPEAT:
Dees_Troyeead9852013-02-15 14:31:06 -0600757 case TOUCH_HOLD:
758 break;
759 }
760 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400761}
762
Vojtech Bocek07220562014-02-08 02:05:33 +0100763int GUIListBox::NotifyVarChange(const std::string& varName, const std::string& value)
Dees_Troy51a0e822012-09-05 15:24:24 -0400764{
Vojtech Bocek07220562014-02-08 02:05:33 +0100765 GUIObject::NotifyVarChange(varName, value);
766
Vojtech Bocekede51c52014-02-07 23:58:09 +0100767 if(!isConditionTrue())
768 return 0;
769
Dees_Troyeead9852013-02-15 14:31:06 -0600770 if (!mHeaderIsStatic) {
771 std::string newValue = gui_parse_text(mHeaderText);
772 if (mLastValue != newValue) {
773 mLastValue = newValue;
774 mStart = 0;
775 scrollingY = 0;
776 scrollingSpeed = 0;
777 mUpdate = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400778 }
Dees_Troyeead9852013-02-15 14:31:06 -0600779 }
780 if (varName == mVariable)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200781 {
782 int i, listSize = mList.size(), selected_index = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400783
784 currentValue = value;
785
786 for (i=0; i<listSize; i++) {
787 if (mList.at(i).variableValue == currentValue) {
788 mList.at(i).selected = 1;
789 selected_index = i;
790 } else
791 mList.at(i).selected = 0;
792 }
793
794 int lines = mRenderH / (mLineHeight + mLineSpacing);
795 int line;
796
797 if (selected_index > mStart + lines - 1)
798 mStart = selected_index;
799 if (mStart > listSize - lines) {
800 mStart = listSize - lines;
801 } else if (selected_index < mStart) {
802 mStart = selected_index;
803 }
804
805 mUpdate = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200806 return 0;
807 }
Dees_Troyeead9852013-02-15 14:31:06 -0600808 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400809}
810
811int GUIListBox::SetRenderPos(int x, int y, int w /* = 0 */, int h /* = 0 */)
812{
Dees_Troyeead9852013-02-15 14:31:06 -0600813 mRenderX = x;
814 mRenderY = y;
815 if (w || h)
816 {
817 mRenderW = w;
818 mRenderH = h;
819 }
820 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
821 mUpdate = 1;
822 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400823}
824
825void GUIListBox::SetPageFocus(int inFocus)
826{
Dees_Troyeead9852013-02-15 14:31:06 -0600827 if (inFocus)
828 {
829 DataManager::GetValue(mVariable, currentValue);
830 NotifyVarChange(mVariable, currentValue);
831 mUpdate = 1;
832 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400833}