blob: 18ddf9c3322328c6ee0db5531aca928bb58d4cd3 [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
211 return (FontResource*) PageManager::FindResource(name);
212 // TODO: make resource lookup type-safe
213}
214
215ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
216{
217 std::string name = LoadAttrString(element, attrname, "");
218 if (name.empty())
219 return NULL;
220 else
221 return (ImageResource*) PageManager::FindResource(name);
222 // TODO: make resource lookup type-safe
223}
224
225AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
226{
227 std::string name = LoadAttrString(element, attrname, "");
228 if (name.empty())
229 return NULL;
230 else
231 return (AnimationResource*) PageManager::FindResource(name);
232 // TODO: make resource lookup type-safe
233}
234
Dees_Troy51a0e822012-09-05 15:24:24 -0400235bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
236{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200237 if (!node)
238 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400239
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100241 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400242
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200243 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100244 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400245
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200246 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100247 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400248
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200249 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100250 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400251
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 if (placement && node->first_attribute("placement"))
thatf6ed8fc2015-02-14 20:23:16 +0100253 *placement = (RenderObject::Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400254
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400256}
257
258int ActionObject::SetActionPos(int x, int y, int w, int h)
259{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 if (x < 0 || y < 0)
261 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400262
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500263 mActionX = x;
264 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200265 if (w || h)
266 {
267 mActionW = w;
268 mActionH = h;
269 }
270 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400271}
272
Ethan Yonker780cd392014-07-21 15:24:39 -0500273Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400274{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400276
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200277 // We can memset the whole structure, because the alpha channel is ignored
278 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400279
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200280 // With NULL, we make a console-only display
281 if (!page)
282 {
283 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400284
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200285 GUIConsole* element = new GUIConsole(NULL);
286 mRenders.push_back(element);
287 mActions.push_back(element);
288 return;
289 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400290
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200291 if (page->first_attribute("name"))
292 mName = page->first_attribute("name")->value();
293 else
294 {
295 LOGERR("No page name attribute found!\n");
296 return;
297 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400298
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200299 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400300
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200301 // This is a recursive routine for template handling
302 ProcessNode(page, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400303
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200304 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400305}
306
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100307Page::~Page()
308{
309 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
310 delete *itr;
311}
312
Ethan Yonker780cd392014-07-21 15:24:39 -0500313bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */, int depth /* = 0 */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400314{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200315 if (depth == 10)
316 {
317 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
318 return false;
319 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400320
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200321 // Let's retrieve the background value, if any
322 xml_node<>* bg = page->first_node("background");
323 if (bg)
324 {
325 xml_attribute<>* attr = bg->first_attribute("color");
326 if (attr)
327 {
328 std::string color = attr->value();
329 ConvertStrToColor(color, &mBackground);
330 }
331 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400332
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200333 xml_node<>* child;
334 child = page->first_node("object");
335 while (child)
336 {
337 if (!child->first_attribute("type"))
338 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400339
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200340 std::string type = child->first_attribute("type")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400341
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200342 if (type == "text")
343 {
344 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100345 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200346 mRenders.push_back(element);
347 mActions.push_back(element);
348 }
349 else if (type == "image")
350 {
351 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100352 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200353 mRenders.push_back(element);
354 }
355 else if (type == "fill")
356 {
357 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100358 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200359 mRenders.push_back(element);
360 }
361 else if (type == "action")
362 {
363 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100364 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200365 mActions.push_back(element);
366 }
367 else if (type == "console")
368 {
369 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100370 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200371 mRenders.push_back(element);
372 mActions.push_back(element);
373 }
374 else if (type == "button")
375 {
376 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100377 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200378 mRenders.push_back(element);
379 mActions.push_back(element);
380 }
381 else if (type == "checkbox")
382 {
383 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100384 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200385 mRenders.push_back(element);
386 mActions.push_back(element);
387 }
388 else if (type == "fileselector")
389 {
390 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100391 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200392 mRenders.push_back(element);
393 mActions.push_back(element);
394 }
395 else if (type == "animation")
396 {
397 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100398 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200399 mRenders.push_back(element);
400 }
401 else if (type == "progressbar")
402 {
403 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100404 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200405 mRenders.push_back(element);
406 mActions.push_back(element);
407 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400408 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200409 {
410 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100411 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200412 mRenders.push_back(element);
413 mActions.push_back(element);
414 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200415 else if (type == "slidervalue")
416 {
417 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100418 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200419 mRenders.push_back(element);
420 mActions.push_back(element);
421 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400422 else if (type == "listbox")
423 {
424 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100425 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400426 mRenders.push_back(element);
427 mActions.push_back(element);
428 }
429 else if (type == "keyboard")
430 {
431 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100432 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400433 mRenders.push_back(element);
434 mActions.push_back(element);
435 }
436 else if (type == "input")
437 {
438 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100439 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400440 mRenders.push_back(element);
441 mActions.push_back(element);
442 mInputs.push_back(element);
443 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500444 else if (type == "partitionlist")
445 {
446 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100447 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500448 mRenders.push_back(element);
449 mActions.push_back(element);
450 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200451 else if (type == "template")
452 {
453 if (!templates || !child->first_attribute("name"))
454 {
455 LOGERR("Invalid template request.\n");
456 }
457 else
458 {
459 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500460 xml_node<>* node;
461 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400462
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200463 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500464 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
465 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400466
Ethan Yonker780cd392014-07-21 15:24:39 -0500467 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200468 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500469 if (!node->first_attribute("name"))
470 continue;
471
472 if (name == node->first_attribute("name")->value())
473 {
474 if (!ProcessNode(node, templates, depth + 1))
475 return false;
476 else {
477 node_found = true;
478 break;
479 }
480 }
481 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200482 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500483 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200484 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200485 }
486 }
487 }
488 else
489 {
490 LOGERR("Unknown object type.\n");
491 }
492 child = child->next_sibling("object");
493 }
494 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400495}
496
497int Page::Render(void)
498{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200499 // Render background
500 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
501 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400502
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200503 // Render remaining objects
504 std::vector<RenderObject*>::iterator iter;
505 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
506 {
507 if ((*iter)->Render())
508 LOGERR("A render request has failed.\n");
509 }
510 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400511}
512
513int Page::Update(void)
514{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400516
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 std::vector<RenderObject*>::iterator iter;
518 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
519 {
520 int ret = (*iter)->Update();
521 if (ret < 0)
522 LOGERR("An update request has failed.\n");
523 else if (ret > retCode)
524 retCode = ret;
525 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400526
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200527 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400528}
529
530int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
531{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200532 // By default, return 1 to ignore further touches if nobody is listening
533 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400534
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200535 // Don't try to handle a lack of handlers
536 if (mActions.size() == 0)
537 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400538
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200539 // We record mTouchStart so we can pass all the touch stream to the same handler
540 if (state == TOUCH_START)
541 {
542 std::vector<ActionObject*>::reverse_iterator iter;
543 // We work backwards, from top-most element to bottom-most element
544 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
545 {
546 if ((*iter)->IsInRegion(x, y))
547 {
548 mTouchStart = (*iter);
549 ret = mTouchStart->NotifyTouch(state, x, y);
550 if (ret >= 0)
551 break;
552 mTouchStart = NULL;
553 }
554 }
555 }
556 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
557 {
558 ret = mTouchStart->NotifyTouch(state, x, y);
559 mTouchStart = NULL;
560 }
561 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
562 {
563 ret = mTouchStart->NotifyTouch(state, x, y);
564 }
565 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400566}
567
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100568int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400569{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200570 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400571
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200572 // Don't try to handle a lack of handlers
573 if (mActions.size() == 0)
574 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400575
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100576 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200577 // We work backwards, from top-most element to bottom-most element
578 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
579 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100580 ret = (*iter)->NotifyKey(key, down);
581 if (ret < 0) {
582 LOGERR("An action handler has returned an error\n");
583 ret = 1;
584 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100586 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400587}
588
589int Page::NotifyKeyboard(int key)
590{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200591 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400592
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200593 // Don't try to handle a lack of handlers
594 if (mInputs.size() == 0)
595 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400596
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200597 // We work backwards, from top-most element to bottom-most element
598 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
599 {
600 int ret = (*iter)->NotifyKeyboard(key);
601 if (ret == 0)
602 return 0;
603 else if (ret < 0)
604 LOGERR("A keyboard handler has returned an error");
605 }
606 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400607}
608
609int Page::SetKeyBoardFocus(int inFocus)
610{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200611 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400612
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200613 // Don't try to handle a lack of handlers
614 if (mInputs.size() == 0)
615 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400616
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200617 // We work backwards, from top-most element to bottom-most element
618 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
619 {
620 int ret = (*iter)->SetInputFocus(inFocus);
621 if (ret == 0)
622 return 0;
623 else if (ret < 0)
624 LOGERR("An input focus handler has returned an error");
625 }
626 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400627}
628
629void Page::SetPageFocus(int inFocus)
630{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 // Render remaining objects
632 std::vector<RenderObject*>::iterator iter;
633 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
634 (*iter)->SetPageFocus(inFocus);
635
636 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400637}
638
639int Page::NotifyVarChange(std::string varName, std::string value)
640{
Vojtech Bocek07220562014-02-08 02:05:33 +0100641 std::vector<GUIObject*>::iterator iter;
642 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200643 {
644 if ((*iter)->NotifyVarChange(varName, value))
645 LOGERR("An action handler errored on NotifyVarChange.\n");
646 }
647 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400648}
649
650PageSet::PageSet(char* xmlFile)
651{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200652 mResources = NULL;
653 mCurrentPage = NULL;
654 mOverlayPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400655
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200656 mXmlFile = xmlFile;
657 if (xmlFile)
658 mDoc.parse<0>(mXmlFile);
659 else
660 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400661}
662
663PageSet::~PageSet()
664{
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100665 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
666 delete *itr;
667
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200668 delete mResources;
669 free(mXmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100670
671 mDoc.clear();
672
673 for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
674 (*itr)->clear();
675 delete *itr;
676 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400677}
678
679int PageSet::Load(ZipArchive* package)
680{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200681 xml_node<>* parent;
682 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500683 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600684 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500685
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200686 parent = mDoc.first_node("recovery");
687 if (!parent)
688 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400689
Ethan Yonker63e414f2015-02-06 15:44:39 -0600690 set_scale_values(1, 1); // Reset any previous scaling values
691
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200692 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600693 LOGINFO("Checking resolution...\n");
694 child = parent->first_node("details");
695 if (child) {
696 xml_node<>* resolution = child->first_node("resolution");
697 if (resolution) {
698 xml_attribute<>* width_attr = resolution->first_attribute("width");
699 xml_attribute<>* height_attr = resolution->first_attribute("height");
700 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
701 if (width_attr && height_attr && !noscale_attr) {
702 int width = atoi(width_attr->value());
703 int height = atoi(height_attr->value());
704 int offx = 0, offy = 0;
705#ifdef TW_ROUND_SCREEN
706 xml_node<>* roundscreen = child->first_node("roundscreen");
707 if (roundscreen) {
708 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
709 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
710 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
711 if (offx_attr) {
712 offx = atoi(offx_attr->value());
713 }
714 if (offy_attr) {
715 offy = atoi(offy_attr->value());
716 }
717 }
718#endif
719 if (width != 0 && height != 0) {
720 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
721 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
722#ifdef TW_ROUND_SCREEN
723 float scale_off_w = (float)gr_fb_width() / (float)width;
724 float scale_off_h = (float)gr_fb_height() / (float)height;
725 tw_x_offset = offx * scale_off_w;
726 tw_y_offset = offy * scale_off_h;
727#endif
728 if (scale_w != 1 || scale_h != 1) {
729 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
730 set_scale_values(scale_w, scale_h);
731 }
732 }
733 } else {
734 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
735 }
736 } else {
737 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
738 }
739 } else {
740 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
741 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200742 LOGINFO("Loading resources...\n");
743 child = parent->first_node("resources");
744 if (child)
745 mResources = new ResourceManager(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400746
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200747 LOGINFO("Loading variables...\n");
748 child = parent->first_node("variables");
749 if (child)
750 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400751
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100752 LOGINFO("Loading mouse cursor...\n");
753 child = parent->first_node("mousecursor");
754 if(child)
755 PageManager::LoadCursorData(child);
756
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200757 LOGINFO("Loading pages...\n");
758 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500759 xmltemplate = parent->first_node("templates");
760 if (xmltemplate)
761 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400762
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600763 // Load styles if present
764 xmlstyle = parent->first_node("styles");
765 if (xmlstyle)
766 styles.push_back(xmlstyle);
767
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200768 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500769 if (child) {
770 if (LoadPages(child)) {
771 LOGERR("PageSet::Load returning -1\n");
772 return -1;
773 }
774 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100775
Ethan Yonker780cd392014-07-21 15:24:39 -0500776 return CheckInclude(package, &mDoc);
777}
Dees_Troy51a0e822012-09-05 15:24:24 -0400778
Ethan Yonker780cd392014-07-21 15:24:39 -0500779int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
780{
781 xml_node<>* par;
782 xml_node<>* par2;
783 xml_node<>* chld;
784 xml_node<>* parent;
785 xml_node<>* child;
786 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600787 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500788 long len;
789 char* xmlFile = NULL;
790 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100791 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500792
793 par = parentDoc->first_node("recovery");
794 if (!par) {
795 par = parentDoc->first_node("install");
796 }
797 if (!par) {
798 return 0;
799 }
800
801 par2 = par->first_node("include");
802 if (!par2)
803 return 0;
804 chld = par2->first_node("xmlfile");
805 while (chld != NULL) {
806 xml_attribute<>* attr = chld->first_attribute("name");
807 if (!attr)
808 break;
809
Ethan Yonker780cd392014-07-21 15:24:39 -0500810 if (!package) {
811 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000812 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500813 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000814 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500815 struct stat st;
816 if(stat(filename.c_str(),&st) != 0) {
817 LOGERR("Unable to locate '%s'\n", filename.c_str());
818 return -1;
819 }
820
821 len = st.st_size;
822 xmlFile = (char*) malloc(len + 1);
823 if (!xmlFile)
824 return -1;
825
826 int fd = open(filename.c_str(), O_RDONLY);
827 if (fd == -1)
828 return -1;
829
830 read(fd, xmlFile, len);
831 close(fd);
832 } else {
833 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000834 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500835 const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
836 if (ui_xml == NULL)
837 {
838 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
839 return -1;
840 }
841
842 // Allocate the buffer for the file
843 len = mzGetZipEntryUncompLen(ui_xml);
844 xmlFile = (char*) malloc(len + 1);
845 if (!xmlFile)
846 return -1;
847
848 if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
849 {
850 LOGERR("Unable to extract '%s'\n", filename.c_str());
851 return -1;
852 }
853 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500854
Vojtech Boceke979abd2015-01-12 18:29:12 +0100855 xmlFile[len] = '\0';
856 doc = new xml_document<>();
857 doc->parse<0>(xmlFile);
858
859 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500860 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100861 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500862
863 // Now, let's parse the XML
864 LOGINFO("Loading included resources...\n");
865 child = parent->first_node("resources");
866 if (child)
867 mResources->LoadResources(child, package);
868
869 LOGINFO("Loading included variables...\n");
870 child = parent->first_node("variables");
871 if (child)
872 LoadVariables(child);
873
874 LOGINFO("Loading mouse cursor...\n");
875 child = parent->first_node("mousecursor");
876 if(child)
877 PageManager::LoadCursorData(child);
878
879 LOGINFO("Loading included pages...\n");
880 // This may be NULL if no templates are present
881 xmltemplate = parent->first_node("templates");
882 if (xmltemplate)
883 templates.push_back(xmltemplate);
884
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600885 // Load styles if present
886 xmlstyle = parent->first_node("styles");
887 if (xmlstyle)
888 styles.push_back(xmlstyle);
889
Ethan Yonker780cd392014-07-21 15:24:39 -0500890 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100891 if (child && LoadPages(child))
892 {
893 templates.pop_back();
894 doc->clear();
895 delete doc;
896 return -1;
897 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500898
Vojtech Boceke979abd2015-01-12 18:29:12 +0100899 mIncludedDocs.push_back(doc);
900
901 if (CheckInclude(package, doc))
Ethan Yonker780cd392014-07-21 15:24:39 -0500902 return -1;
903
904 chld = chld->next_sibling("xmlfile");
905 }
906
907 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400908}
909
910int PageSet::SetPage(std::string page)
911{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200912 Page* tmp = FindPage(page);
913 if (tmp)
914 {
915 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
916 mCurrentPage = tmp;
917 mCurrentPage->SetPageFocus(1);
918 mCurrentPage->NotifyVarChange("", "");
919 return 0;
920 }
921 else
922 {
923 LOGERR("Unable to locate page (%s)\n", page.c_str());
924 }
925 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400926}
927
928int PageSet::SetOverlay(Page* page)
929{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200930 if (mOverlayPage) mOverlayPage->SetPageFocus(0);
931 mOverlayPage = page;
932 if (mOverlayPage)
933 {
934 mOverlayPage->SetPageFocus(1);
935 mOverlayPage->NotifyVarChange("", "");
936 }
937 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400938}
939
940Resource* PageSet::FindResource(std::string name)
941{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200942 return mResources ? mResources->FindResource(name) : NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400943}
944
945Page* PageSet::FindPage(std::string name)
946{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200947 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400948
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200949 for (iter = mPages.begin(); iter != mPages.end(); iter++)
950 {
951 if (name == (*iter)->GetName())
952 return (*iter);
953 }
954 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400955}
956
957int PageSet::LoadVariables(xml_node<>* vars)
958{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200959 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100960 xml_attribute<> *name, *value, *persist;
961 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400962
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200963 child = vars->first_node("variable");
964 while (child)
965 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100966 name = child->first_attribute("name");
967 value = child->first_attribute("value");
968 persist = child->first_attribute("persist");
969 if(name && value)
970 {
Ethan Yonker751a85e2014-12-12 16:59:10 -0600971 if (strcmp(name->value(), "tw_x_offset") == 0) {
972 tw_x_offset = atoi(value->value());
973 child = child->next_sibling("variable");
974 continue;
975 }
976 if (strcmp(name->value(), "tw_y_offset") == 0) {
977 tw_y_offset = atoi(value->value());
978 child = child->next_sibling("variable");
979 continue;
980 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100981 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -0500982 string temp = value->value();
983 string valstr = gui_parse_text(temp);
984
985 if (valstr.find("+") != string::npos) {
986 string val1str = valstr;
987 val1str = val1str.substr(0, val1str.find('+'));
988 string val2str = valstr;
989 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
990 int val1 = atoi(val1str.c_str());
991 int val2 = atoi(val2str.c_str());
992 int val = val1 + val2;
993
994 DataManager::SetValue(name->value(), val, p);
995 } else if (valstr.find("-") != string::npos) {
996 string val1str = valstr;
997 val1str = val1str.substr(0, val1str.find('-'));
998 string val2str = valstr;
999 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1000 int val1 = atoi(val1str.c_str());
1001 int val2 = atoi(val2str.c_str());
1002 int val = val1 - val2;
1003
1004 DataManager::SetValue(name->value(), val, p);
1005 } else {
1006 DataManager::SetValue(name->value(), valstr, p);
1007 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001008 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001009
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001010 child = child->next_sibling("variable");
1011 }
1012 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001013}
1014
Ethan Yonker780cd392014-07-21 15:24:39 -05001015int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001016{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001017 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001018
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001019 if (!pages)
1020 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001021
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001022 child = pages->first_node("page");
1023 while (child != NULL)
1024 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001025 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001026 if (page->GetName().empty())
1027 {
1028 LOGERR("Unable to process load page\n");
1029 delete page;
1030 }
1031 else
1032 {
1033 mPages.push_back(page);
1034 }
1035 child = child->next_sibling("page");
1036 }
1037 if (mPages.size() > 0)
1038 return 0;
1039 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001040}
1041
1042int PageSet::IsCurrentPage(Page* page)
1043{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001044 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001045}
1046
1047int PageSet::Render(void)
1048{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001049 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001050
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001051 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1052 if (ret < 0)
1053 return ret;
1054 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
1055 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001056}
1057
1058int PageSet::Update(void)
1059{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001060 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001061
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001062 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1063 if (ret < 0 || ret > 1)
1064 return ret;
1065 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
1066 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001067}
1068
1069int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1070{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001071 if (mOverlayPage)
1072 return (mOverlayPage->NotifyTouch(state, x, y));
1073
1074 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001075}
1076
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001077int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001078{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001079 if (mOverlayPage)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001080 return (mOverlayPage->NotifyKey(key, down));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001081
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001082 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001083}
1084
1085int PageSet::NotifyKeyboard(int key)
1086{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001087 if (mOverlayPage)
1088 return (mOverlayPage->NotifyKeyboard(key));
1089
1090 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001091}
1092
1093int PageSet::SetKeyBoardFocus(int inFocus)
1094{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001095 if (mOverlayPage)
1096 return (mOverlayPage->SetKeyBoardFocus(inFocus));
1097
1098 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001099}
1100
1101int PageSet::NotifyVarChange(std::string varName, std::string value)
1102{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001103 if (mOverlayPage)
1104 mOverlayPage->NotifyVarChange(varName, value);
1105
1106 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001107}
1108
1109int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1110{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001111 int fd;
1112 ZipArchive zip, *pZip = NULL;
1113 long len;
1114 char* xmlFile = NULL;
1115 PageSet* pageSet = NULL;
1116 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001117 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001118
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001119 // Open the XML file
1120 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001121 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001122 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001123 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001124 tw_x_offset = TW_X_OFFSET;
1125 tw_y_offset = TW_Y_OFFSET;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001126 // We can try to load the XML directly...
1127 struct stat st;
1128 if(stat(package.c_str(),&st) != 0)
1129 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001130
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001131 len = st.st_size;
1132 xmlFile = (char*) malloc(len + 1);
1133 if (!xmlFile)
1134 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001135
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001136 fd = open(package.c_str(), O_RDONLY);
1137 if (fd == -1)
1138 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -04001139
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001140 read(fd, xmlFile, len);
1141 close(fd);
1142 }
1143 else
1144 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001145 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001146 tw_x_offset = 0;
1147 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001148 if (!TWFunc::Path_Exists(package))
1149 return -1;
1150 if (sysMapFile(package.c_str(), &map) != 0) {
1151 LOGERR("Failed to map '%s'\n", package.c_str());
1152 return -1;
1153 }
1154 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1155 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1156 sysReleaseMap(&map);
1157 return -1;
1158 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001159 pZip = &zip;
1160 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
1161 if (ui_xml == NULL)
1162 {
1163 LOGERR("Unable to locate ui.xml in zip file\n");
1164 goto error;
1165 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001166
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001167 // Allocate the buffer for the file
1168 len = mzGetZipEntryUncompLen(ui_xml);
1169 xmlFile = (char*) malloc(len + 1);
1170 if (!xmlFile)
1171 goto error;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001172
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001173 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
1174 {
1175 LOGERR("Unable to extract ui.xml\n");
1176 goto error;
1177 }
1178 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001179
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001180 // NULL-terminate the string
1181 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -04001182
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001183 // Before loading, mCurrentSet must be the loading package so we can find resources
1184 pageSet = mCurrentSet;
1185 mCurrentSet = new PageSet(xmlFile);
1186
1187 ret = mCurrentSet->Load(pZip);
1188 if (ret == 0)
1189 {
1190 mCurrentSet->SetPage(startpage);
1191 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1192 }
1193 else
1194 {
1195 LOGERR("Package %s failed to load.\n", name.c_str());
1196 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001197
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001198 // The first successful package we loaded is the base
1199 if (mBaseSet == NULL)
1200 mBaseSet = mCurrentSet;
1201
1202 mCurrentSet = pageSet;
1203
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001204 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001205 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001206 sysReleaseMap(&map);
1207 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001208 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001209
1210error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001211 LOGERR("An internal error has occurred.\n");
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001212 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001213 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001214 sysReleaseMap(&map);
1215 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001216 if (xmlFile)
1217 free(xmlFile);
1218 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001219}
1220
1221PageSet* PageManager::FindPackage(std::string name)
1222{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001223 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001224
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001225 iter = mPageSets.find(name);
1226 if (iter != mPageSets.end())
1227 return (*iter).second;
1228
1229 LOGERR("Unable to locate package %s\n", name.c_str());
1230 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001231}
1232
1233PageSet* PageManager::SelectPackage(std::string name)
1234{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001235 LOGINFO("Switching packages (%s)\n", name.c_str());
1236 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001237
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001238 tmp = FindPackage(name);
1239 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001240 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001241 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001242 mCurrentSet->NotifyVarChange("", "");
1243 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001244 else
1245 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001246
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001247 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001248}
1249
1250int PageManager::ReloadPackage(std::string name, std::string package)
1251{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001252 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001253
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001254 iter = mPageSets.find(name);
1255 if (iter == mPageSets.end())
1256 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001257
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001258 if(mMouseCursor)
1259 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001261 PageSet* set = (*iter).second;
1262 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001263
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001264 if (LoadPackage(name, package, "main") != 0)
1265 {
Dees Troy3454ade2015-01-20 19:21:04 +00001266 LOGERR("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001267 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1268 return -1;
1269 }
1270 if (mCurrentSet == set)
1271 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001272 if (mBaseSet == set)
1273 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001274 delete set;
1275 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001276}
1277
1278void PageManager::ReleasePackage(std::string name)
1279{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001280 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001281
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001282 iter = mPageSets.find(name);
1283 if (iter == mPageSets.end())
1284 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001285
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001286 PageSet* set = (*iter).second;
1287 mPageSets.erase(iter);
1288 delete set;
1289 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001290}
1291
1292int PageManager::ChangePage(std::string name)
1293{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001294 DataManager::SetValue("tw_operation_state", 0);
1295 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1296 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001297}
1298
1299int PageManager::ChangeOverlay(std::string name)
1300{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001301 if (name.empty())
1302 return mCurrentSet->SetOverlay(NULL);
1303 else
1304 {
1305 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1306 return mCurrentSet->SetOverlay(page);
1307 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001308}
1309
1310Resource* PageManager::FindResource(std::string name)
1311{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001312 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001313}
1314
1315Resource* PageManager::FindResource(std::string package, std::string name)
1316{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001317 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001318
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001319 tmp = FindPackage(name);
1320 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001321}
1322
1323int PageManager::SwitchToConsole(void)
1324{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001325 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001326
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001327 mCurrentSet = console;
1328 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001329}
1330
Ethan Yonker03a42f62014-08-08 11:03:51 -05001331int PageManager::EndConsole(void)
1332{
1333 if (mCurrentSet && mBaseSet) {
1334 delete mCurrentSet;
1335 mCurrentSet = mBaseSet;
1336 return 0;
1337 }
1338 return -1;
1339}
1340
Dees_Troy51a0e822012-09-05 15:24:24 -04001341int PageManager::IsCurrentPage(Page* page)
1342{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001343 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001344}
1345
1346int PageManager::Render(void)
1347{
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001348 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1349 if(mMouseCursor)
1350 mMouseCursor->Render();
1351 return res;
1352}
1353
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001354HardwareKeyboard *PageManager::GetHardwareKeyboard()
1355{
1356 if(!mHardwareKeyboard)
1357 mHardwareKeyboard = new HardwareKeyboard();
1358 return mHardwareKeyboard;
1359}
1360
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001361xml_node<>* PageManager::FindStyle(std::string name)
1362{
1363 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1364 xml_node<>* node = (*itr)->first_node("style");
1365
1366 while (node) {
1367 if (!node->first_attribute("name"))
1368 continue;
1369
1370 if (name == node->first_attribute("name")->value())
1371 return node;
1372 node = node->next_sibling("style");
1373 }
1374 }
1375 return NULL;
1376}
1377
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001378MouseCursor *PageManager::GetMouseCursor()
1379{
1380 if(!mMouseCursor)
1381 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1382 return mMouseCursor;
1383}
1384
1385void PageManager::LoadCursorData(xml_node<>* node)
1386{
1387 if(!mMouseCursor)
1388 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1389
1390 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001391}
1392
1393int PageManager::Update(void)
1394{
thatfb759d42015-01-11 12:16:53 +01001395 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001396 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001397
1398 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1399
1400 if(mMouseCursor)
1401 {
1402 int c_res = mMouseCursor->Update();
1403 if(c_res > res)
1404 res = c_res;
1405 }
1406 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001407}
1408
1409int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1410{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001411 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001412}
1413
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001414int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001415{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001416 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001417}
1418
1419int PageManager::NotifyKeyboard(int key)
1420{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001421 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001422}
1423
1424int PageManager::SetKeyBoardFocus(int inFocus)
1425{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001426 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001427}
1428
1429int PageManager::NotifyVarChange(std::string varName, std::string value)
1430{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001431 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001432}
1433
1434extern "C" void gui_notifyVarChange(const char *name, const char* value)
1435{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001436 if (!gGuiRunning)
1437 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001438
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001439 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001440}