blob: 7107c924ce029b3272101eeac053dd5bd460c7af [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 Troy3be70a82013-10-22 14:25:12 +000018
Dees_Troya13d74f2013-03-24 08:54:55 -050019// pages.cpp - Source to manage GUI base objects
Dees_Troy51a0e822012-09-05 15:24:24 -040020
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>
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060035#include "../twrp-functions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040036
37#include <string>
38
39extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000040#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040041#include "../minuitwrp/minui.h"
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060042#include "../minzip/SysUtil.h"
43#include "../minzip/Zip.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060044#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040045}
46
47#include "rapidxml.hpp"
48#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020049#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040050
51extern int gGuiRunning;
52
53std::map<std::string, PageSet*> PageManager::mPageSets;
54PageSet* PageManager::mCurrentSet;
55PageSet* PageManager::mBaseSet = NULL;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010056MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010057HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040058
Ethan Yonker751a85e2014-12-12 16:59:10 -060059int tw_x_offset = 0;
60int tw_y_offset = 0;
61
Dees_Troy51a0e822012-09-05 15:24:24 -040062// Helper routine to convert a string to a color declaration
63int ConvertStrToColor(std::string str, COLOR* color)
64{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020065 // Set the default, solid black
66 memset(color, 0, sizeof(COLOR));
67 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040068
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020069 // Translate variables
70 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050071
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020072 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010073 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020074 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
75 else if (str == "red") { color->red = 255; return 0; }
76 else if (str == "green") { color->green = 255; return 0; }
77 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040078
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020079 // At this point, we require an RGB(A) color
80 if (str[0] != '#')
81 return -1;
82
83 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040084
Dees_Troy30b962e2012-10-19 20:48:59 -040085 int result;
86 if (str.size() >= 8) {
87 // We have alpha channel
88 string alpha = str.substr(6, 2);
89 result = strtol(alpha.c_str(), NULL, 16);
90 color->alpha = result & 0x000000FF;
91 str.resize(6);
92 result = strtol(str.c_str(), NULL, 16);
93 color->red = (result >> 16) & 0x000000FF;
94 color->green = (result >> 8) & 0x000000FF;
95 color->blue = result & 0x000000FF;
96 } else {
97 result = strtol(str.c_str(), NULL, 16);
98 color->red = (result >> 16) & 0x000000FF;
99 color->green = (result >> 8) & 0x000000FF;
100 color->blue = result & 0x000000FF;
101 }
102 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400103}
104
105// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600106xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
107{
that8d46c092015-02-26 01:30:04 +0100108 if (!parent)
109 return NULL;
110
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600111 xml_node<>* child = parent->first_node(nodename);
112 if (child)
113 return child;
114
115 if (depth == 10) {
116 LOGERR("Too many style loops detected.\n");
117 return NULL;
118 }
119
120 xml_node<>* style = parent->first_node("style");
121 if (style) {
122 while (style) {
123 if (!style->first_attribute("name")) {
124 LOGERR("No name given for style.\n");
125 continue;
126 } else {
127 std::string name = style->first_attribute("name")->value();
128 xml_node<>* node = PageManager::FindStyle(name);
129
130 if (node) {
131 // We found the style that was named
132 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
133 if (stylenode)
134 return stylenode;
135 }
136 }
137 style = style->next_sibling("style");
138 }
139 } else {
140 // Search for stylename in the parent node <object type="foo" stylename="foo2">
141 xml_attribute<>* attr = parent->first_attribute("style");
142 // If no style is found anywhere else and the node wasn't found in the object itself
143 // as a special case we will search for a style that uses the same style name as the
144 // object type, so <object type="button"> would search for a style named "button"
145 if (!attr)
146 attr = parent->first_attribute("type");
147 if (attr) {
148 xml_node<>* node = PageManager::FindStyle(attr->value());
149 if (node) {
150 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
151 if (stylenode)
152 return stylenode;
153 }
154 }
155 }
156 return NULL;
157}
158
thatf6ed8fc2015-02-14 20:23:16 +0100159std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
160{
161 if (!element)
162 return defaultvalue;
163
164 xml_attribute<>* attr = element->first_attribute(attrname);
165 return attr ? attr->value() : defaultvalue;
166}
167
168int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
169{
170 string value = LoadAttrString(element, attrname);
171 // resolve variables
172 DataManager::GetValue(value, value);
173 return value.empty() ? defaultvalue : atoi(value.c_str());
174}
175
176int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
177{
178 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
179}
180
181int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
182{
183 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
184}
185
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600186COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100187{
188 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600189 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100190 // resolve variables
191 DataManager::GetValue(value, value);
192 COLOR ret = defaultvalue;
193 if (ConvertStrToColor(value, &ret) == 0)
194 return ret;
195 else
196 return defaultvalue;
197}
198
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600199COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
200{
201 bool found_color = false;
202 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
203}
204
thatf6ed8fc2015-02-14 20:23:16 +0100205FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
206{
207 std::string name = LoadAttrString(element, attrname, "");
208 if (name.empty())
209 return NULL;
210 else
that74ac6062015-03-04 22:39:34 +0100211 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100212}
213
214ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
215{
216 std::string name = LoadAttrString(element, attrname, "");
217 if (name.empty())
218 return NULL;
219 else
that74ac6062015-03-04 22:39:34 +0100220 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100221}
222
223AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
224{
225 std::string name = LoadAttrString(element, attrname, "");
226 if (name.empty())
227 return NULL;
228 else
that74ac6062015-03-04 22:39:34 +0100229 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100230}
231
Dees_Troy51a0e822012-09-05 15:24:24 -0400232bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
233{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200234 if (!node)
235 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400236
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200237 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100238 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400239
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100241 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400242
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200243 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100244 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400245
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200246 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100247 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400248
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200249 if (placement && node->first_attribute("placement"))
thatf6ed8fc2015-02-14 20:23:16 +0100250 *placement = (RenderObject::Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400251
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400253}
254
255int ActionObject::SetActionPos(int x, int y, int w, int h)
256{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 if (x < 0 || y < 0)
258 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400259
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500260 mActionX = x;
261 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200262 if (w || h)
263 {
264 mActionW = w;
265 mActionH = h;
266 }
267 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400268}
269
Ethan Yonker780cd392014-07-21 15:24:39 -0500270Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400271{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200272 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400273
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200274 // We can memset the whole structure, because the alpha channel is ignored
275 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400276
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200277 // With NULL, we make a console-only display
278 if (!page)
279 {
280 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400281
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200282 GUIConsole* element = new GUIConsole(NULL);
283 mRenders.push_back(element);
284 mActions.push_back(element);
285 return;
286 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400287
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200288 if (page->first_attribute("name"))
289 mName = page->first_attribute("name")->value();
290 else
291 {
292 LOGERR("No page name attribute found!\n");
293 return;
294 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400295
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200296 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400297
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200298 // This is a recursive routine for template handling
299 ProcessNode(page, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400300
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200301 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400302}
303
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100304Page::~Page()
305{
306 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
307 delete *itr;
308}
309
Ethan Yonker780cd392014-07-21 15:24:39 -0500310bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */, int depth /* = 0 */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400311{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200312 if (depth == 10)
313 {
314 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
315 return false;
316 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400317
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200318 // Let's retrieve the background value, if any
319 xml_node<>* bg = page->first_node("background");
320 if (bg)
321 {
322 xml_attribute<>* attr = bg->first_attribute("color");
323 if (attr)
324 {
325 std::string color = attr->value();
326 ConvertStrToColor(color, &mBackground);
327 }
328 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400329
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200330 xml_node<>* child;
331 child = page->first_node("object");
332 while (child)
333 {
334 if (!child->first_attribute("type"))
335 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400336
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200337 std::string type = child->first_attribute("type")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400338
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200339 if (type == "text")
340 {
341 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100342 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200343 mRenders.push_back(element);
344 mActions.push_back(element);
345 }
346 else if (type == "image")
347 {
348 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100349 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200350 mRenders.push_back(element);
351 }
352 else if (type == "fill")
353 {
354 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100355 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200356 mRenders.push_back(element);
357 }
358 else if (type == "action")
359 {
360 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100361 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200362 mActions.push_back(element);
363 }
364 else if (type == "console")
365 {
366 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100367 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200368 mRenders.push_back(element);
369 mActions.push_back(element);
370 }
371 else if (type == "button")
372 {
373 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100374 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200375 mRenders.push_back(element);
376 mActions.push_back(element);
377 }
378 else if (type == "checkbox")
379 {
380 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100381 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200382 mRenders.push_back(element);
383 mActions.push_back(element);
384 }
385 else if (type == "fileselector")
386 {
387 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100388 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200389 mRenders.push_back(element);
390 mActions.push_back(element);
391 }
392 else if (type == "animation")
393 {
394 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100395 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200396 mRenders.push_back(element);
397 }
398 else if (type == "progressbar")
399 {
400 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100401 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200402 mRenders.push_back(element);
403 mActions.push_back(element);
404 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400405 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200406 {
407 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100408 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200409 mRenders.push_back(element);
410 mActions.push_back(element);
411 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200412 else if (type == "slidervalue")
413 {
414 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100415 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200416 mRenders.push_back(element);
417 mActions.push_back(element);
418 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400419 else if (type == "listbox")
420 {
421 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100422 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400423 mRenders.push_back(element);
424 mActions.push_back(element);
425 }
426 else if (type == "keyboard")
427 {
428 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100429 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400430 mRenders.push_back(element);
431 mActions.push_back(element);
432 }
433 else if (type == "input")
434 {
435 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100436 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400437 mRenders.push_back(element);
438 mActions.push_back(element);
439 mInputs.push_back(element);
440 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500441 else if (type == "partitionlist")
442 {
443 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100444 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500445 mRenders.push_back(element);
446 mActions.push_back(element);
447 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100448 else if (type == "patternpassword")
449 {
450 GUIPatternPassword* element = new GUIPatternPassword(child);
451 mObjects.push_back(element);
452 mRenders.push_back(element);
453 mActions.push_back(element);
454 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200455 else if (type == "template")
456 {
457 if (!templates || !child->first_attribute("name"))
458 {
459 LOGERR("Invalid template request.\n");
460 }
461 else
462 {
463 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500464 xml_node<>* node;
465 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400466
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200467 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500468 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
469 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400470
Ethan Yonker780cd392014-07-21 15:24:39 -0500471 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200472 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500473 if (!node->first_attribute("name"))
474 continue;
475
476 if (name == node->first_attribute("name")->value())
477 {
478 if (!ProcessNode(node, templates, depth + 1))
479 return false;
480 else {
481 node_found = true;
482 break;
483 }
484 }
485 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200486 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500487 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200488 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200489 }
490 }
491 }
492 else
493 {
494 LOGERR("Unknown object type.\n");
495 }
496 child = child->next_sibling("object");
497 }
498 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400499}
500
501int Page::Render(void)
502{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200503 // Render background
504 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
505 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400506
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200507 // Render remaining objects
508 std::vector<RenderObject*>::iterator iter;
509 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
510 {
511 if ((*iter)->Render())
512 LOGERR("A render request has failed.\n");
513 }
514 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400515}
516
517int Page::Update(void)
518{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200519 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400520
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200521 std::vector<RenderObject*>::iterator iter;
522 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
523 {
524 int ret = (*iter)->Update();
525 if (ret < 0)
526 LOGERR("An update request has failed.\n");
527 else if (ret > retCode)
528 retCode = ret;
529 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400530
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200531 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400532}
533
534int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
535{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200536 // By default, return 1 to ignore further touches if nobody is listening
537 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400538
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200539 // Don't try to handle a lack of handlers
540 if (mActions.size() == 0)
541 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400542
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200543 // We record mTouchStart so we can pass all the touch stream to the same handler
544 if (state == TOUCH_START)
545 {
546 std::vector<ActionObject*>::reverse_iterator iter;
547 // We work backwards, from top-most element to bottom-most element
548 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
549 {
550 if ((*iter)->IsInRegion(x, y))
551 {
552 mTouchStart = (*iter);
553 ret = mTouchStart->NotifyTouch(state, x, y);
554 if (ret >= 0)
555 break;
556 mTouchStart = NULL;
557 }
558 }
559 }
560 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
561 {
562 ret = mTouchStart->NotifyTouch(state, x, y);
563 mTouchStart = NULL;
564 }
565 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
566 {
567 ret = mTouchStart->NotifyTouch(state, x, y);
568 }
569 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400570}
571
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100572int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400573{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200574 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400575
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200576 // Don't try to handle a lack of handlers
577 if (mActions.size() == 0)
578 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400579
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100580 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200581 // We work backwards, from top-most element to bottom-most element
582 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
583 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100584 ret = (*iter)->NotifyKey(key, down);
585 if (ret < 0) {
586 LOGERR("An action handler has returned an error\n");
587 ret = 1;
588 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200589 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100590 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400591}
592
593int Page::NotifyKeyboard(int key)
594{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200595 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400596
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200597 // Don't try to handle a lack of handlers
598 if (mInputs.size() == 0)
599 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400600
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200601 // We work backwards, from top-most element to bottom-most element
602 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
603 {
604 int ret = (*iter)->NotifyKeyboard(key);
605 if (ret == 0)
606 return 0;
607 else if (ret < 0)
608 LOGERR("A keyboard handler has returned an error");
609 }
610 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400611}
612
613int Page::SetKeyBoardFocus(int inFocus)
614{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400616
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200617 // Don't try to handle a lack of handlers
618 if (mInputs.size() == 0)
619 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400620
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200621 // We work backwards, from top-most element to bottom-most element
622 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
623 {
624 int ret = (*iter)->SetInputFocus(inFocus);
625 if (ret == 0)
626 return 0;
627 else if (ret < 0)
628 LOGERR("An input focus handler has returned an error");
629 }
630 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400631}
632
633void Page::SetPageFocus(int inFocus)
634{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200635 // Render remaining objects
636 std::vector<RenderObject*>::iterator iter;
637 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
638 (*iter)->SetPageFocus(inFocus);
639
640 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400641}
642
643int Page::NotifyVarChange(std::string varName, std::string value)
644{
Vojtech Bocek07220562014-02-08 02:05:33 +0100645 std::vector<GUIObject*>::iterator iter;
646 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200647 {
648 if ((*iter)->NotifyVarChange(varName, value))
649 LOGERR("An action handler errored on NotifyVarChange.\n");
650 }
651 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400652}
653
654PageSet::PageSet(char* xmlFile)
655{
that74ac6062015-03-04 22:39:34 +0100656 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200657 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400658
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200659 mXmlFile = xmlFile;
660 if (xmlFile)
661 mDoc.parse<0>(mXmlFile);
662 else
663 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400664}
665
666PageSet::~PageSet()
667{
Ethan Yonker1c273312015-03-16 12:18:56 -0500668 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100669 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
670 delete *itr;
671
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200672 delete mResources;
673 free(mXmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100674
675 mDoc.clear();
676
677 for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
678 (*itr)->clear();
679 delete *itr;
680 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400681}
682
683int PageSet::Load(ZipArchive* package)
684{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200685 xml_node<>* parent;
686 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500687 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600688 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500689
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200690 parent = mDoc.first_node("recovery");
691 if (!parent)
692 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400693
Ethan Yonker63e414f2015-02-06 15:44:39 -0600694 set_scale_values(1, 1); // Reset any previous scaling values
695
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200696 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600697 LOGINFO("Checking resolution...\n");
698 child = parent->first_node("details");
699 if (child) {
700 xml_node<>* resolution = child->first_node("resolution");
701 if (resolution) {
702 xml_attribute<>* width_attr = resolution->first_attribute("width");
703 xml_attribute<>* height_attr = resolution->first_attribute("height");
704 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
705 if (width_attr && height_attr && !noscale_attr) {
706 int width = atoi(width_attr->value());
707 int height = atoi(height_attr->value());
708 int offx = 0, offy = 0;
709#ifdef TW_ROUND_SCREEN
710 xml_node<>* roundscreen = child->first_node("roundscreen");
711 if (roundscreen) {
712 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
713 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
714 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
715 if (offx_attr) {
716 offx = atoi(offx_attr->value());
717 }
718 if (offy_attr) {
719 offy = atoi(offy_attr->value());
720 }
721 }
722#endif
723 if (width != 0 && height != 0) {
724 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
725 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
726#ifdef TW_ROUND_SCREEN
727 float scale_off_w = (float)gr_fb_width() / (float)width;
728 float scale_off_h = (float)gr_fb_height() / (float)height;
729 tw_x_offset = offx * scale_off_w;
730 tw_y_offset = offy * scale_off_h;
731#endif
732 if (scale_w != 1 || scale_h != 1) {
733 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
734 set_scale_values(scale_w, scale_h);
735 }
736 }
737 } else {
738 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
739 }
740 } else {
741 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
742 }
743 } else {
744 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
745 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200746 LOGINFO("Loading resources...\n");
747 child = parent->first_node("resources");
748 if (child)
that74ac6062015-03-04 22:39:34 +0100749 mResources->LoadResources(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400750
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200751 LOGINFO("Loading variables...\n");
752 child = parent->first_node("variables");
753 if (child)
754 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400755
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100756 LOGINFO("Loading mouse cursor...\n");
757 child = parent->first_node("mousecursor");
758 if(child)
759 PageManager::LoadCursorData(child);
760
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200761 LOGINFO("Loading pages...\n");
762 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500763 xmltemplate = parent->first_node("templates");
764 if (xmltemplate)
765 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400766
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600767 // Load styles if present
768 xmlstyle = parent->first_node("styles");
769 if (xmlstyle)
770 styles.push_back(xmlstyle);
771
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200772 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500773 if (child) {
774 if (LoadPages(child)) {
775 LOGERR("PageSet::Load returning -1\n");
776 return -1;
777 }
778 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100779
Ethan Yonker780cd392014-07-21 15:24:39 -0500780 return CheckInclude(package, &mDoc);
781}
Dees_Troy51a0e822012-09-05 15:24:24 -0400782
Ethan Yonker780cd392014-07-21 15:24:39 -0500783int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
784{
785 xml_node<>* par;
786 xml_node<>* par2;
787 xml_node<>* chld;
788 xml_node<>* parent;
789 xml_node<>* child;
790 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600791 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500792 long len;
793 char* xmlFile = NULL;
794 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100795 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500796
797 par = parentDoc->first_node("recovery");
798 if (!par) {
799 par = parentDoc->first_node("install");
800 }
801 if (!par) {
802 return 0;
803 }
804
805 par2 = par->first_node("include");
806 if (!par2)
807 return 0;
808 chld = par2->first_node("xmlfile");
809 while (chld != NULL) {
810 xml_attribute<>* attr = chld->first_attribute("name");
811 if (!attr)
812 break;
813
Ethan Yonker780cd392014-07-21 15:24:39 -0500814 if (!package) {
815 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000816 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500817 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000818 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500819 struct stat st;
820 if(stat(filename.c_str(),&st) != 0) {
821 LOGERR("Unable to locate '%s'\n", filename.c_str());
822 return -1;
823 }
824
825 len = st.st_size;
826 xmlFile = (char*) malloc(len + 1);
827 if (!xmlFile)
828 return -1;
829
830 int fd = open(filename.c_str(), O_RDONLY);
831 if (fd == -1)
832 return -1;
833
834 read(fd, xmlFile, len);
835 close(fd);
836 } else {
837 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000838 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500839 const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
840 if (ui_xml == NULL)
841 {
842 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
843 return -1;
844 }
845
846 // Allocate the buffer for the file
847 len = mzGetZipEntryUncompLen(ui_xml);
848 xmlFile = (char*) malloc(len + 1);
849 if (!xmlFile)
850 return -1;
851
852 if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
853 {
854 LOGERR("Unable to extract '%s'\n", filename.c_str());
855 return -1;
856 }
857 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500858
Vojtech Boceke979abd2015-01-12 18:29:12 +0100859 xmlFile[len] = '\0';
860 doc = new xml_document<>();
861 doc->parse<0>(xmlFile);
862
863 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500864 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100865 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500866
867 // Now, let's parse the XML
868 LOGINFO("Loading included resources...\n");
869 child = parent->first_node("resources");
870 if (child)
871 mResources->LoadResources(child, package);
872
873 LOGINFO("Loading included variables...\n");
874 child = parent->first_node("variables");
875 if (child)
876 LoadVariables(child);
877
878 LOGINFO("Loading mouse cursor...\n");
879 child = parent->first_node("mousecursor");
880 if(child)
881 PageManager::LoadCursorData(child);
882
883 LOGINFO("Loading included pages...\n");
884 // This may be NULL if no templates are present
885 xmltemplate = parent->first_node("templates");
886 if (xmltemplate)
887 templates.push_back(xmltemplate);
888
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600889 // Load styles if present
890 xmlstyle = parent->first_node("styles");
891 if (xmlstyle)
892 styles.push_back(xmlstyle);
893
Ethan Yonker780cd392014-07-21 15:24:39 -0500894 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100895 if (child && LoadPages(child))
896 {
897 templates.pop_back();
898 doc->clear();
899 delete doc;
900 return -1;
901 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500902
Vojtech Boceke979abd2015-01-12 18:29:12 +0100903 mIncludedDocs.push_back(doc);
904
905 if (CheckInclude(package, doc))
Ethan Yonker780cd392014-07-21 15:24:39 -0500906 return -1;
907
908 chld = chld->next_sibling("xmlfile");
909 }
910
911 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400912}
913
914int PageSet::SetPage(std::string page)
915{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200916 Page* tmp = FindPage(page);
917 if (tmp)
918 {
919 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
920 mCurrentPage = tmp;
921 mCurrentPage->SetPageFocus(1);
922 mCurrentPage->NotifyVarChange("", "");
923 return 0;
924 }
925 else
926 {
927 LOGERR("Unable to locate page (%s)\n", page.c_str());
928 }
929 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400930}
931
932int PageSet::SetOverlay(Page* page)
933{
Ethan Yonker1c273312015-03-16 12:18:56 -0500934 if (page) {
935 if (mOverlays.size() >= 10) {
936 LOGERR("Too many overlays requested, max is 10.\n");
937 return -1;
938 }
939 page->SetPageFocus(1);
940 page->NotifyVarChange("", "");
941
942 if (!mOverlays.empty())
943 mOverlays.back()->SetPageFocus(0);
944
945 mOverlays.push_back(page);
946 } else {
947 if (!mOverlays.empty()) {
948 mOverlays.back()->SetPageFocus(0);
949 mOverlays.pop_back();
950 if (!mOverlays.empty())
951 mOverlays.back()->SetPageFocus(1);
952 else if (mCurrentPage)
953 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
954 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200955 }
956 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400957}
958
that74ac6062015-03-04 22:39:34 +0100959const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400960{
that74ac6062015-03-04 22:39:34 +0100961 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400962}
963
964Page* PageSet::FindPage(std::string name)
965{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200966 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400967
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200968 for (iter = mPages.begin(); iter != mPages.end(); iter++)
969 {
970 if (name == (*iter)->GetName())
971 return (*iter);
972 }
973 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400974}
975
976int PageSet::LoadVariables(xml_node<>* vars)
977{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200978 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100979 xml_attribute<> *name, *value, *persist;
980 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400981
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200982 child = vars->first_node("variable");
983 while (child)
984 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100985 name = child->first_attribute("name");
986 value = child->first_attribute("value");
987 persist = child->first_attribute("persist");
988 if(name && value)
989 {
Ethan Yonker751a85e2014-12-12 16:59:10 -0600990 if (strcmp(name->value(), "tw_x_offset") == 0) {
991 tw_x_offset = atoi(value->value());
992 child = child->next_sibling("variable");
993 continue;
994 }
995 if (strcmp(name->value(), "tw_y_offset") == 0) {
996 tw_y_offset = atoi(value->value());
997 child = child->next_sibling("variable");
998 continue;
999 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001000 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001001 string temp = value->value();
1002 string valstr = gui_parse_text(temp);
1003
1004 if (valstr.find("+") != string::npos) {
1005 string val1str = valstr;
1006 val1str = val1str.substr(0, val1str.find('+'));
1007 string val2str = valstr;
1008 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1009 int val1 = atoi(val1str.c_str());
1010 int val2 = atoi(val2str.c_str());
1011 int val = val1 + val2;
1012
1013 DataManager::SetValue(name->value(), val, p);
1014 } else if (valstr.find("-") != string::npos) {
1015 string val1str = valstr;
1016 val1str = val1str.substr(0, val1str.find('-'));
1017 string val2str = valstr;
1018 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1019 int val1 = atoi(val1str.c_str());
1020 int val2 = atoi(val2str.c_str());
1021 int val = val1 - val2;
1022
1023 DataManager::SetValue(name->value(), val, p);
1024 } else {
1025 DataManager::SetValue(name->value(), valstr, p);
1026 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001027 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001028
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001029 child = child->next_sibling("variable");
1030 }
1031 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001032}
1033
Ethan Yonker780cd392014-07-21 15:24:39 -05001034int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001035{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001036 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001037
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001038 if (!pages)
1039 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001040
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001041 child = pages->first_node("page");
1042 while (child != NULL)
1043 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001044 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001045 if (page->GetName().empty())
1046 {
1047 LOGERR("Unable to process load page\n");
1048 delete page;
1049 }
1050 else
1051 {
1052 mPages.push_back(page);
1053 }
1054 child = child->next_sibling("page");
1055 }
1056 if (mPages.size() > 0)
1057 return 0;
1058 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001059}
1060
1061int PageSet::IsCurrentPage(Page* page)
1062{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001063 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001064}
1065
1066int PageSet::Render(void)
1067{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001068 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001069
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001070 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1071 if (ret < 0)
1072 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001073
1074 std::vector<Page*>::iterator iter;
1075
1076 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1077 ret = ((*iter) ? (*iter)->Render() : -1);
1078 if (ret < 0)
1079 return ret;
1080 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001081 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001082}
1083
1084int PageSet::Update(void)
1085{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001086 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001087
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001088 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1089 if (ret < 0 || ret > 1)
1090 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001091
1092 std::vector<Page*>::iterator iter;
1093
1094 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1095 ret = ((*iter) ? (*iter)->Update() : -1);
1096 if (ret < 0)
1097 return ret;
1098 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001099 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001100}
1101
1102int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1103{
Ethan Yonker1c273312015-03-16 12:18:56 -05001104 if (!mOverlays.empty())
1105 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001106
1107 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001108}
1109
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001110int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001111{
Ethan Yonker1c273312015-03-16 12:18:56 -05001112 if (!mOverlays.empty())
1113 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001114
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001115 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001116}
1117
1118int PageSet::NotifyKeyboard(int key)
1119{
Ethan Yonker1c273312015-03-16 12:18:56 -05001120 if (!mOverlays.empty())
1121 return mOverlays.back()->NotifyKeyboard(key);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001122
1123 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001124}
1125
1126int PageSet::SetKeyBoardFocus(int inFocus)
1127{
Ethan Yonker1c273312015-03-16 12:18:56 -05001128 if (!mOverlays.empty())
1129 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001130
1131 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001132}
1133
1134int PageSet::NotifyVarChange(std::string varName, std::string value)
1135{
Ethan Yonker1c273312015-03-16 12:18:56 -05001136 std::vector<Page*>::iterator iter;
1137
1138 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1139 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001140
1141 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001142}
1143
1144int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1145{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001146 int fd;
1147 ZipArchive zip, *pZip = NULL;
1148 long len;
1149 char* xmlFile = NULL;
1150 PageSet* pageSet = NULL;
1151 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001152 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001153
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001154 // Open the XML file
1155 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001156 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001157 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001158 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001159 tw_x_offset = TW_X_OFFSET;
1160 tw_y_offset = TW_Y_OFFSET;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001161 // We can try to load the XML directly...
1162 struct stat st;
1163 if(stat(package.c_str(),&st) != 0)
1164 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001165
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001166 len = st.st_size;
1167 xmlFile = (char*) malloc(len + 1);
1168 if (!xmlFile)
1169 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001170
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001171 fd = open(package.c_str(), O_RDONLY);
1172 if (fd == -1)
1173 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -04001174
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001175 read(fd, xmlFile, len);
1176 close(fd);
1177 }
1178 else
1179 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001180 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001181 tw_x_offset = 0;
1182 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001183 if (!TWFunc::Path_Exists(package))
1184 return -1;
1185 if (sysMapFile(package.c_str(), &map) != 0) {
1186 LOGERR("Failed to map '%s'\n", package.c_str());
1187 return -1;
1188 }
1189 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1190 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1191 sysReleaseMap(&map);
1192 return -1;
1193 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001194 pZip = &zip;
1195 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
1196 if (ui_xml == NULL)
1197 {
1198 LOGERR("Unable to locate ui.xml in zip file\n");
1199 goto error;
1200 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001201
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001202 // Allocate the buffer for the file
1203 len = mzGetZipEntryUncompLen(ui_xml);
1204 xmlFile = (char*) malloc(len + 1);
1205 if (!xmlFile)
1206 goto error;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001207
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001208 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
1209 {
1210 LOGERR("Unable to extract ui.xml\n");
1211 goto error;
1212 }
1213 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001214
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001215 // NULL-terminate the string
1216 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -04001217
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001218 // Before loading, mCurrentSet must be the loading package so we can find resources
1219 pageSet = mCurrentSet;
1220 mCurrentSet = new PageSet(xmlFile);
1221
1222 ret = mCurrentSet->Load(pZip);
1223 if (ret == 0)
1224 {
1225 mCurrentSet->SetPage(startpage);
1226 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1227 }
1228 else
1229 {
1230 LOGERR("Package %s failed to load.\n", name.c_str());
1231 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001232
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001233 // The first successful package we loaded is the base
1234 if (mBaseSet == NULL)
1235 mBaseSet = mCurrentSet;
1236
1237 mCurrentSet = pageSet;
1238
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001239 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001240 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001241 sysReleaseMap(&map);
1242 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001243 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001244
1245error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001246 LOGERR("An internal error has occurred.\n");
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001247 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001248 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001249 sysReleaseMap(&map);
1250 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001251 if (xmlFile)
1252 free(xmlFile);
1253 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001254}
1255
1256PageSet* PageManager::FindPackage(std::string name)
1257{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001258 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001259
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001260 iter = mPageSets.find(name);
1261 if (iter != mPageSets.end())
1262 return (*iter).second;
1263
1264 LOGERR("Unable to locate package %s\n", name.c_str());
1265 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001266}
1267
1268PageSet* PageManager::SelectPackage(std::string name)
1269{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001270 LOGINFO("Switching packages (%s)\n", name.c_str());
1271 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001272
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001273 tmp = FindPackage(name);
1274 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001275 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001276 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001277 mCurrentSet->NotifyVarChange("", "");
1278 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001279 else
1280 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001281
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001282 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001283}
1284
1285int PageManager::ReloadPackage(std::string name, std::string package)
1286{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001287 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001288
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001289 iter = mPageSets.find(name);
1290 if (iter == mPageSets.end())
1291 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001292
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001293 if(mMouseCursor)
1294 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1295
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001296 PageSet* set = (*iter).second;
1297 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001298
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001299 if (LoadPackage(name, package, "main") != 0)
1300 {
Dees Troy3454ade2015-01-20 19:21:04 +00001301 LOGERR("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001302 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1303 return -1;
1304 }
1305 if (mCurrentSet == set)
1306 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001307 if (mBaseSet == set)
1308 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001309 delete set;
1310 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001311}
1312
1313void PageManager::ReleasePackage(std::string name)
1314{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001315 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001316
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001317 iter = mPageSets.find(name);
1318 if (iter == mPageSets.end())
1319 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001320
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001321 PageSet* set = (*iter).second;
1322 mPageSets.erase(iter);
1323 delete set;
1324 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001325}
1326
1327int PageManager::ChangePage(std::string name)
1328{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001329 DataManager::SetValue("tw_operation_state", 0);
1330 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1331 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001332}
1333
1334int PageManager::ChangeOverlay(std::string name)
1335{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001336 if (name.empty())
1337 return mCurrentSet->SetOverlay(NULL);
1338 else
1339 {
1340 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1341 return mCurrentSet->SetOverlay(page);
1342 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001343}
1344
that74ac6062015-03-04 22:39:34 +01001345const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001346{
that74ac6062015-03-04 22:39:34 +01001347 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001348}
1349
1350int PageManager::SwitchToConsole(void)
1351{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001352 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001353
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001354 mCurrentSet = console;
1355 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001356}
1357
Ethan Yonker03a42f62014-08-08 11:03:51 -05001358int PageManager::EndConsole(void)
1359{
1360 if (mCurrentSet && mBaseSet) {
1361 delete mCurrentSet;
1362 mCurrentSet = mBaseSet;
1363 return 0;
1364 }
1365 return -1;
1366}
1367
Dees_Troy51a0e822012-09-05 15:24:24 -04001368int PageManager::IsCurrentPage(Page* page)
1369{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001370 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001371}
1372
1373int PageManager::Render(void)
1374{
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001375 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1376 if(mMouseCursor)
1377 mMouseCursor->Render();
1378 return res;
1379}
1380
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001381HardwareKeyboard *PageManager::GetHardwareKeyboard()
1382{
1383 if(!mHardwareKeyboard)
1384 mHardwareKeyboard = new HardwareKeyboard();
1385 return mHardwareKeyboard;
1386}
1387
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001388xml_node<>* PageManager::FindStyle(std::string name)
1389{
1390 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1391 xml_node<>* node = (*itr)->first_node("style");
1392
1393 while (node) {
1394 if (!node->first_attribute("name"))
1395 continue;
1396
1397 if (name == node->first_attribute("name")->value())
1398 return node;
1399 node = node->next_sibling("style");
1400 }
1401 }
1402 return NULL;
1403}
1404
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001405MouseCursor *PageManager::GetMouseCursor()
1406{
1407 if(!mMouseCursor)
1408 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1409 return mMouseCursor;
1410}
1411
1412void PageManager::LoadCursorData(xml_node<>* node)
1413{
1414 if(!mMouseCursor)
1415 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1416
1417 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001418}
1419
1420int PageManager::Update(void)
1421{
thatfb759d42015-01-11 12:16:53 +01001422 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001423 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001424
1425 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1426
1427 if(mMouseCursor)
1428 {
1429 int c_res = mMouseCursor->Update();
1430 if(c_res > res)
1431 res = c_res;
1432 }
1433 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001434}
1435
1436int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1437{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001438 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001439}
1440
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001441int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001442{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001443 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001444}
1445
1446int PageManager::NotifyKeyboard(int key)
1447{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001448 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001449}
1450
1451int PageManager::SetKeyBoardFocus(int inFocus)
1452{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001453 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001454}
1455
1456int PageManager::NotifyVarChange(std::string varName, std::string value)
1457{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001458 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001459}
1460
1461extern "C" void gui_notifyVarChange(const char *name, const char* value)
1462{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001463 if (!gGuiRunning)
1464 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001465
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001466 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001467}