blob: 13f3bd7b50ab370a6822252020c7e31cf02dd7d9 [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"
Ethan Yonker74db1572015-10-28 12:44:49 -050036#include "../partitions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040037
38#include <string>
39
40extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042#include "../minuitwrp/minui.h"
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060043#include "../minzip/SysUtil.h"
44#include "../minzip/Zip.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060045#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040046}
47
48#include "rapidxml.hpp"
49#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020050#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040051
52extern int gGuiRunning;
53
Ethan Yonker74db1572015-10-28 12:44:49 -050054// From ../twrp.cpp
55extern bool datamedia;
56
57// From console.cpp
58extern size_t last_message_count;
59extern std::vector<std::string> gConsole;
60extern std::vector<std::string> gConsoleColor;
61
Dees_Troy51a0e822012-09-05 15:24:24 -040062std::map<std::string, PageSet*> PageManager::mPageSets;
63PageSet* PageManager::mCurrentSet;
64PageSet* PageManager::mBaseSet = NULL;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010065MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010066HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050067bool PageManager::mReloadTheme = false;
68std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050069std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040070
Ethan Yonker751a85e2014-12-12 16:59:10 -060071int tw_x_offset = 0;
72int tw_y_offset = 0;
73
Dees_Troy51a0e822012-09-05 15:24:24 -040074// Helper routine to convert a string to a color declaration
75int ConvertStrToColor(std::string str, COLOR* color)
76{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020077 // Set the default, solid black
78 memset(color, 0, sizeof(COLOR));
79 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040080
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020081 // Translate variables
82 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050083
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020084 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010085 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
87 else if (str == "red") { color->red = 255; return 0; }
88 else if (str == "green") { color->green = 255; return 0; }
89 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040090
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020091 // At this point, we require an RGB(A) color
92 if (str[0] != '#')
93 return -1;
94
95 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040096
Dees_Troy30b962e2012-10-19 20:48:59 -040097 int result;
98 if (str.size() >= 8) {
99 // We have alpha channel
100 string alpha = str.substr(6, 2);
101 result = strtol(alpha.c_str(), NULL, 16);
102 color->alpha = result & 0x000000FF;
103 str.resize(6);
104 result = strtol(str.c_str(), NULL, 16);
105 color->red = (result >> 16) & 0x000000FF;
106 color->green = (result >> 8) & 0x000000FF;
107 color->blue = result & 0x000000FF;
108 } else {
109 result = strtol(str.c_str(), NULL, 16);
110 color->red = (result >> 16) & 0x000000FF;
111 color->green = (result >> 8) & 0x000000FF;
112 color->blue = result & 0x000000FF;
113 }
114 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400115}
116
117// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600118xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
119{
that8d46c092015-02-26 01:30:04 +0100120 if (!parent)
121 return NULL;
122
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600123 xml_node<>* child = parent->first_node(nodename);
124 if (child)
125 return child;
126
127 if (depth == 10) {
128 LOGERR("Too many style loops detected.\n");
129 return NULL;
130 }
131
132 xml_node<>* style = parent->first_node("style");
133 if (style) {
134 while (style) {
135 if (!style->first_attribute("name")) {
136 LOGERR("No name given for style.\n");
137 continue;
138 } else {
139 std::string name = style->first_attribute("name")->value();
140 xml_node<>* node = PageManager::FindStyle(name);
141
142 if (node) {
143 // We found the style that was named
144 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
145 if (stylenode)
146 return stylenode;
147 }
148 }
149 style = style->next_sibling("style");
150 }
151 } else {
that54e9c832015-11-04 21:46:01 +0100152 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600153 xml_attribute<>* attr = parent->first_attribute("style");
154 // If no style is found anywhere else and the node wasn't found in the object itself
155 // as a special case we will search for a style that uses the same style name as the
156 // object type, so <object type="button"> would search for a style named "button"
157 if (!attr)
158 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100159 // if there's no attribute type, the object type must be the element name
160 std::string stylename = attr ? attr->value() : parent->name();
161 xml_node<>* node = PageManager::FindStyle(stylename);
162 if (node) {
163 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
164 if (stylenode)
165 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600166 }
167 }
168 return NULL;
169}
170
thatf6ed8fc2015-02-14 20:23:16 +0100171std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
172{
173 if (!element)
174 return defaultvalue;
175
176 xml_attribute<>* attr = element->first_attribute(attrname);
177 return attr ? attr->value() : defaultvalue;
178}
179
180int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
181{
182 string value = LoadAttrString(element, attrname);
183 // resolve variables
184 DataManager::GetValue(value, value);
185 return value.empty() ? defaultvalue : atoi(value.c_str());
186}
187
188int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
189{
190 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
191}
192
193int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
194{
195 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
196}
197
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600198COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100199{
200 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600201 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100202 // resolve variables
203 DataManager::GetValue(value, value);
204 COLOR ret = defaultvalue;
205 if (ConvertStrToColor(value, &ret) == 0)
206 return ret;
207 else
208 return defaultvalue;
209}
210
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600211COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
212{
213 bool found_color = false;
214 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
215}
216
thatf6ed8fc2015-02-14 20:23:16 +0100217FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
218{
219 std::string name = LoadAttrString(element, attrname, "");
220 if (name.empty())
221 return NULL;
222 else
that74ac6062015-03-04 22:39:34 +0100223 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100224}
225
226ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
227{
228 std::string name = LoadAttrString(element, attrname, "");
229 if (name.empty())
230 return NULL;
231 else
that74ac6062015-03-04 22:39:34 +0100232 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100233}
234
235AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
236{
237 std::string name = LoadAttrString(element, attrname, "");
238 if (name.empty())
239 return NULL;
240 else
that74ac6062015-03-04 22:39:34 +0100241 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100242}
243
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500244bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400245{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200246 if (!node)
247 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400248
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200249 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100250 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400251
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100253 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400254
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100256 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400257
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100259 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200261 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500262 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400263
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200264 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400265}
266
267int ActionObject::SetActionPos(int x, int y, int w, int h)
268{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200269 if (x < 0 || y < 0)
270 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400271
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500272 mActionX = x;
273 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200274 if (w || h)
275 {
276 mActionW = w;
277 mActionH = h;
278 }
279 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400280}
281
thatb63e2f92015-06-27 21:35:11 +0200282Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400283{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200284 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400285
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200286 // We can memset the whole structure, because the alpha channel is ignored
287 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400288
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200289 // With NULL, we make a console-only display
290 if (!page)
291 {
292 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400293
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200294 GUIConsole* element = new GUIConsole(NULL);
295 mRenders.push_back(element);
296 mActions.push_back(element);
297 return;
298 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400299
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200300 if (page->first_attribute("name"))
301 mName = page->first_attribute("name")->value();
302 else
303 {
304 LOGERR("No page name attribute found!\n");
305 return;
306 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400307
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200308 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400309
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200310 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200311 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400312}
313
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100314Page::~Page()
315{
316 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
317 delete *itr;
318}
319
thatb63e2f92015-06-27 21:35:11 +0200320bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400321{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200322 if (depth == 10)
323 {
324 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
325 return false;
326 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400327
thatb63e2f92015-06-27 21:35:11 +0200328 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200329 {
thatb63e2f92015-06-27 21:35:11 +0200330 std::string type = child->name();
331
332 if (type == "background") {
333 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
334 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200335 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400336
thatb63e2f92015-06-27 21:35:11 +0200337 if (type == "object") {
338 // legacy format : <object type="...">
339 xml_attribute<>* attr = child->first_attribute("type");
340 type = attr ? attr->value() : "*unspecified*";
341 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400342
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200343 if (type == "text")
344 {
345 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100346 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200347 mRenders.push_back(element);
348 mActions.push_back(element);
349 }
350 else if (type == "image")
351 {
352 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100353 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200354 mRenders.push_back(element);
355 }
356 else if (type == "fill")
357 {
358 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100359 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200360 mRenders.push_back(element);
361 }
362 else if (type == "action")
363 {
364 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100365 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200366 mActions.push_back(element);
367 }
368 else if (type == "console")
369 {
370 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100371 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200372 mRenders.push_back(element);
373 mActions.push_back(element);
374 }
375 else if (type == "button")
376 {
377 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100378 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200379 mRenders.push_back(element);
380 mActions.push_back(element);
381 }
382 else if (type == "checkbox")
383 {
384 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100385 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200386 mRenders.push_back(element);
387 mActions.push_back(element);
388 }
389 else if (type == "fileselector")
390 {
391 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100392 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200393 mRenders.push_back(element);
394 mActions.push_back(element);
395 }
396 else if (type == "animation")
397 {
398 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100399 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200400 mRenders.push_back(element);
401 }
402 else if (type == "progressbar")
403 {
404 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100405 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200406 mRenders.push_back(element);
407 mActions.push_back(element);
408 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400409 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200410 {
411 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100412 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 mRenders.push_back(element);
414 mActions.push_back(element);
415 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200416 else if (type == "slidervalue")
417 {
418 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100419 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200420 mRenders.push_back(element);
421 mActions.push_back(element);
422 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400423 else if (type == "listbox")
424 {
425 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100426 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400427 mRenders.push_back(element);
428 mActions.push_back(element);
429 }
430 else if (type == "keyboard")
431 {
432 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100433 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400434 mRenders.push_back(element);
435 mActions.push_back(element);
436 }
437 else if (type == "input")
438 {
439 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100440 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400441 mRenders.push_back(element);
442 mActions.push_back(element);
443 mInputs.push_back(element);
444 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500445 else if (type == "partitionlist")
446 {
447 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100448 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500449 mRenders.push_back(element);
450 mActions.push_back(element);
451 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100452 else if (type == "patternpassword")
453 {
454 GUIPatternPassword* element = new GUIPatternPassword(child);
455 mObjects.push_back(element);
456 mRenders.push_back(element);
457 mActions.push_back(element);
458 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500459 else if (type == "textbox")
460 {
461 GUITextBox* element = new GUITextBox(child);
462 mObjects.push_back(element);
463 mRenders.push_back(element);
464 mActions.push_back(element);
465 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200466 else if (type == "template")
467 {
468 if (!templates || !child->first_attribute("name"))
469 {
470 LOGERR("Invalid template request.\n");
471 }
472 else
473 {
474 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500475 xml_node<>* node;
476 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400477
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200478 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500479 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
480 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400481
Ethan Yonker780cd392014-07-21 15:24:39 -0500482 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200483 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500484 if (!node->first_attribute("name"))
485 continue;
486
487 if (name == node->first_attribute("name")->value())
488 {
489 if (!ProcessNode(node, templates, depth + 1))
490 return false;
491 else {
492 node_found = true;
493 break;
494 }
495 }
496 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200497 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500498 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200499 }
thatb63e2f92015-06-27 21:35:11 +0200500 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200501 }
502 }
503 }
504 else
505 {
thatb63e2f92015-06-27 21:35:11 +0200506 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200507 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200508 }
509 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400510}
511
512int Page::Render(void)
513{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200514 // Render background
515 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
516 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400517
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200518 // Render remaining objects
519 std::vector<RenderObject*>::iterator iter;
520 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
521 {
522 if ((*iter)->Render())
523 LOGERR("A render request has failed.\n");
524 }
525 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400526}
527
528int Page::Update(void)
529{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200530 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400531
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200532 std::vector<RenderObject*>::iterator iter;
533 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
534 {
535 int ret = (*iter)->Update();
536 if (ret < 0)
537 LOGERR("An update request has failed.\n");
538 else if (ret > retCode)
539 retCode = ret;
540 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400541
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200542 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400543}
544
545int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
546{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200547 // By default, return 1 to ignore further touches if nobody is listening
548 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400549
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 // Don't try to handle a lack of handlers
551 if (mActions.size() == 0)
552 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400553
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200554 // We record mTouchStart so we can pass all the touch stream to the same handler
555 if (state == TOUCH_START)
556 {
557 std::vector<ActionObject*>::reverse_iterator iter;
558 // We work backwards, from top-most element to bottom-most element
559 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
560 {
561 if ((*iter)->IsInRegion(x, y))
562 {
563 mTouchStart = (*iter);
564 ret = mTouchStart->NotifyTouch(state, x, y);
565 if (ret >= 0)
566 break;
567 mTouchStart = NULL;
568 }
569 }
570 }
571 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
572 {
573 ret = mTouchStart->NotifyTouch(state, x, y);
574 mTouchStart = NULL;
575 }
576 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
577 {
578 ret = mTouchStart->NotifyTouch(state, x, y);
579 }
580 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400581}
582
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100583int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400584{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400586
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200587 // Don't try to handle a lack of handlers
588 if (mActions.size() == 0)
589 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400590
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100591 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200592 // We work backwards, from top-most element to bottom-most element
593 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
594 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100595 ret = (*iter)->NotifyKey(key, down);
596 if (ret < 0) {
597 LOGERR("An action handler has returned an error\n");
598 ret = 1;
599 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200600 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100601 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400602}
603
604int Page::NotifyKeyboard(int key)
605{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200606 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400607
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 // Don't try to handle a lack of handlers
609 if (mInputs.size() == 0)
610 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400611
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200612 // We work backwards, from top-most element to bottom-most element
613 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
614 {
615 int ret = (*iter)->NotifyKeyboard(key);
616 if (ret == 0)
617 return 0;
618 else if (ret < 0)
619 LOGERR("A keyboard handler has returned an error");
620 }
621 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400622}
623
624int Page::SetKeyBoardFocus(int inFocus)
625{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200626 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400627
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628 // Don't try to handle a lack of handlers
629 if (mInputs.size() == 0)
630 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400631
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200632 // We work backwards, from top-most element to bottom-most element
633 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
634 {
635 int ret = (*iter)->SetInputFocus(inFocus);
636 if (ret == 0)
637 return 0;
638 else if (ret < 0)
639 LOGERR("An input focus handler has returned an error");
640 }
641 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400642}
643
644void Page::SetPageFocus(int inFocus)
645{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200646 // Render remaining objects
647 std::vector<RenderObject*>::iterator iter;
648 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
649 (*iter)->SetPageFocus(inFocus);
650
651 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400652}
653
654int Page::NotifyVarChange(std::string varName, std::string value)
655{
Vojtech Bocek07220562014-02-08 02:05:33 +0100656 std::vector<GUIObject*>::iterator iter;
657 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200658 {
659 if ((*iter)->NotifyVarChange(varName, value))
660 LOGERR("An action handler errored on NotifyVarChange.\n");
661 }
662 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400663}
664
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500665PageSet::PageSet(const char* xmlFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400666{
that74ac6062015-03-04 22:39:34 +0100667 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200668 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400669
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500670 if (!xmlFile)
thatb63e2f92015-06-27 21:35:11 +0200671 mCurrentPage = new Page(NULL, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400672}
673
674PageSet::~PageSet()
675{
Ethan Yonker1c273312015-03-16 12:18:56 -0500676 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100677 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
678 delete *itr;
679
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200680 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400681}
682
Ethan Yonker74db1572015-10-28 12:44:49 -0500683int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
684{
685 xml_document<> lang;
686 xml_node<>* parent;
687 xml_node<>* child;
688 std::string resource_source;
689
690 if (languageFile) {
691 printf("parsing languageFile\n");
692 lang.parse<0>(languageFile);
693 printf("parsing languageFile done\n");
694 } else {
695 return -1;
696 }
697
698 parent = lang.first_node("language");
699 if (!parent) {
700 LOGERR("Unable to locate language node in language file.\n");
701 lang.clear();
702 return -1;
703 }
704
705 child = parent->first_node("display");
706 if (child) {
707 DataManager::SetValue("tw_language_display", child->value());
708 resource_source = child->value();
709 } else {
710 LOGERR("language file does not have a display value set\n");
711 DataManager::SetValue("tw_language_display", "Not Set");
712 resource_source = languageFile;
713 }
714
715 child = parent->first_node("resources");
716 if (child)
717 mResources->LoadResources(child, package, resource_source);
718 else
719 return -1;
720 lang.clear();
721 return 0;
722}
723
724int PageSet::Load(ZipArchive* package, char* xmlFile, char* languageFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400725{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500726 xml_document<> mDoc;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200727 xml_node<>* parent;
728 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500729 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600730 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500731
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500732 mDoc.parse<0>(xmlFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200733 parent = mDoc.first_node("recovery");
734 if (!parent)
735 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400736
Ethan Yonker63e414f2015-02-06 15:44:39 -0600737 set_scale_values(1, 1); // Reset any previous scaling values
738
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200739 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600740 LOGINFO("Checking resolution...\n");
741 child = parent->first_node("details");
742 if (child) {
743 xml_node<>* resolution = child->first_node("resolution");
744 if (resolution) {
745 xml_attribute<>* width_attr = resolution->first_attribute("width");
746 xml_attribute<>* height_attr = resolution->first_attribute("height");
747 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
748 if (width_attr && height_attr && !noscale_attr) {
749 int width = atoi(width_attr->value());
750 int height = atoi(height_attr->value());
751 int offx = 0, offy = 0;
752#ifdef TW_ROUND_SCREEN
753 xml_node<>* roundscreen = child->first_node("roundscreen");
754 if (roundscreen) {
755 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
756 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
757 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
758 if (offx_attr) {
759 offx = atoi(offx_attr->value());
760 }
761 if (offy_attr) {
762 offy = atoi(offy_attr->value());
763 }
764 }
765#endif
766 if (width != 0 && height != 0) {
767 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
768 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
769#ifdef TW_ROUND_SCREEN
770 float scale_off_w = (float)gr_fb_width() / (float)width;
771 float scale_off_h = (float)gr_fb_height() / (float)height;
772 tw_x_offset = offx * scale_off_w;
773 tw_y_offset = offy * scale_off_h;
774#endif
775 if (scale_w != 1 || scale_h != 1) {
776 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
777 set_scale_values(scale_w, scale_h);
778 }
779 }
780 } else {
781 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
782 }
783 } else {
784 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
785 }
786 } else {
787 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
788 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500789
790 if (languageFile)
791 LoadLanguage(languageFile, package);
792
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200793 LOGINFO("Loading resources...\n");
794 child = parent->first_node("resources");
795 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500796 mResources->LoadResources(child, package, "theme");
Dees_Troy51a0e822012-09-05 15:24:24 -0400797
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200798 LOGINFO("Loading variables...\n");
799 child = parent->first_node("variables");
800 if (child)
801 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400802
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100803 LOGINFO("Loading mouse cursor...\n");
804 child = parent->first_node("mousecursor");
805 if(child)
806 PageManager::LoadCursorData(child);
807
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200808 LOGINFO("Loading pages...\n");
809 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500810 xmltemplate = parent->first_node("templates");
811 if (xmltemplate)
812 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400813
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600814 // Load styles if present
815 xmlstyle = parent->first_node("styles");
816 if (xmlstyle)
817 styles.push_back(xmlstyle);
818
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200819 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500820 if (child) {
821 if (LoadPages(child)) {
822 LOGERR("PageSet::Load returning -1\n");
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500823 mDoc.clear();
Ethan Yonker780cd392014-07-21 15:24:39 -0500824 return -1;
825 }
826 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100827
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500828 int ret = CheckInclude(package, &mDoc);
829 mDoc.clear();
830 templates.clear();
831 return ret;
Ethan Yonker780cd392014-07-21 15:24:39 -0500832}
Dees_Troy51a0e822012-09-05 15:24:24 -0400833
Ethan Yonker780cd392014-07-21 15:24:39 -0500834int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
835{
836 xml_node<>* par;
837 xml_node<>* par2;
838 xml_node<>* chld;
839 xml_node<>* parent;
840 xml_node<>* child;
841 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600842 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500843 long len;
844 char* xmlFile = NULL;
845 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100846 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500847
848 par = parentDoc->first_node("recovery");
849 if (!par) {
850 par = parentDoc->first_node("install");
851 }
852 if (!par) {
853 return 0;
854 }
855
856 par2 = par->first_node("include");
857 if (!par2)
858 return 0;
859 chld = par2->first_node("xmlfile");
860 while (chld != NULL) {
861 xml_attribute<>* attr = chld->first_attribute("name");
862 if (!attr)
863 break;
864
Ethan Yonker780cd392014-07-21 15:24:39 -0500865 if (!package) {
866 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000867 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500868 filename += attr->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500869 } else {
870 filename += attr->value();
Ethan Yonker561c58d2015-10-05 08:48:22 -0500871 }
872 xmlFile = PageManager::LoadFileToBuffer(filename, package);
873 if (xmlFile == NULL) {
874 LOGERR("PageSet::CheckInclude unable to load '%s'\n", filename.c_str());
875 return -1;
Ethan Yonker780cd392014-07-21 15:24:39 -0500876 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500877
Vojtech Boceke979abd2015-01-12 18:29:12 +0100878 doc = new xml_document<>();
879 doc->parse<0>(xmlFile);
880
881 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500882 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100883 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500884
885 // Now, let's parse the XML
886 LOGINFO("Loading included resources...\n");
887 child = parent->first_node("resources");
888 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500889 mResources->LoadResources(child, package, "theme");
Ethan Yonker780cd392014-07-21 15:24:39 -0500890
891 LOGINFO("Loading included variables...\n");
892 child = parent->first_node("variables");
893 if (child)
894 LoadVariables(child);
895
896 LOGINFO("Loading mouse cursor...\n");
897 child = parent->first_node("mousecursor");
898 if(child)
899 PageManager::LoadCursorData(child);
900
901 LOGINFO("Loading included pages...\n");
902 // This may be NULL if no templates are present
903 xmltemplate = parent->first_node("templates");
904 if (xmltemplate)
905 templates.push_back(xmltemplate);
906
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600907 // Load styles if present
908 xmlstyle = parent->first_node("styles");
909 if (xmlstyle)
910 styles.push_back(xmlstyle);
911
Ethan Yonker780cd392014-07-21 15:24:39 -0500912 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100913 if (child && LoadPages(child))
914 {
915 templates.pop_back();
916 doc->clear();
917 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500918 free(xmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100919 return -1;
920 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500921
Ethan Yonker561c58d2015-10-05 08:48:22 -0500922 if (CheckInclude(package, doc)) {
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500923 doc->clear();
924 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500925 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500926 return -1;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500927 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500928 doc->clear();
929 delete doc;
930 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500931
932 chld = chld->next_sibling("xmlfile");
933 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500934
Ethan Yonker780cd392014-07-21 15:24:39 -0500935 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400936}
937
938int PageSet::SetPage(std::string page)
939{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200940 Page* tmp = FindPage(page);
941 if (tmp)
942 {
943 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
944 mCurrentPage = tmp;
945 mCurrentPage->SetPageFocus(1);
946 mCurrentPage->NotifyVarChange("", "");
947 return 0;
948 }
949 else
950 {
951 LOGERR("Unable to locate page (%s)\n", page.c_str());
952 }
953 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400954}
955
956int PageSet::SetOverlay(Page* page)
957{
Ethan Yonker1c273312015-03-16 12:18:56 -0500958 if (page) {
959 if (mOverlays.size() >= 10) {
960 LOGERR("Too many overlays requested, max is 10.\n");
961 return -1;
962 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500963
964 std::vector<Page*>::iterator iter;
965 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
966 if ((*iter)->GetName() == page->GetName()) {
967 mOverlays.erase(iter);
968 // SetOverlay() is (and should stay) the only function which
969 // adds to mOverlays. Then, each page can appear at most once.
970 break;
971 }
972 }
973
Ethan Yonker1c273312015-03-16 12:18:56 -0500974 page->SetPageFocus(1);
975 page->NotifyVarChange("", "");
976
977 if (!mOverlays.empty())
978 mOverlays.back()->SetPageFocus(0);
979
980 mOverlays.push_back(page);
981 } else {
982 if (!mOverlays.empty()) {
983 mOverlays.back()->SetPageFocus(0);
984 mOverlays.pop_back();
985 if (!mOverlays.empty())
986 mOverlays.back()->SetPageFocus(1);
987 else if (mCurrentPage)
988 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
989 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200990 }
991 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400992}
993
that74ac6062015-03-04 22:39:34 +0100994const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400995{
that74ac6062015-03-04 22:39:34 +0100996 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400997}
998
999Page* PageSet::FindPage(std::string name)
1000{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001001 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001002
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001003 for (iter = mPages.begin(); iter != mPages.end(); iter++)
1004 {
1005 if (name == (*iter)->GetName())
1006 return (*iter);
1007 }
1008 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001009}
1010
1011int PageSet::LoadVariables(xml_node<>* vars)
1012{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001013 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001014 xml_attribute<> *name, *value, *persist;
1015 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001016
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001017 child = vars->first_node("variable");
1018 while (child)
1019 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001020 name = child->first_attribute("name");
1021 value = child->first_attribute("value");
1022 persist = child->first_attribute("persist");
1023 if(name && value)
1024 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001025 if (strcmp(name->value(), "tw_x_offset") == 0) {
1026 tw_x_offset = atoi(value->value());
1027 child = child->next_sibling("variable");
1028 continue;
1029 }
1030 if (strcmp(name->value(), "tw_y_offset") == 0) {
1031 tw_y_offset = atoi(value->value());
1032 child = child->next_sibling("variable");
1033 continue;
1034 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001035 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001036 string temp = value->value();
1037 string valstr = gui_parse_text(temp);
1038
1039 if (valstr.find("+") != string::npos) {
1040 string val1str = valstr;
1041 val1str = val1str.substr(0, val1str.find('+'));
1042 string val2str = valstr;
1043 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1044 int val1 = atoi(val1str.c_str());
1045 int val2 = atoi(val2str.c_str());
1046 int val = val1 + val2;
1047
1048 DataManager::SetValue(name->value(), val, p);
1049 } else if (valstr.find("-") != string::npos) {
1050 string val1str = valstr;
1051 val1str = val1str.substr(0, val1str.find('-'));
1052 string val2str = valstr;
1053 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1054 int val1 = atoi(val1str.c_str());
1055 int val2 = atoi(val2str.c_str());
1056 int val = val1 - val2;
1057
1058 DataManager::SetValue(name->value(), val, p);
1059 } else {
1060 DataManager::SetValue(name->value(), valstr, p);
1061 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001062 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001063
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001064 child = child->next_sibling("variable");
1065 }
1066 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001067}
1068
Ethan Yonker780cd392014-07-21 15:24:39 -05001069int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001070{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001071 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001072
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001073 if (!pages)
1074 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001075
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001076 child = pages->first_node("page");
1077 while (child != NULL)
1078 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001079 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001080 if (page->GetName().empty())
1081 {
1082 LOGERR("Unable to process load page\n");
1083 delete page;
1084 }
1085 else
1086 {
1087 mPages.push_back(page);
1088 }
1089 child = child->next_sibling("page");
1090 }
1091 if (mPages.size() > 0)
1092 return 0;
1093 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001094}
1095
1096int PageSet::IsCurrentPage(Page* page)
1097{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001098 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001099}
1100
1101int PageSet::Render(void)
1102{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001103 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001104
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001105 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1106 if (ret < 0)
1107 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001108
1109 std::vector<Page*>::iterator iter;
1110
1111 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1112 ret = ((*iter) ? (*iter)->Render() : -1);
1113 if (ret < 0)
1114 return ret;
1115 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001116 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001117}
1118
1119int PageSet::Update(void)
1120{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001121 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001122
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001123 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1124 if (ret < 0 || ret > 1)
1125 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001126
1127 std::vector<Page*>::iterator iter;
1128
1129 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1130 ret = ((*iter) ? (*iter)->Update() : -1);
1131 if (ret < 0)
1132 return ret;
1133 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001134 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001135}
1136
1137int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1138{
Ethan Yonker1c273312015-03-16 12:18:56 -05001139 if (!mOverlays.empty())
1140 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001141
1142 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001143}
1144
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001145int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001146{
Ethan Yonker1c273312015-03-16 12:18:56 -05001147 if (!mOverlays.empty())
1148 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001149
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001150 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001151}
1152
1153int PageSet::NotifyKeyboard(int key)
1154{
Ethan Yonker1c273312015-03-16 12:18:56 -05001155 if (!mOverlays.empty())
1156 return mOverlays.back()->NotifyKeyboard(key);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001157
1158 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001159}
1160
1161int PageSet::SetKeyBoardFocus(int inFocus)
1162{
Ethan Yonker1c273312015-03-16 12:18:56 -05001163 if (!mOverlays.empty())
1164 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001165
1166 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001167}
1168
1169int PageSet::NotifyVarChange(std::string varName, std::string value)
1170{
Ethan Yonker1c273312015-03-16 12:18:56 -05001171 std::vector<Page*>::iterator iter;
1172
1173 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1174 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001175
1176 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001177}
1178
Ethan Yonker74db1572015-10-28 12:44:49 -05001179void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1180{
1181 mResources->AddStringResource(resource_source, resource_name, value);
1182}
1183
Ethan Yonker561c58d2015-10-05 08:48:22 -05001184char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
1185 size_t len;
1186 char* buffer = NULL;
1187
1188 if (!package) {
1189 // We can try to load the XML directly...
1190 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1191 struct stat st;
1192 if(stat(filename.c_str(),&st) != 0) {
1193 // This isn't always an error, sometimes we request files that don't exist.
1194 return NULL;
1195 }
1196
1197 len = (size_t)st.st_size;
1198
1199 buffer = (char*) malloc(len + 1);
1200 if (!buffer) {
1201 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1202 return NULL;
1203 }
1204
1205 int fd = open(filename.c_str(), O_RDONLY);
1206 if (fd == -1) {
1207 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1208 free(buffer);
1209 return NULL;
1210 }
1211
1212 if (read(fd, buffer, len) < 0) {
1213 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1214 free(buffer);
1215 close(fd);
1216 return NULL;
1217 }
1218 close(fd);
1219 } else {
1220 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
1221 const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
1222 if (zipentry == NULL) {
1223 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1224 return NULL;
1225 }
1226
1227 // Allocate the buffer for the file
1228 len = mzGetZipEntryUncompLen(zipentry);
1229 buffer = (char*) malloc(len + 1);
1230 if (!buffer)
1231 return NULL;
1232
1233 if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
1234 LOGERR("Unable to extract '%s'\n", filename.c_str());
1235 free(buffer);
1236 return NULL;
1237 }
1238 }
1239 // NULL-terminate the string
1240 buffer[len] = 0x00;
1241 return buffer;
1242}
1243
Ethan Yonker74db1572015-10-28 12:44:49 -05001244void PageManager::LoadLanguageListDir(string dir) {
1245 if (!TWFunc::Path_Exists(dir)) {
1246 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1247 return;
1248 }
1249
1250 DIR *d = opendir(dir.c_str());
1251 struct dirent *p;
1252
1253 if (d == NULL) {
1254 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1255 return;
1256 }
1257
1258 while ((p = readdir(d))) {
1259 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1260 continue;
1261
1262 string file = p->d_name;
1263 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1264 continue;
1265 string path = dir + p->d_name;
1266 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1267 struct language_struct language_entry;
1268 language_entry.filename = file_no_extn;
1269 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1270 if (xmlFile == NULL) {
1271 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1272 continue;
1273 }
1274 xml_document<> *doc = new xml_document<>();
1275 doc->parse<0>(xmlFile);
1276
1277 xml_node<>* parent = doc->first_node("language");
1278 if (!parent) {
1279 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1280 } else {
1281 xml_node<>* child = parent->first_node("display");
1282 if (child) {
1283 language_entry.displayvalue = child->value();
1284 } else {
1285 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1286 language_entry.displayvalue = language_entry.filename;
1287 }
1288 Language_List.push_back(language_entry);
1289 }
1290 doc->clear();
1291 delete doc;
1292 free(xmlFile);
1293 }
1294 closedir(d);
1295}
1296
1297void PageManager::LoadLanguageList(ZipArchive* package) {
1298 Language_List.clear();
1299 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1300 TWFunc::removeDir(TWRES "customlanguages", true);
1301 if (package) {
1302 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
1303 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
1304 mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
1305 LoadLanguageListDir(TWRES "customlanguages/");
1306 } else {
1307 LoadLanguageListDir(TWRES "languages/");
1308 }
1309}
1310
1311void PageManager::LoadLanguage(string filename) {
1312 string actual_filename;
1313 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1314 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1315 else
1316 actual_filename = TWRES "languages/" + filename + ".xml";
1317 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1318 if (xmlFile == NULL)
1319 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1320 else {
1321 mCurrentSet->LoadLanguage(xmlFile, NULL);
1322 free(xmlFile);
1323 }
1324 PartitionManager.Translate_Partition_Display_Names();
1325}
1326
Dees_Troy51a0e822012-09-05 15:24:24 -04001327int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1328{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001329 int fd;
1330 ZipArchive zip, *pZip = NULL;
1331 long len;
1332 char* xmlFile = NULL;
Ethan Yonker74db1572015-10-28 12:44:49 -05001333 char* languageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001334 PageSet* pageSet = NULL;
1335 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001336 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001337
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001338 mReloadTheme = false;
1339 mStartPage = startpage;
1340
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001341 // Open the XML file
1342 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001343 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001344 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001345 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001346 tw_x_offset = TW_X_OFFSET;
1347 tw_y_offset = TW_Y_OFFSET;
Ethan Yonker74db1572015-10-28 12:44:49 -05001348 LoadLanguageList(NULL);
1349 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001350 }
1351 else
1352 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001353 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001354 tw_x_offset = 0;
1355 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001356 if (!TWFunc::Path_Exists(package))
1357 return -1;
1358 if (sysMapFile(package.c_str(), &map) != 0) {
1359 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001360 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001361 }
1362 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1363 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1364 sysReleaseMap(&map);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001365 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001366 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001367 pZip = &zip;
Ethan Yonker561c58d2015-10-05 08:48:22 -05001368 package = "ui.xml";
Ethan Yonker74db1572015-10-28 12:44:49 -05001369 LoadLanguageList(pZip);
1370 languageFile = LoadFileToBuffer("languages/en.xml", pZip);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001371 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001372
Ethan Yonker561c58d2015-10-05 08:48:22 -05001373 xmlFile = LoadFileToBuffer(package, pZip);
1374 if (xmlFile == NULL) {
1375 goto error;
1376 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001377
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001378 // Before loading, mCurrentSet must be the loading package so we can find resources
1379 pageSet = mCurrentSet;
1380 mCurrentSet = new PageSet(xmlFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001381 ret = mCurrentSet->Load(pZip, xmlFile, languageFile);
1382 if (languageFile) {
1383 free(languageFile);
1384 languageFile = NULL;
1385 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001386 if (ret == 0)
1387 {
1388 mCurrentSet->SetPage(startpage);
1389 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1390 }
1391 else
1392 {
1393 LOGERR("Package %s failed to load.\n", name.c_str());
1394 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001395
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001396 // The first successful package we loaded is the base
1397 if (mBaseSet == NULL)
1398 mBaseSet = mCurrentSet;
1399
1400 mCurrentSet = pageSet;
1401
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001402 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001403 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001404 sysReleaseMap(&map);
1405 }
Ethan Yonker561c58d2015-10-05 08:48:22 -05001406 free(xmlFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001407 if (languageFile)
1408 free(languageFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001409 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001410
1411error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001412 // Sometimes we get here without a real error
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001413 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001414 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001415 sysReleaseMap(&map);
1416 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001417 if (xmlFile)
1418 free(xmlFile);
1419 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001420}
1421
1422PageSet* PageManager::FindPackage(std::string name)
1423{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001424 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001425
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001426 iter = mPageSets.find(name);
1427 if (iter != mPageSets.end())
1428 return (*iter).second;
1429
1430 LOGERR("Unable to locate package %s\n", name.c_str());
1431 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001432}
1433
1434PageSet* PageManager::SelectPackage(std::string name)
1435{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001436 LOGINFO("Switching packages (%s)\n", name.c_str());
1437 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001438
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001439 tmp = FindPackage(name);
1440 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001441 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001442 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001443 mCurrentSet->NotifyVarChange("", "");
1444 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001445 else
1446 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001447
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001448 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001449}
1450
1451int PageManager::ReloadPackage(std::string name, std::string package)
1452{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001453 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001454
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001455 mReloadTheme = false;
1456
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001457 iter = mPageSets.find(name);
1458 if (iter == mPageSets.end())
1459 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001460
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001461 if(mMouseCursor)
1462 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1463
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001464 PageSet* set = (*iter).second;
1465 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001466
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001467 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001469 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001470 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1471 return -1;
1472 }
1473 if (mCurrentSet == set)
1474 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001475 if (mBaseSet == set)
1476 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001477 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001478 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001479 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001480}
1481
1482void PageManager::ReleasePackage(std::string name)
1483{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001484 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001485
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001486 iter = mPageSets.find(name);
1487 if (iter == mPageSets.end())
1488 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001489
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001490 PageSet* set = (*iter).second;
1491 mPageSets.erase(iter);
1492 delete set;
1493 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001494}
1495
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001496int PageManager::RunReload() {
1497 int ret_val = 0;
1498 std::string theme_path;
1499
1500 if (!mReloadTheme)
1501 return 0;
1502
1503 mReloadTheme = false;
1504 theme_path = DataManager::GetSettingsStoragePath();
1505 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1506 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1507 ret_val = 1;
1508 }
1509
1510 theme_path += "/TWRP/theme/ui.zip";
1511 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1512 {
1513 // Loading the custom theme failed - try loading the stock theme
1514 LOGINFO("Attempting to reload stock theme...\n");
1515 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1516 {
1517 LOGERR("Failed to load base packages.\n");
1518 ret_val = 1;
1519 }
1520 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001521 if (ret_val == 0) {
1522 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1523 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1524 LoadLanguage(DataManager::GetStrValue("tw_language"));
1525 }
1526 }
1527
1528 // This makes the console re-translate
1529 last_message_count = 0;
1530 gConsole.clear();
1531 gConsoleColor.clear();
1532
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001533 return ret_val;
1534}
1535
1536void PageManager::RequestReload() {
1537 mReloadTheme = true;
1538}
1539
Dees_Troy51a0e822012-09-05 15:24:24 -04001540int PageManager::ChangePage(std::string name)
1541{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001542 DataManager::SetValue("tw_operation_state", 0);
1543 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1544 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001545}
1546
1547int PageManager::ChangeOverlay(std::string name)
1548{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001549 if (name.empty())
1550 return mCurrentSet->SetOverlay(NULL);
1551 else
1552 {
1553 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1554 return mCurrentSet->SetOverlay(page);
1555 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001556}
1557
that74ac6062015-03-04 22:39:34 +01001558const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001559{
that74ac6062015-03-04 22:39:34 +01001560 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001561}
1562
1563int PageManager::SwitchToConsole(void)
1564{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001565 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001566
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001567 mCurrentSet = console;
1568 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001569}
1570
Ethan Yonker03a42f62014-08-08 11:03:51 -05001571int PageManager::EndConsole(void)
1572{
1573 if (mCurrentSet && mBaseSet) {
1574 delete mCurrentSet;
1575 mCurrentSet = mBaseSet;
1576 return 0;
1577 }
1578 return -1;
1579}
1580
Dees_Troy51a0e822012-09-05 15:24:24 -04001581int PageManager::IsCurrentPage(Page* page)
1582{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001583 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001584}
1585
1586int PageManager::Render(void)
1587{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001588 if(blankTimer.isScreenOff())
1589 return 0;
1590
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001591 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1592 if(mMouseCursor)
1593 mMouseCursor->Render();
1594 return res;
1595}
1596
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001597HardwareKeyboard *PageManager::GetHardwareKeyboard()
1598{
1599 if(!mHardwareKeyboard)
1600 mHardwareKeyboard = new HardwareKeyboard();
1601 return mHardwareKeyboard;
1602}
1603
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001604xml_node<>* PageManager::FindStyle(std::string name)
1605{
1606 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1607 xml_node<>* node = (*itr)->first_node("style");
1608
1609 while (node) {
1610 if (!node->first_attribute("name"))
1611 continue;
1612
1613 if (name == node->first_attribute("name")->value())
1614 return node;
1615 node = node->next_sibling("style");
1616 }
1617 }
1618 return NULL;
1619}
1620
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001621MouseCursor *PageManager::GetMouseCursor()
1622{
1623 if(!mMouseCursor)
1624 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1625 return mMouseCursor;
1626}
1627
1628void PageManager::LoadCursorData(xml_node<>* node)
1629{
1630 if(!mMouseCursor)
1631 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1632
1633 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001634}
1635
1636int PageManager::Update(void)
1637{
thatfb759d42015-01-11 12:16:53 +01001638 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001639 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001640
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001641 if (RunReload())
1642 return -2;
1643
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001644 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1645
1646 if(mMouseCursor)
1647 {
1648 int c_res = mMouseCursor->Update();
1649 if(c_res > res)
1650 res = c_res;
1651 }
1652 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001653}
1654
1655int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1656{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001657 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001658}
1659
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001660int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001661{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001662 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001663}
1664
1665int PageManager::NotifyKeyboard(int key)
1666{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001667 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001668}
1669
1670int PageManager::SetKeyBoardFocus(int inFocus)
1671{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001672 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001673}
1674
1675int PageManager::NotifyVarChange(std::string varName, std::string value)
1676{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001677 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001678}
1679
Ethan Yonker74db1572015-10-28 12:44:49 -05001680void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1681{
1682 if (mCurrentSet)
1683 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1684}
1685
Dees_Troy51a0e822012-09-05 15:24:24 -04001686extern "C" void gui_notifyVarChange(const char *name, const char* value)
1687{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001688 if (!gGuiRunning)
1689 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001690
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001691 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001692}