blob: 50c60a695f6f127b991645d1f19d7841dec7f840 [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{
108 xml_node<>* child = parent->first_node(nodename);
109 if (child)
110 return child;
111
112 if (depth == 10) {
113 LOGERR("Too many style loops detected.\n");
114 return NULL;
115 }
116
117 xml_node<>* style = parent->first_node("style");
118 if (style) {
119 while (style) {
120 if (!style->first_attribute("name")) {
121 LOGERR("No name given for style.\n");
122 continue;
123 } else {
124 std::string name = style->first_attribute("name")->value();
125 xml_node<>* node = PageManager::FindStyle(name);
126
127 if (node) {
128 // We found the style that was named
129 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
130 if (stylenode)
131 return stylenode;
132 }
133 }
134 style = style->next_sibling("style");
135 }
136 } else {
137 // Search for stylename in the parent node <object type="foo" stylename="foo2">
138 xml_attribute<>* attr = parent->first_attribute("style");
139 // If no style is found anywhere else and the node wasn't found in the object itself
140 // as a special case we will search for a style that uses the same style name as the
141 // object type, so <object type="button"> would search for a style named "button"
142 if (!attr)
143 attr = parent->first_attribute("type");
144 if (attr) {
145 xml_node<>* node = PageManager::FindStyle(attr->value());
146 if (node) {
147 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
148 if (stylenode)
149 return stylenode;
150 }
151 }
152 }
153 return NULL;
154}
155
thatf6ed8fc2015-02-14 20:23:16 +0100156std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
157{
158 if (!element)
159 return defaultvalue;
160
161 xml_attribute<>* attr = element->first_attribute(attrname);
162 return attr ? attr->value() : defaultvalue;
163}
164
165int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
166{
167 string value = LoadAttrString(element, attrname);
168 // resolve variables
169 DataManager::GetValue(value, value);
170 return value.empty() ? defaultvalue : atoi(value.c_str());
171}
172
173int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
174{
175 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
176}
177
178int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
179{
180 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
181}
182
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600183COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100184{
185 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600186 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100187 // resolve variables
188 DataManager::GetValue(value, value);
189 COLOR ret = defaultvalue;
190 if (ConvertStrToColor(value, &ret) == 0)
191 return ret;
192 else
193 return defaultvalue;
194}
195
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600196COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
197{
198 bool found_color = false;
199 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
200}
201
thatf6ed8fc2015-02-14 20:23:16 +0100202FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
203{
204 std::string name = LoadAttrString(element, attrname, "");
205 if (name.empty())
206 return NULL;
207 else
208 return (FontResource*) PageManager::FindResource(name);
209 // TODO: make resource lookup type-safe
210}
211
212ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
213{
214 std::string name = LoadAttrString(element, attrname, "");
215 if (name.empty())
216 return NULL;
217 else
218 return (ImageResource*) PageManager::FindResource(name);
219 // TODO: make resource lookup type-safe
220}
221
222AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
223{
224 std::string name = LoadAttrString(element, attrname, "");
225 if (name.empty())
226 return NULL;
227 else
228 return (AnimationResource*) PageManager::FindResource(name);
229 // TODO: make resource lookup type-safe
230}
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 Bocekfafb0c52013-07-25 22:53:02 +0200448 else if (type == "template")
449 {
450 if (!templates || !child->first_attribute("name"))
451 {
452 LOGERR("Invalid template request.\n");
453 }
454 else
455 {
456 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500457 xml_node<>* node;
458 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400459
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200460 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500461 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
462 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400463
Ethan Yonker780cd392014-07-21 15:24:39 -0500464 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200465 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500466 if (!node->first_attribute("name"))
467 continue;
468
469 if (name == node->first_attribute("name")->value())
470 {
471 if (!ProcessNode(node, templates, depth + 1))
472 return false;
473 else {
474 node_found = true;
475 break;
476 }
477 }
478 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200479 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500480 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200481 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200482 }
483 }
484 }
485 else
486 {
487 LOGERR("Unknown object type.\n");
488 }
489 child = child->next_sibling("object");
490 }
491 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400492}
493
494int Page::Render(void)
495{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200496 // Render background
497 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
498 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400499
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200500 // Render remaining objects
501 std::vector<RenderObject*>::iterator iter;
502 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
503 {
504 if ((*iter)->Render())
505 LOGERR("A render request has failed.\n");
506 }
507 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400508}
509
510int Page::Update(void)
511{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200512 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400513
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200514 std::vector<RenderObject*>::iterator iter;
515 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
516 {
517 int ret = (*iter)->Update();
518 if (ret < 0)
519 LOGERR("An update request has failed.\n");
520 else if (ret > retCode)
521 retCode = ret;
522 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400523
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200524 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400525}
526
527int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
528{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200529 // By default, return 1 to ignore further touches if nobody is listening
530 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400531
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200532 // Don't try to handle a lack of handlers
533 if (mActions.size() == 0)
534 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400535
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200536 // We record mTouchStart so we can pass all the touch stream to the same handler
537 if (state == TOUCH_START)
538 {
539 std::vector<ActionObject*>::reverse_iterator iter;
540 // We work backwards, from top-most element to bottom-most element
541 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
542 {
543 if ((*iter)->IsInRegion(x, y))
544 {
545 mTouchStart = (*iter);
546 ret = mTouchStart->NotifyTouch(state, x, y);
547 if (ret >= 0)
548 break;
549 mTouchStart = NULL;
550 }
551 }
552 }
553 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
554 {
555 ret = mTouchStart->NotifyTouch(state, x, y);
556 mTouchStart = NULL;
557 }
558 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
559 {
560 ret = mTouchStart->NotifyTouch(state, x, y);
561 }
562 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400563}
564
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100565int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400566{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200567 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400568
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200569 // Don't try to handle a lack of handlers
570 if (mActions.size() == 0)
571 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400572
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100573 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200574 // We work backwards, from top-most element to bottom-most element
575 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
576 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100577 ret = (*iter)->NotifyKey(key, down);
578 if (ret < 0) {
579 LOGERR("An action handler has returned an error\n");
580 ret = 1;
581 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200582 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100583 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400584}
585
586int Page::NotifyKeyboard(int key)
587{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200588 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400589
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200590 // Don't try to handle a lack of handlers
591 if (mInputs.size() == 0)
592 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400593
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200594 // We work backwards, from top-most element to bottom-most element
595 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
596 {
597 int ret = (*iter)->NotifyKeyboard(key);
598 if (ret == 0)
599 return 0;
600 else if (ret < 0)
601 LOGERR("A keyboard handler has returned an error");
602 }
603 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400604}
605
606int Page::SetKeyBoardFocus(int inFocus)
607{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400609
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200610 // Don't try to handle a lack of handlers
611 if (mInputs.size() == 0)
612 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400613
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200614 // We work backwards, from top-most element to bottom-most element
615 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
616 {
617 int ret = (*iter)->SetInputFocus(inFocus);
618 if (ret == 0)
619 return 0;
620 else if (ret < 0)
621 LOGERR("An input focus handler has returned an error");
622 }
623 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400624}
625
626void Page::SetPageFocus(int inFocus)
627{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628 // Render remaining objects
629 std::vector<RenderObject*>::iterator iter;
630 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
631 (*iter)->SetPageFocus(inFocus);
632
633 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400634}
635
636int Page::NotifyVarChange(std::string varName, std::string value)
637{
Vojtech Bocek07220562014-02-08 02:05:33 +0100638 std::vector<GUIObject*>::iterator iter;
639 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200640 {
641 if ((*iter)->NotifyVarChange(varName, value))
642 LOGERR("An action handler errored on NotifyVarChange.\n");
643 }
644 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400645}
646
647PageSet::PageSet(char* xmlFile)
648{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200649 mResources = NULL;
650 mCurrentPage = NULL;
651 mOverlayPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400652
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200653 mXmlFile = xmlFile;
654 if (xmlFile)
655 mDoc.parse<0>(mXmlFile);
656 else
657 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400658}
659
660PageSet::~PageSet()
661{
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100662 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
663 delete *itr;
664
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200665 delete mResources;
666 free(mXmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100667
668 mDoc.clear();
669
670 for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
671 (*itr)->clear();
672 delete *itr;
673 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400674}
675
676int PageSet::Load(ZipArchive* package)
677{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200678 xml_node<>* parent;
679 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500680 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600681 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500682
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200683 parent = mDoc.first_node("recovery");
684 if (!parent)
685 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400686
Ethan Yonker63e414f2015-02-06 15:44:39 -0600687 set_scale_values(1, 1); // Reset any previous scaling values
688
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200689 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600690 LOGINFO("Checking resolution...\n");
691 child = parent->first_node("details");
692 if (child) {
693 xml_node<>* resolution = child->first_node("resolution");
694 if (resolution) {
695 xml_attribute<>* width_attr = resolution->first_attribute("width");
696 xml_attribute<>* height_attr = resolution->first_attribute("height");
697 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
698 if (width_attr && height_attr && !noscale_attr) {
699 int width = atoi(width_attr->value());
700 int height = atoi(height_attr->value());
701 int offx = 0, offy = 0;
702#ifdef TW_ROUND_SCREEN
703 xml_node<>* roundscreen = child->first_node("roundscreen");
704 if (roundscreen) {
705 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
706 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
707 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
708 if (offx_attr) {
709 offx = atoi(offx_attr->value());
710 }
711 if (offy_attr) {
712 offy = atoi(offy_attr->value());
713 }
714 }
715#endif
716 if (width != 0 && height != 0) {
717 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
718 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
719#ifdef TW_ROUND_SCREEN
720 float scale_off_w = (float)gr_fb_width() / (float)width;
721 float scale_off_h = (float)gr_fb_height() / (float)height;
722 tw_x_offset = offx * scale_off_w;
723 tw_y_offset = offy * scale_off_h;
724#endif
725 if (scale_w != 1 || scale_h != 1) {
726 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
727 set_scale_values(scale_w, scale_h);
728 }
729 }
730 } else {
731 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
732 }
733 } else {
734 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
735 }
736 } else {
737 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
738 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200739 LOGINFO("Loading resources...\n");
740 child = parent->first_node("resources");
741 if (child)
742 mResources = new ResourceManager(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400743
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200744 LOGINFO("Loading variables...\n");
745 child = parent->first_node("variables");
746 if (child)
747 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400748
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100749 LOGINFO("Loading mouse cursor...\n");
750 child = parent->first_node("mousecursor");
751 if(child)
752 PageManager::LoadCursorData(child);
753
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200754 LOGINFO("Loading pages...\n");
755 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500756 xmltemplate = parent->first_node("templates");
757 if (xmltemplate)
758 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400759
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600760 // Load styles if present
761 xmlstyle = parent->first_node("styles");
762 if (xmlstyle)
763 styles.push_back(xmlstyle);
764
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200765 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500766 if (child) {
767 if (LoadPages(child)) {
768 LOGERR("PageSet::Load returning -1\n");
769 return -1;
770 }
771 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100772
Ethan Yonker780cd392014-07-21 15:24:39 -0500773 return CheckInclude(package, &mDoc);
774}
Dees_Troy51a0e822012-09-05 15:24:24 -0400775
Ethan Yonker780cd392014-07-21 15:24:39 -0500776int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
777{
778 xml_node<>* par;
779 xml_node<>* par2;
780 xml_node<>* chld;
781 xml_node<>* parent;
782 xml_node<>* child;
783 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600784 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500785 long len;
786 char* xmlFile = NULL;
787 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100788 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500789
790 par = parentDoc->first_node("recovery");
791 if (!par) {
792 par = parentDoc->first_node("install");
793 }
794 if (!par) {
795 return 0;
796 }
797
798 par2 = par->first_node("include");
799 if (!par2)
800 return 0;
801 chld = par2->first_node("xmlfile");
802 while (chld != NULL) {
803 xml_attribute<>* attr = chld->first_attribute("name");
804 if (!attr)
805 break;
806
Ethan Yonker780cd392014-07-21 15:24:39 -0500807 if (!package) {
808 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000809 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500810 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000811 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500812 struct stat st;
813 if(stat(filename.c_str(),&st) != 0) {
814 LOGERR("Unable to locate '%s'\n", filename.c_str());
815 return -1;
816 }
817
818 len = st.st_size;
819 xmlFile = (char*) malloc(len + 1);
820 if (!xmlFile)
821 return -1;
822
823 int fd = open(filename.c_str(), O_RDONLY);
824 if (fd == -1)
825 return -1;
826
827 read(fd, xmlFile, len);
828 close(fd);
829 } else {
830 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000831 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500832 const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
833 if (ui_xml == NULL)
834 {
835 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
836 return -1;
837 }
838
839 // Allocate the buffer for the file
840 len = mzGetZipEntryUncompLen(ui_xml);
841 xmlFile = (char*) malloc(len + 1);
842 if (!xmlFile)
843 return -1;
844
845 if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
846 {
847 LOGERR("Unable to extract '%s'\n", filename.c_str());
848 return -1;
849 }
850 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500851
Vojtech Boceke979abd2015-01-12 18:29:12 +0100852 xmlFile[len] = '\0';
853 doc = new xml_document<>();
854 doc->parse<0>(xmlFile);
855
856 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500857 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100858 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500859
860 // Now, let's parse the XML
861 LOGINFO("Loading included resources...\n");
862 child = parent->first_node("resources");
863 if (child)
864 mResources->LoadResources(child, package);
865
866 LOGINFO("Loading included variables...\n");
867 child = parent->first_node("variables");
868 if (child)
869 LoadVariables(child);
870
871 LOGINFO("Loading mouse cursor...\n");
872 child = parent->first_node("mousecursor");
873 if(child)
874 PageManager::LoadCursorData(child);
875
876 LOGINFO("Loading included pages...\n");
877 // This may be NULL if no templates are present
878 xmltemplate = parent->first_node("templates");
879 if (xmltemplate)
880 templates.push_back(xmltemplate);
881
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600882 // Load styles if present
883 xmlstyle = parent->first_node("styles");
884 if (xmlstyle)
885 styles.push_back(xmlstyle);
886
Ethan Yonker780cd392014-07-21 15:24:39 -0500887 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100888 if (child && LoadPages(child))
889 {
890 templates.pop_back();
891 doc->clear();
892 delete doc;
893 return -1;
894 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500895
Vojtech Boceke979abd2015-01-12 18:29:12 +0100896 mIncludedDocs.push_back(doc);
897
898 if (CheckInclude(package, doc))
Ethan Yonker780cd392014-07-21 15:24:39 -0500899 return -1;
900
901 chld = chld->next_sibling("xmlfile");
902 }
903
904 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400905}
906
907int PageSet::SetPage(std::string page)
908{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200909 Page* tmp = FindPage(page);
910 if (tmp)
911 {
912 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
913 mCurrentPage = tmp;
914 mCurrentPage->SetPageFocus(1);
915 mCurrentPage->NotifyVarChange("", "");
916 return 0;
917 }
918 else
919 {
920 LOGERR("Unable to locate page (%s)\n", page.c_str());
921 }
922 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400923}
924
925int PageSet::SetOverlay(Page* page)
926{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200927 if (mOverlayPage) mOverlayPage->SetPageFocus(0);
928 mOverlayPage = page;
929 if (mOverlayPage)
930 {
931 mOverlayPage->SetPageFocus(1);
932 mOverlayPage->NotifyVarChange("", "");
933 }
934 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400935}
936
937Resource* PageSet::FindResource(std::string name)
938{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200939 return mResources ? mResources->FindResource(name) : NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400940}
941
942Page* PageSet::FindPage(std::string name)
943{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200944 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400945
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200946 for (iter = mPages.begin(); iter != mPages.end(); iter++)
947 {
948 if (name == (*iter)->GetName())
949 return (*iter);
950 }
951 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400952}
953
954int PageSet::LoadVariables(xml_node<>* vars)
955{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200956 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100957 xml_attribute<> *name, *value, *persist;
958 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400959
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200960 child = vars->first_node("variable");
961 while (child)
962 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100963 name = child->first_attribute("name");
964 value = child->first_attribute("value");
965 persist = child->first_attribute("persist");
966 if(name && value)
967 {
Ethan Yonker751a85e2014-12-12 16:59:10 -0600968 if (strcmp(name->value(), "tw_x_offset") == 0) {
969 tw_x_offset = atoi(value->value());
970 child = child->next_sibling("variable");
971 continue;
972 }
973 if (strcmp(name->value(), "tw_y_offset") == 0) {
974 tw_y_offset = atoi(value->value());
975 child = child->next_sibling("variable");
976 continue;
977 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100978 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -0500979 string temp = value->value();
980 string valstr = gui_parse_text(temp);
981
982 if (valstr.find("+") != string::npos) {
983 string val1str = valstr;
984 val1str = val1str.substr(0, val1str.find('+'));
985 string val2str = valstr;
986 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
987 int val1 = atoi(val1str.c_str());
988 int val2 = atoi(val2str.c_str());
989 int val = val1 + val2;
990
991 DataManager::SetValue(name->value(), val, p);
992 } else if (valstr.find("-") != string::npos) {
993 string val1str = valstr;
994 val1str = val1str.substr(0, val1str.find('-'));
995 string val2str = valstr;
996 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
997 int val1 = atoi(val1str.c_str());
998 int val2 = atoi(val2str.c_str());
999 int val = val1 - val2;
1000
1001 DataManager::SetValue(name->value(), val, p);
1002 } else {
1003 DataManager::SetValue(name->value(), valstr, p);
1004 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001005 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001006
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001007 child = child->next_sibling("variable");
1008 }
1009 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001010}
1011
Ethan Yonker780cd392014-07-21 15:24:39 -05001012int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001013{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001014 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001015
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001016 if (!pages)
1017 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001018
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001019 child = pages->first_node("page");
1020 while (child != NULL)
1021 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001022 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001023 if (page->GetName().empty())
1024 {
1025 LOGERR("Unable to process load page\n");
1026 delete page;
1027 }
1028 else
1029 {
1030 mPages.push_back(page);
1031 }
1032 child = child->next_sibling("page");
1033 }
1034 if (mPages.size() > 0)
1035 return 0;
1036 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001037}
1038
1039int PageSet::IsCurrentPage(Page* page)
1040{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001041 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001042}
1043
1044int PageSet::Render(void)
1045{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001046 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001047
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001048 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1049 if (ret < 0)
1050 return ret;
1051 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
1052 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001053}
1054
1055int PageSet::Update(void)
1056{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001057 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001058
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001059 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1060 if (ret < 0 || ret > 1)
1061 return ret;
1062 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
1063 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001064}
1065
1066int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1067{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001068 if (mOverlayPage)
1069 return (mOverlayPage->NotifyTouch(state, x, y));
1070
1071 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001072}
1073
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001074int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001075{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001076 if (mOverlayPage)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001077 return (mOverlayPage->NotifyKey(key, down));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001078
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001079 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001080}
1081
1082int PageSet::NotifyKeyboard(int key)
1083{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001084 if (mOverlayPage)
1085 return (mOverlayPage->NotifyKeyboard(key));
1086
1087 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001088}
1089
1090int PageSet::SetKeyBoardFocus(int inFocus)
1091{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001092 if (mOverlayPage)
1093 return (mOverlayPage->SetKeyBoardFocus(inFocus));
1094
1095 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001096}
1097
1098int PageSet::NotifyVarChange(std::string varName, std::string value)
1099{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001100 if (mOverlayPage)
1101 mOverlayPage->NotifyVarChange(varName, value);
1102
1103 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001104}
1105
1106int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1107{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001108 int fd;
1109 ZipArchive zip, *pZip = NULL;
1110 long len;
1111 char* xmlFile = NULL;
1112 PageSet* pageSet = NULL;
1113 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001114 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001115
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001116 // Open the XML file
1117 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001118 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001119 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001120 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001121 tw_x_offset = TW_X_OFFSET;
1122 tw_y_offset = TW_Y_OFFSET;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001123 // We can try to load the XML directly...
1124 struct stat st;
1125 if(stat(package.c_str(),&st) != 0)
1126 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001127
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001128 len = st.st_size;
1129 xmlFile = (char*) malloc(len + 1);
1130 if (!xmlFile)
1131 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001132
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001133 fd = open(package.c_str(), O_RDONLY);
1134 if (fd == -1)
1135 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -04001136
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001137 read(fd, xmlFile, len);
1138 close(fd);
1139 }
1140 else
1141 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001142 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001143 tw_x_offset = 0;
1144 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001145 if (!TWFunc::Path_Exists(package))
1146 return -1;
1147 if (sysMapFile(package.c_str(), &map) != 0) {
1148 LOGERR("Failed to map '%s'\n", package.c_str());
1149 return -1;
1150 }
1151 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1152 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1153 sysReleaseMap(&map);
1154 return -1;
1155 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001156 pZip = &zip;
1157 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
1158 if (ui_xml == NULL)
1159 {
1160 LOGERR("Unable to locate ui.xml in zip file\n");
1161 goto error;
1162 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001163
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001164 // Allocate the buffer for the file
1165 len = mzGetZipEntryUncompLen(ui_xml);
1166 xmlFile = (char*) malloc(len + 1);
1167 if (!xmlFile)
1168 goto error;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001169
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001170 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
1171 {
1172 LOGERR("Unable to extract ui.xml\n");
1173 goto error;
1174 }
1175 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001176
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001177 // NULL-terminate the string
1178 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -04001179
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001180 // Before loading, mCurrentSet must be the loading package so we can find resources
1181 pageSet = mCurrentSet;
1182 mCurrentSet = new PageSet(xmlFile);
1183
1184 ret = mCurrentSet->Load(pZip);
1185 if (ret == 0)
1186 {
1187 mCurrentSet->SetPage(startpage);
1188 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1189 }
1190 else
1191 {
1192 LOGERR("Package %s failed to load.\n", name.c_str());
1193 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001194
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001195 // The first successful package we loaded is the base
1196 if (mBaseSet == NULL)
1197 mBaseSet = mCurrentSet;
1198
1199 mCurrentSet = pageSet;
1200
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001201 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001202 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001203 sysReleaseMap(&map);
1204 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001205 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001206
1207error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001208 LOGERR("An internal error has occurred.\n");
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001209 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001210 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001211 sysReleaseMap(&map);
1212 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001213 if (xmlFile)
1214 free(xmlFile);
1215 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001216}
1217
1218PageSet* PageManager::FindPackage(std::string name)
1219{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001220 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001221
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001222 iter = mPageSets.find(name);
1223 if (iter != mPageSets.end())
1224 return (*iter).second;
1225
1226 LOGERR("Unable to locate package %s\n", name.c_str());
1227 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001228}
1229
1230PageSet* PageManager::SelectPackage(std::string name)
1231{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001232 LOGINFO("Switching packages (%s)\n", name.c_str());
1233 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001234
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001235 tmp = FindPackage(name);
1236 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001237 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001238 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001239 mCurrentSet->NotifyVarChange("", "");
1240 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001241 else
1242 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001243
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001244 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001245}
1246
1247int PageManager::ReloadPackage(std::string name, std::string package)
1248{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001249 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001250
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001251 iter = mPageSets.find(name);
1252 if (iter == mPageSets.end())
1253 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001254
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001255 if(mMouseCursor)
1256 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1257
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001258 PageSet* set = (*iter).second;
1259 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001261 if (LoadPackage(name, package, "main") != 0)
1262 {
Dees Troy3454ade2015-01-20 19:21:04 +00001263 LOGERR("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001264 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1265 return -1;
1266 }
1267 if (mCurrentSet == set)
1268 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001269 if (mBaseSet == set)
1270 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001271 delete set;
1272 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001273}
1274
1275void PageManager::ReleasePackage(std::string name)
1276{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001277 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001278
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001279 iter = mPageSets.find(name);
1280 if (iter == mPageSets.end())
1281 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001282
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001283 PageSet* set = (*iter).second;
1284 mPageSets.erase(iter);
1285 delete set;
1286 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001287}
1288
1289int PageManager::ChangePage(std::string name)
1290{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001291 DataManager::SetValue("tw_operation_state", 0);
1292 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1293 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001294}
1295
1296int PageManager::ChangeOverlay(std::string name)
1297{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001298 if (name.empty())
1299 return mCurrentSet->SetOverlay(NULL);
1300 else
1301 {
1302 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1303 return mCurrentSet->SetOverlay(page);
1304 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001305}
1306
1307Resource* PageManager::FindResource(std::string name)
1308{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001309 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001310}
1311
1312Resource* PageManager::FindResource(std::string package, std::string name)
1313{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001314 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001315
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001316 tmp = FindPackage(name);
1317 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001318}
1319
1320int PageManager::SwitchToConsole(void)
1321{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001322 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001323
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001324 mCurrentSet = console;
1325 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001326}
1327
Ethan Yonker03a42f62014-08-08 11:03:51 -05001328int PageManager::EndConsole(void)
1329{
1330 if (mCurrentSet && mBaseSet) {
1331 delete mCurrentSet;
1332 mCurrentSet = mBaseSet;
1333 return 0;
1334 }
1335 return -1;
1336}
1337
Dees_Troy51a0e822012-09-05 15:24:24 -04001338int PageManager::IsCurrentPage(Page* page)
1339{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001340 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001341}
1342
1343int PageManager::Render(void)
1344{
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001345 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1346 if(mMouseCursor)
1347 mMouseCursor->Render();
1348 return res;
1349}
1350
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001351HardwareKeyboard *PageManager::GetHardwareKeyboard()
1352{
1353 if(!mHardwareKeyboard)
1354 mHardwareKeyboard = new HardwareKeyboard();
1355 return mHardwareKeyboard;
1356}
1357
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001358xml_node<>* PageManager::FindStyle(std::string name)
1359{
1360 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1361 xml_node<>* node = (*itr)->first_node("style");
1362
1363 while (node) {
1364 if (!node->first_attribute("name"))
1365 continue;
1366
1367 if (name == node->first_attribute("name")->value())
1368 return node;
1369 node = node->next_sibling("style");
1370 }
1371 }
1372 return NULL;
1373}
1374
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001375MouseCursor *PageManager::GetMouseCursor()
1376{
1377 if(!mMouseCursor)
1378 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1379 return mMouseCursor;
1380}
1381
1382void PageManager::LoadCursorData(xml_node<>* node)
1383{
1384 if(!mMouseCursor)
1385 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1386
1387 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001388}
1389
1390int PageManager::Update(void)
1391{
thatfb759d42015-01-11 12:16:53 +01001392 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001393 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001394
1395 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1396
1397 if(mMouseCursor)
1398 {
1399 int c_res = mMouseCursor->Update();
1400 if(c_res > res)
1401 res = c_res;
1402 }
1403 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001404}
1405
1406int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1407{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001408 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001409}
1410
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001411int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001412{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001413 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001414}
1415
1416int PageManager::NotifyKeyboard(int key)
1417{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001418 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001419}
1420
1421int PageManager::SetKeyBoardFocus(int inFocus)
1422{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001423 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001424}
1425
1426int PageManager::NotifyVarChange(std::string varName, std::string value)
1427{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001428 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001429}
1430
1431extern "C" void gui_notifyVarChange(const char *name, const char* value)
1432{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001433 if (!gGuiRunning)
1434 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001435
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001436 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001437}