blob: b6b72966a641ebd59e59d0f7058b9dacee72117b [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 Yonker3fdcda42016-11-30 12:29:37 -060035#include <dirent.h>
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060036#include "../twrp-functions.hpp"
Ethan Yonker74db1572015-10-28 12:44:49 -050037#include "../partitions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040038
39#include <string>
Xuefercac6ace2016-02-01 02:28:55 +080040#include <algorithm>
Dees_Troy51a0e822012-09-05 15:24:24 -040041
42extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000043#include "../twcommon.h"
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060044#include "../minzip/SysUtil.h"
45#include "../minzip/Zip.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060046#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040047}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010048#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040049
50#include "rapidxml.hpp"
51#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020052#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040053
Ethan Yonker1308d532016-01-14 22:21:49 -060054#define TW_THEME_VERSION 1
Ethan Yonker8e5692f2016-01-21 11:21:06 -060055#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060056
Dees_Troy51a0e822012-09-05 15:24:24 -040057extern int gGuiRunning;
58
Ethan Yonker74db1572015-10-28 12:44:49 -050059// From console.cpp
60extern size_t last_message_count;
61extern std::vector<std::string> gConsole;
62extern std::vector<std::string> gConsoleColor;
63
Dees_Troy51a0e822012-09-05 15:24:24 -040064std::map<std::string, PageSet*> PageManager::mPageSets;
65PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010066MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010067HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050068bool PageManager::mReloadTheme = false;
69std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050070std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040071
Ethan Yonker751a85e2014-12-12 16:59:10 -060072int tw_x_offset = 0;
73int tw_y_offset = 0;
74
Dees_Troy51a0e822012-09-05 15:24:24 -040075// Helper routine to convert a string to a color declaration
76int ConvertStrToColor(std::string str, COLOR* color)
77{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020078 // Set the default, solid black
79 memset(color, 0, sizeof(COLOR));
80 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040081
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020082 // Translate variables
83 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050084
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020085 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010086 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
88 else if (str == "red") { color->red = 255; return 0; }
89 else if (str == "green") { color->green = 255; return 0; }
90 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040091
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020092 // At this point, we require an RGB(A) color
93 if (str[0] != '#')
94 return -1;
95
96 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040097
Dees_Troy30b962e2012-10-19 20:48:59 -040098 int result;
99 if (str.size() >= 8) {
100 // We have alpha channel
101 string alpha = str.substr(6, 2);
102 result = strtol(alpha.c_str(), NULL, 16);
103 color->alpha = result & 0x000000FF;
104 str.resize(6);
105 result = strtol(str.c_str(), NULL, 16);
106 color->red = (result >> 16) & 0x000000FF;
107 color->green = (result >> 8) & 0x000000FF;
108 color->blue = result & 0x000000FF;
109 } else {
110 result = strtol(str.c_str(), NULL, 16);
111 color->red = (result >> 16) & 0x000000FF;
112 color->green = (result >> 8) & 0x000000FF;
113 color->blue = result & 0x000000FF;
114 }
115 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400116}
117
118// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600119xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
120{
that8d46c092015-02-26 01:30:04 +0100121 if (!parent)
122 return NULL;
123
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600124 xml_node<>* child = parent->first_node(nodename);
125 if (child)
126 return child;
127
128 if (depth == 10) {
129 LOGERR("Too many style loops detected.\n");
130 return NULL;
131 }
132
133 xml_node<>* style = parent->first_node("style");
134 if (style) {
135 while (style) {
136 if (!style->first_attribute("name")) {
137 LOGERR("No name given for style.\n");
138 continue;
139 } else {
140 std::string name = style->first_attribute("name")->value();
141 xml_node<>* node = PageManager::FindStyle(name);
142
143 if (node) {
144 // We found the style that was named
145 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
146 if (stylenode)
147 return stylenode;
148 }
149 }
150 style = style->next_sibling("style");
151 }
152 } else {
that54e9c832015-11-04 21:46:01 +0100153 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600154 xml_attribute<>* attr = parent->first_attribute("style");
155 // If no style is found anywhere else and the node wasn't found in the object itself
156 // as a special case we will search for a style that uses the same style name as the
157 // object type, so <object type="button"> would search for a style named "button"
158 if (!attr)
159 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100160 // if there's no attribute type, the object type must be the element name
161 std::string stylename = attr ? attr->value() : parent->name();
162 xml_node<>* node = PageManager::FindStyle(stylename);
163 if (node) {
164 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
165 if (stylenode)
166 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600167 }
168 }
169 return NULL;
170}
171
thatf6ed8fc2015-02-14 20:23:16 +0100172std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
173{
174 if (!element)
175 return defaultvalue;
176
177 xml_attribute<>* attr = element->first_attribute(attrname);
178 return attr ? attr->value() : defaultvalue;
179}
180
181int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
182{
183 string value = LoadAttrString(element, attrname);
184 // resolve variables
185 DataManager::GetValue(value, value);
186 return value.empty() ? defaultvalue : atoi(value.c_str());
187}
188
189int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
190{
191 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
192}
193
194int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
195{
196 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
197}
198
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600199COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100200{
201 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600202 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100203 // resolve variables
204 DataManager::GetValue(value, value);
205 COLOR ret = defaultvalue;
206 if (ConvertStrToColor(value, &ret) == 0)
207 return ret;
208 else
209 return defaultvalue;
210}
211
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600212COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
213{
214 bool found_color = false;
215 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
216}
217
thatf6ed8fc2015-02-14 20:23:16 +0100218FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
219{
220 std::string name = LoadAttrString(element, attrname, "");
221 if (name.empty())
222 return NULL;
223 else
that74ac6062015-03-04 22:39:34 +0100224 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100225}
226
227ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
228{
229 std::string name = LoadAttrString(element, attrname, "");
230 if (name.empty())
231 return NULL;
232 else
that74ac6062015-03-04 22:39:34 +0100233 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100234}
235
236AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
237{
238 std::string name = LoadAttrString(element, attrname, "");
239 if (name.empty())
240 return NULL;
241 else
that74ac6062015-03-04 22:39:34 +0100242 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100243}
244
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500245bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400246{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200247 if (!node)
248 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400249
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200250 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100251 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400252
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200253 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100254 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400255
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200256 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100257 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400258
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200259 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100260 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400261
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200262 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500263 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400264
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200265 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400266}
267
268int ActionObject::SetActionPos(int x, int y, int w, int h)
269{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200270 if (x < 0 || y < 0)
271 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400272
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500273 mActionX = x;
274 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 if (w || h)
276 {
277 mActionW = w;
278 mActionH = h;
279 }
280 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400281}
282
thatb63e2f92015-06-27 21:35:11 +0200283Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400284{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200285 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400286
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200287 // We can memset the whole structure, because the alpha channel is ignored
288 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400289
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200290 // With NULL, we make a console-only display
291 if (!page)
292 {
293 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400294
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200295 GUIConsole* element = new GUIConsole(NULL);
296 mRenders.push_back(element);
297 mActions.push_back(element);
298 return;
299 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400300
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200301 if (page->first_attribute("name"))
302 mName = page->first_attribute("name")->value();
303 else
304 {
305 LOGERR("No page name attribute found!\n");
306 return;
307 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400308
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200309 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400310
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200311 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200312 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400313}
314
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100315Page::~Page()
316{
317 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
318 delete *itr;
319}
320
thatb63e2f92015-06-27 21:35:11 +0200321bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400322{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200323 if (depth == 10)
324 {
325 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
326 return false;
327 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400328
thatb63e2f92015-06-27 21:35:11 +0200329 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200330 {
thatb63e2f92015-06-27 21:35:11 +0200331 std::string type = child->name();
332
333 if (type == "background") {
334 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
335 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200336 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400337
thatb63e2f92015-06-27 21:35:11 +0200338 if (type == "object") {
339 // legacy format : <object type="...">
340 xml_attribute<>* attr = child->first_attribute("type");
341 type = attr ? attr->value() : "*unspecified*";
342 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400343
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200344 if (type == "text")
345 {
346 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100347 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200348 mRenders.push_back(element);
349 mActions.push_back(element);
350 }
351 else if (type == "image")
352 {
353 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100354 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200355 mRenders.push_back(element);
356 }
357 else if (type == "fill")
358 {
359 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100360 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200361 mRenders.push_back(element);
362 }
363 else if (type == "action")
364 {
365 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100366 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200367 mActions.push_back(element);
368 }
369 else if (type == "console")
370 {
371 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100372 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200373 mRenders.push_back(element);
374 mActions.push_back(element);
375 }
that1964d192016-01-07 00:41:03 +0100376 else if (type == "terminal")
377 {
378 GUITerminal* element = new GUITerminal(child);
379 mObjects.push_back(element);
380 mRenders.push_back(element);
381 mActions.push_back(element);
382 mInputs.push_back(element);
383 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200384 else if (type == "button")
385 {
386 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100387 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200388 mRenders.push_back(element);
389 mActions.push_back(element);
390 }
391 else if (type == "checkbox")
392 {
393 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100394 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200395 mRenders.push_back(element);
396 mActions.push_back(element);
397 }
398 else if (type == "fileselector")
399 {
400 GUIFileSelector* element = new GUIFileSelector(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 }
405 else if (type == "animation")
406 {
407 GUIAnimation* element = new GUIAnimation(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 }
411 else if (type == "progressbar")
412 {
413 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100414 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200415 mRenders.push_back(element);
416 mActions.push_back(element);
417 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400418 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200419 {
420 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100421 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200422 mRenders.push_back(element);
423 mActions.push_back(element);
424 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200425 else if (type == "slidervalue")
426 {
427 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100428 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200429 mRenders.push_back(element);
430 mActions.push_back(element);
431 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400432 else if (type == "listbox")
433 {
434 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100435 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400436 mRenders.push_back(element);
437 mActions.push_back(element);
438 }
439 else if (type == "keyboard")
440 {
441 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100442 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400443 mRenders.push_back(element);
444 mActions.push_back(element);
445 }
446 else if (type == "input")
447 {
448 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100449 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400450 mRenders.push_back(element);
451 mActions.push_back(element);
452 mInputs.push_back(element);
453 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500454 else if (type == "partitionlist")
455 {
456 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100457 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500458 mRenders.push_back(element);
459 mActions.push_back(element);
460 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100461 else if (type == "patternpassword")
462 {
463 GUIPatternPassword* element = new GUIPatternPassword(child);
464 mObjects.push_back(element);
465 mRenders.push_back(element);
466 mActions.push_back(element);
467 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500468 else if (type == "textbox")
469 {
470 GUITextBox* element = new GUITextBox(child);
471 mObjects.push_back(element);
472 mRenders.push_back(element);
473 mActions.push_back(element);
474 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200475 else if (type == "template")
476 {
477 if (!templates || !child->first_attribute("name"))
478 {
479 LOGERR("Invalid template request.\n");
480 }
481 else
482 {
483 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500484 xml_node<>* node;
485 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400486
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200487 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500488 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
489 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400490
Ethan Yonker780cd392014-07-21 15:24:39 -0500491 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200492 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500493 if (!node->first_attribute("name"))
494 continue;
495
496 if (name == node->first_attribute("name")->value())
497 {
498 if (!ProcessNode(node, templates, depth + 1))
499 return false;
500 else {
501 node_found = true;
502 break;
503 }
504 }
505 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200506 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500507 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200508 }
thatb63e2f92015-06-27 21:35:11 +0200509 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200510 }
511 }
512 }
513 else
514 {
thatb63e2f92015-06-27 21:35:11 +0200515 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200516 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 }
518 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400519}
520
521int Page::Render(void)
522{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200523 // Render background
524 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
525 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400526
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200527 // Render remaining objects
528 std::vector<RenderObject*>::iterator iter;
529 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
530 {
531 if ((*iter)->Render())
532 LOGERR("A render request has failed.\n");
533 }
534 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400535}
536
537int Page::Update(void)
538{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200539 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400540
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200541 std::vector<RenderObject*>::iterator iter;
542 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
543 {
544 int ret = (*iter)->Update();
545 if (ret < 0)
546 LOGERR("An update request has failed.\n");
547 else if (ret > retCode)
548 retCode = ret;
549 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400550
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200551 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400552}
553
554int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
555{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200556 // By default, return 1 to ignore further touches if nobody is listening
557 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400558
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200559 // Don't try to handle a lack of handlers
560 if (mActions.size() == 0)
561 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400562
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200563 // We record mTouchStart so we can pass all the touch stream to the same handler
564 if (state == TOUCH_START)
565 {
566 std::vector<ActionObject*>::reverse_iterator iter;
567 // We work backwards, from top-most element to bottom-most element
568 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
569 {
570 if ((*iter)->IsInRegion(x, y))
571 {
572 mTouchStart = (*iter);
573 ret = mTouchStart->NotifyTouch(state, x, y);
574 if (ret >= 0)
575 break;
576 mTouchStart = NULL;
577 }
578 }
579 }
580 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
581 {
582 ret = mTouchStart->NotifyTouch(state, x, y);
583 mTouchStart = NULL;
584 }
585 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
586 {
587 ret = mTouchStart->NotifyTouch(state, x, y);
588 }
589 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400590}
591
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100592int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400593{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200594 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400595
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100596 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200597 // We work backwards, from top-most element to bottom-most element
598 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
599 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100600 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100601 if (ret == 0)
602 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100603 if (ret < 0) {
604 LOGERR("An action handler has returned an error\n");
605 ret = 1;
606 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200607 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100608 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400609}
610
that8834a0f2016-01-05 23:29:30 +0100611int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400612{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200613 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400614
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 // We work backwards, from top-most element to bottom-most element
616 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
617 {
that8834a0f2016-01-05 23:29:30 +0100618 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200619 if (ret == 0)
620 return 0;
621 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100622 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200623 }
624 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400625}
626
627int Page::SetKeyBoardFocus(int inFocus)
628{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200629 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400630
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 // We work backwards, from top-most element to bottom-most element
632 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
633 {
634 int ret = (*iter)->SetInputFocus(inFocus);
635 if (ret == 0)
636 return 0;
637 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100638 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200639 }
640 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400641}
642
643void Page::SetPageFocus(int inFocus)
644{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200645 // Render remaining objects
646 std::vector<RenderObject*>::iterator iter;
647 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
648 (*iter)->SetPageFocus(inFocus);
649
650 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400651}
652
653int Page::NotifyVarChange(std::string varName, std::string value)
654{
Vojtech Bocek07220562014-02-08 02:05:33 +0100655 std::vector<GUIObject*>::iterator iter;
656 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200657 {
658 if ((*iter)->NotifyVarChange(varName, value))
659 LOGERR("An action handler errored on NotifyVarChange.\n");
660 }
661 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400662}
663
that6a894592016-03-13 17:51:28 +0100664
665// transient data for loading themes
666struct LoadingContext
667{
668 ZipArchive* zip; // zip to load theme from, or NULL for the stock theme
669 std::set<std::string> filenames; // to detect cyclic includes
670 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
671 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
672 std::vector<char*> xmlbuffers; // text buffers with xml content
673 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
674 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
675
676 LoadingContext()
677 {
678 zip = NULL;
679 }
680
681 ~LoadingContext()
682 {
683 // free all xml buffers
684 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
685 free(*it);
686 }
687
688};
689
690// for FindStyle
691LoadingContext* PageManager::currentLoadingContext = NULL;
692
693
694PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400695{
that74ac6062015-03-04 22:39:34 +0100696 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200697 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400698
that6a894592016-03-13 17:51:28 +0100699 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400700}
701
702PageSet::~PageSet()
703{
Ethan Yonker1c273312015-03-16 12:18:56 -0500704 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100705 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
706 delete *itr;
707
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200708 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400709}
710
that6a894592016-03-13 17:51:28 +0100711int PageSet::Load(LoadingContext& ctx, const std::string& filename)
712{
713 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
714
715 if (!ctx.filenames.insert(filename).second)
716 // ignore already loaded files to prevent crash with cyclic includes
717 return 0;
718
719 // load XML into buffer
720 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
721 if (!xmlbuffer)
722 return -1; // error already displayed by LoadFileToBuffer
723 ctx.xmlbuffers.push_back(xmlbuffer);
724
725 // parse XML
726 xml_document<>* doc = new xml_document<>();
727 doc->parse<0>(xmlbuffer);
728 ctx.xmldocs.push_back(doc);
729
730 xml_node<>* root = doc->first_node("recovery");
731 if (!root)
732 root = doc->first_node("install");
733 if (!root) {
734 LOGERR("Unknown root element in %s\n", filename.c_str());
735 return -1;
736 }
737
738 if (isMain) {
739 int rc = LoadDetails(ctx, root);
740 if (rc != 0)
741 return rc;
742 }
743
744 LOGINFO("Loading resources...\n");
745 xml_node<>* child = root->first_node("resources");
746 if (child)
747 mResources->LoadResources(child, ctx.zip, "theme");
748
749 LOGINFO("Loading variables...\n");
750 child = root->first_node("variables");
751 if (child)
752 LoadVariables(child);
753
754 LOGINFO("Loading mouse cursor...\n");
755 child = root->first_node("mousecursor");
756 if (child)
757 PageManager::LoadCursorData(child);
758
759 LOGINFO("Loading pages...\n");
760 child = root->first_node("templates");
761 if (child)
762 ctx.templates.push_back(child);
763
764 child = root->first_node("styles");
765 if (child)
766 ctx.styles.push_back(child);
767
768 // Load pages
769 child = root->first_node("pages");
770 if (child) {
771 if (LoadPages(ctx, child)) {
772 LOGERR("PageSet::Load returning -1\n");
773 return -1;
774 }
775 }
776
777 // process includes recursively
778 child = root->first_node("include");
779 if (child) {
780 xml_node<>* include = child->first_node("xmlfile");
781 while (include != NULL) {
782 xml_attribute<>* attr = include->first_attribute("name");
783 if (!attr) {
784 LOGERR("Skipping include/xmlfile with no name\n");
785 continue;
786 }
787
788 string filename = ctx.basepath + attr->value();
789 LOGINFO("Including file: %s...\n", filename.c_str());
790 int rc = Load(ctx, filename);
791 if (rc != 0)
792 return rc;
793
794 include = include->next_sibling("xmlfile");
795 }
796 }
797
798 return 0;
799}
800
801void PageSet::MakeEmergencyConsoleIfNeeded()
802{
803 if (mPages.empty()) {
804 mCurrentPage = new Page(NULL, NULL); // fallback console page
805 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
806 mPages.push_back(mCurrentPage);
807 }
808}
809
Ethan Yonker74db1572015-10-28 12:44:49 -0500810int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
811{
812 xml_document<> lang;
813 xml_node<>* parent;
814 xml_node<>* child;
815 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600816 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500817
818 if (languageFile) {
819 printf("parsing languageFile\n");
820 lang.parse<0>(languageFile);
821 printf("parsing languageFile done\n");
822 } else {
823 return -1;
824 }
825
826 parent = lang.first_node("language");
827 if (!parent) {
828 LOGERR("Unable to locate language node in language file.\n");
829 lang.clear();
830 return -1;
831 }
832
833 child = parent->first_node("display");
834 if (child) {
835 DataManager::SetValue("tw_language_display", child->value());
836 resource_source = child->value();
837 } else {
838 LOGERR("language file does not have a display value set\n");
839 DataManager::SetValue("tw_language_display", "Not Set");
840 resource_source = languageFile;
841 }
842
843 child = parent->first_node("resources");
844 if (child)
845 mResources->LoadResources(child, package, resource_source);
846 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600847 ret = -1;
848 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500849 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600850 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500851}
852
that6a894592016-03-13 17:51:28 +0100853int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400854{
that6a894592016-03-13 17:51:28 +0100855 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600856 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600857 int theme_ver = 0;
858 xml_node<>* themeversion = child->first_node("themeversion");
859 if (themeversion && themeversion->value()) {
860 theme_ver = atoi(themeversion->value());
861 } else {
862 LOGINFO("No themeversion in theme.\n");
863 }
864 if (theme_ver != TW_THEME_VERSION) {
865 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100866 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600867 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600868 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600869 } else {
870 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
871 }
872 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600873 xml_node<>* resolution = child->first_node("resolution");
874 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600875 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600876 xml_attribute<>* width_attr = resolution->first_attribute("width");
877 xml_attribute<>* height_attr = resolution->first_attribute("height");
878 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
879 if (width_attr && height_attr && !noscale_attr) {
880 int width = atoi(width_attr->value());
881 int height = atoi(height_attr->value());
882 int offx = 0, offy = 0;
883#ifdef TW_ROUND_SCREEN
884 xml_node<>* roundscreen = child->first_node("roundscreen");
885 if (roundscreen) {
886 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
887 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
888 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
889 if (offx_attr) {
890 offx = atoi(offx_attr->value());
891 }
892 if (offy_attr) {
893 offy = atoi(offy_attr->value());
894 }
895 }
896#endif
897 if (width != 0 && height != 0) {
898 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
899 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
900#ifdef TW_ROUND_SCREEN
901 float scale_off_w = (float)gr_fb_width() / (float)width;
902 float scale_off_h = (float)gr_fb_height() / (float)height;
903 tw_x_offset = offx * scale_off_w;
904 tw_y_offset = offy * scale_off_h;
905#endif
906 if (scale_w != 1 || scale_h != 1) {
907 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
908 set_scale_values(scale_w, scale_h);
909 }
910 }
911 } else {
912 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
913 }
914 } else {
915 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
916 }
917 } else {
918 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
919 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500920
Ethan Yonker780cd392014-07-21 15:24:39 -0500921 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400922}
923
924int PageSet::SetPage(std::string page)
925{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200926 Page* tmp = FindPage(page);
927 if (tmp)
928 {
929 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
930 mCurrentPage = tmp;
931 mCurrentPage->SetPageFocus(1);
932 mCurrentPage->NotifyVarChange("", "");
933 return 0;
934 }
935 else
936 {
937 LOGERR("Unable to locate page (%s)\n", page.c_str());
938 }
939 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400940}
941
942int PageSet::SetOverlay(Page* page)
943{
Ethan Yonker1c273312015-03-16 12:18:56 -0500944 if (page) {
945 if (mOverlays.size() >= 10) {
946 LOGERR("Too many overlays requested, max is 10.\n");
947 return -1;
948 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500949
950 std::vector<Page*>::iterator iter;
951 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
952 if ((*iter)->GetName() == page->GetName()) {
953 mOverlays.erase(iter);
954 // SetOverlay() is (and should stay) the only function which
955 // adds to mOverlays. Then, each page can appear at most once.
956 break;
957 }
958 }
959
Ethan Yonker1c273312015-03-16 12:18:56 -0500960 page->SetPageFocus(1);
961 page->NotifyVarChange("", "");
962
963 if (!mOverlays.empty())
964 mOverlays.back()->SetPageFocus(0);
965
966 mOverlays.push_back(page);
967 } else {
968 if (!mOverlays.empty()) {
969 mOverlays.back()->SetPageFocus(0);
970 mOverlays.pop_back();
971 if (!mOverlays.empty())
972 mOverlays.back()->SetPageFocus(1);
973 else if (mCurrentPage)
974 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
975 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200976 }
977 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400978}
979
that74ac6062015-03-04 22:39:34 +0100980const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400981{
that74ac6062015-03-04 22:39:34 +0100982 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400983}
984
985Page* PageSet::FindPage(std::string name)
986{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200987 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400988
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200989 for (iter = mPages.begin(); iter != mPages.end(); iter++)
990 {
991 if (name == (*iter)->GetName())
992 return (*iter);
993 }
994 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400995}
996
997int PageSet::LoadVariables(xml_node<>* vars)
998{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200999 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001000 xml_attribute<> *name, *value, *persist;
1001 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001002
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001003 child = vars->first_node("variable");
1004 while (child)
1005 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001006 name = child->first_attribute("name");
1007 value = child->first_attribute("value");
1008 persist = child->first_attribute("persist");
1009 if(name && value)
1010 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001011 if (strcmp(name->value(), "tw_x_offset") == 0) {
1012 tw_x_offset = atoi(value->value());
1013 child = child->next_sibling("variable");
1014 continue;
1015 }
1016 if (strcmp(name->value(), "tw_y_offset") == 0) {
1017 tw_y_offset = atoi(value->value());
1018 child = child->next_sibling("variable");
1019 continue;
1020 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001021 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001022 string temp = value->value();
1023 string valstr = gui_parse_text(temp);
1024
1025 if (valstr.find("+") != string::npos) {
1026 string val1str = valstr;
1027 val1str = val1str.substr(0, val1str.find('+'));
1028 string val2str = valstr;
1029 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1030 int val1 = atoi(val1str.c_str());
1031 int val2 = atoi(val2str.c_str());
1032 int val = val1 + val2;
1033
1034 DataManager::SetValue(name->value(), val, p);
1035 } else if (valstr.find("-") != string::npos) {
1036 string val1str = valstr;
1037 val1str = val1str.substr(0, val1str.find('-'));
1038 string val2str = valstr;
1039 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1040 int val1 = atoi(val1str.c_str());
1041 int val2 = atoi(val2str.c_str());
1042 int val = val1 - val2;
1043
1044 DataManager::SetValue(name->value(), val, p);
1045 } else {
1046 DataManager::SetValue(name->value(), valstr, p);
1047 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001048 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001049
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001050 child = child->next_sibling("variable");
1051 }
1052 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001053}
1054
that6a894592016-03-13 17:51:28 +01001055int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001056{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001057 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001058
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001059 if (!pages)
1060 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001061
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001062 child = pages->first_node("page");
1063 while (child != NULL)
1064 {
that6a894592016-03-13 17:51:28 +01001065 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001066 if (page->GetName().empty())
1067 {
1068 LOGERR("Unable to process load page\n");
1069 delete page;
1070 }
1071 else
1072 {
1073 mPages.push_back(page);
1074 }
1075 child = child->next_sibling("page");
1076 }
1077 if (mPages.size() > 0)
1078 return 0;
1079 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001080}
1081
1082int PageSet::IsCurrentPage(Page* page)
1083{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001084 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001085}
1086
that10ae24f2015-12-26 20:53:51 +01001087std::string PageSet::GetCurrentPage() const
1088{
1089 return mCurrentPage ? mCurrentPage->GetName() : "";
1090}
1091
Dees_Troy51a0e822012-09-05 15:24:24 -04001092int PageSet::Render(void)
1093{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001094 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001095
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001096 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1097 if (ret < 0)
1098 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001099
1100 std::vector<Page*>::iterator iter;
1101
1102 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1103 ret = ((*iter) ? (*iter)->Render() : -1);
1104 if (ret < 0)
1105 return ret;
1106 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001107 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001108}
1109
1110int PageSet::Update(void)
1111{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001112 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001113
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001114 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1115 if (ret < 0 || ret > 1)
1116 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001117
1118 std::vector<Page*>::iterator iter;
1119
1120 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1121 ret = ((*iter) ? (*iter)->Update() : -1);
1122 if (ret < 0)
1123 return ret;
1124 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001125 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001126}
1127
1128int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1129{
Ethan Yonker1c273312015-03-16 12:18:56 -05001130 if (!mOverlays.empty())
1131 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001132
1133 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001134}
1135
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001136int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001137{
Ethan Yonker1c273312015-03-16 12:18:56 -05001138 if (!mOverlays.empty())
1139 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001140
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001141 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001142}
1143
that8834a0f2016-01-05 23:29:30 +01001144int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001145{
Ethan Yonker1c273312015-03-16 12:18:56 -05001146 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001147 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001148
that8834a0f2016-01-05 23:29:30 +01001149 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001150}
1151
1152int PageSet::SetKeyBoardFocus(int inFocus)
1153{
Ethan Yonker1c273312015-03-16 12:18:56 -05001154 if (!mOverlays.empty())
1155 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001156
1157 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001158}
1159
1160int PageSet::NotifyVarChange(std::string varName, std::string value)
1161{
Ethan Yonker1c273312015-03-16 12:18:56 -05001162 std::vector<Page*>::iterator iter;
1163
1164 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1165 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001166
1167 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001168}
1169
Ethan Yonker74db1572015-10-28 12:44:49 -05001170void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1171{
1172 mResources->AddStringResource(resource_source, resource_name, value);
1173}
1174
Ethan Yonker561c58d2015-10-05 08:48:22 -05001175char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
1176 size_t len;
1177 char* buffer = NULL;
1178
1179 if (!package) {
1180 // We can try to load the XML directly...
1181 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1182 struct stat st;
1183 if(stat(filename.c_str(),&st) != 0) {
1184 // This isn't always an error, sometimes we request files that don't exist.
1185 return NULL;
1186 }
1187
1188 len = (size_t)st.st_size;
1189
1190 buffer = (char*) malloc(len + 1);
1191 if (!buffer) {
1192 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1193 return NULL;
1194 }
1195
1196 int fd = open(filename.c_str(), O_RDONLY);
1197 if (fd == -1) {
1198 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1199 free(buffer);
1200 return NULL;
1201 }
1202
1203 if (read(fd, buffer, len) < 0) {
1204 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1205 free(buffer);
1206 close(fd);
1207 return NULL;
1208 }
1209 close(fd);
1210 } else {
1211 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
1212 const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
1213 if (zipentry == NULL) {
1214 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1215 return NULL;
1216 }
1217
1218 // Allocate the buffer for the file
1219 len = mzGetZipEntryUncompLen(zipentry);
1220 buffer = (char*) malloc(len + 1);
1221 if (!buffer)
1222 return NULL;
1223
1224 if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
1225 LOGERR("Unable to extract '%s'\n", filename.c_str());
1226 free(buffer);
1227 return NULL;
1228 }
1229 }
1230 // NULL-terminate the string
1231 buffer[len] = 0x00;
1232 return buffer;
1233}
1234
Ethan Yonker74db1572015-10-28 12:44:49 -05001235void PageManager::LoadLanguageListDir(string dir) {
1236 if (!TWFunc::Path_Exists(dir)) {
1237 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1238 return;
1239 }
1240
1241 DIR *d = opendir(dir.c_str());
1242 struct dirent *p;
1243
1244 if (d == NULL) {
1245 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1246 return;
1247 }
1248
1249 while ((p = readdir(d))) {
1250 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1251 continue;
1252
1253 string file = p->d_name;
1254 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1255 continue;
1256 string path = dir + p->d_name;
1257 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1258 struct language_struct language_entry;
1259 language_entry.filename = file_no_extn;
1260 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1261 if (xmlFile == NULL) {
1262 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1263 continue;
1264 }
1265 xml_document<> *doc = new xml_document<>();
1266 doc->parse<0>(xmlFile);
1267
1268 xml_node<>* parent = doc->first_node("language");
1269 if (!parent) {
1270 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1271 } else {
1272 xml_node<>* child = parent->first_node("display");
1273 if (child) {
1274 language_entry.displayvalue = child->value();
1275 } else {
1276 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1277 language_entry.displayvalue = language_entry.filename;
1278 }
1279 Language_List.push_back(language_entry);
1280 }
1281 doc->clear();
1282 delete doc;
1283 free(xmlFile);
1284 }
1285 closedir(d);
1286}
1287
1288void PageManager::LoadLanguageList(ZipArchive* package) {
1289 Language_List.clear();
1290 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1291 TWFunc::removeDir(TWRES "customlanguages", true);
1292 if (package) {
1293 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
1294 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
1295 mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
1296 LoadLanguageListDir(TWRES "customlanguages/");
1297 } else {
1298 LoadLanguageListDir(TWRES "languages/");
1299 }
Xuefercac6ace2016-02-01 02:28:55 +08001300
1301 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001302}
1303
1304void PageManager::LoadLanguage(string filename) {
1305 string actual_filename;
1306 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1307 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1308 else
1309 actual_filename = TWRES "languages/" + filename + ".xml";
1310 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1311 if (xmlFile == NULL)
1312 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1313 else {
1314 mCurrentSet->LoadLanguage(xmlFile, NULL);
1315 free(xmlFile);
1316 }
1317 PartitionManager.Translate_Partition_Display_Names();
1318}
1319
Dees_Troy51a0e822012-09-05 15:24:24 -04001320int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1321{
that6a894592016-03-13 17:51:28 +01001322 std::string mainxmlfilename = package;
1323 ZipArchive zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001324 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001325 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001326 PageSet* pageSet = NULL;
1327 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001328 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001329
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001330 mReloadTheme = false;
1331 mStartPage = startpage;
1332
that6a894592016-03-13 17:51:28 +01001333 // init the loading context
1334 LoadingContext ctx;
1335
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001336 // Open the XML file
1337 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001338 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001339 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001340 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001341 tw_x_offset = TW_X_OFFSET;
1342 tw_y_offset = TW_Y_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001343 if (name != "splash") {
1344 LoadLanguageList(NULL);
1345 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1346 }
that6a894592016-03-13 17:51:28 +01001347 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001348 }
1349 else
1350 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001351 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001352 tw_x_offset = 0;
1353 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001354 if (!TWFunc::Path_Exists(package))
1355 return -1;
1356 if (sysMapFile(package.c_str(), &map) != 0) {
1357 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001358 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001359 }
1360 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1361 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1362 sysReleaseMap(&map);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001363 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001364 }
that6a894592016-03-13 17:51:28 +01001365 ctx.zip = &zip;
1366 mainxmlfilename = "ui.xml";
1367 LoadLanguageList(ctx.zip);
1368 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001369 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001370 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001371
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001372 // Before loading, mCurrentSet must be the loading package so we can find resources
1373 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001374 mCurrentSet = new PageSet();
1375
1376 if (baseLanguageFile) {
1377 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1378 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001379 }
that6a894592016-03-13 17:51:28 +01001380
1381 if (languageFile) {
1382 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1383 free(languageFile);
1384 }
1385
1386 // Load and parse the XML and all includes
1387 currentLoadingContext = &ctx; // required to find styles
1388 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1389 currentLoadingContext = NULL;
1390
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001391 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001392 mCurrentSet->SetPage(startpage);
1393 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001394 } else {
1395 if (ret != TW_THEME_VER_ERR)
1396 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001397 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001398
that6a894592016-03-13 17:51:28 +01001399 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001400 mCurrentSet = pageSet;
1401
that6a894592016-03-13 17:51:28 +01001402 if (ctx.zip) {
1403 mzCloseZipArchive(ctx.zip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001404 sysReleaseMap(&map);
1405 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001406 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001407
1408error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001409 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001410 if (ctx.zip) {
1411 mzCloseZipArchive(ctx.zip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001412 sysReleaseMap(&map);
1413 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001414 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001415}
1416
1417PageSet* PageManager::FindPackage(std::string name)
1418{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001419 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001420
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001421 iter = mPageSets.find(name);
1422 if (iter != mPageSets.end())
1423 return (*iter).second;
1424
1425 LOGERR("Unable to locate package %s\n", name.c_str());
1426 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001427}
1428
1429PageSet* PageManager::SelectPackage(std::string name)
1430{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001431 LOGINFO("Switching packages (%s)\n", name.c_str());
1432 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001433
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001434 tmp = FindPackage(name);
1435 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001436 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001437 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001438 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001439 mCurrentSet->NotifyVarChange("", "");
1440 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001441 else
1442 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001443
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001444 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001445}
1446
1447int PageManager::ReloadPackage(std::string name, std::string package)
1448{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001449 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001450
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001451 mReloadTheme = false;
1452
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001453 iter = mPageSets.find(name);
1454 if (iter == mPageSets.end())
1455 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001456
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001457 if(mMouseCursor)
1458 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1459
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001460 PageSet* set = (*iter).second;
1461 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001462
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001463 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001464 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001465 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001466 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1467 return -1;
1468 }
1469 if (mCurrentSet == set)
1470 SelectPackage(name);
1471 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001472 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001473 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001474}
1475
1476void PageManager::ReleasePackage(std::string name)
1477{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001478 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001479
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001480 iter = mPageSets.find(name);
1481 if (iter == mPageSets.end())
1482 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001483
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001484 PageSet* set = (*iter).second;
1485 mPageSets.erase(iter);
1486 delete set;
that235c6482016-01-24 21:59:00 +01001487 if (set == mCurrentSet)
1488 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001489 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001490}
1491
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001492int PageManager::RunReload() {
1493 int ret_val = 0;
1494 std::string theme_path;
1495
1496 if (!mReloadTheme)
1497 return 0;
1498
1499 mReloadTheme = false;
1500 theme_path = DataManager::GetSettingsStoragePath();
1501 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1502 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1503 ret_val = 1;
1504 }
1505
1506 theme_path += "/TWRP/theme/ui.zip";
1507 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1508 {
1509 // Loading the custom theme failed - try loading the stock theme
1510 LOGINFO("Attempting to reload stock theme...\n");
1511 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1512 {
1513 LOGERR("Failed to load base packages.\n");
1514 ret_val = 1;
1515 }
1516 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001517 if (ret_val == 0) {
1518 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1519 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1520 LoadLanguage(DataManager::GetStrValue("tw_language"));
1521 }
1522 }
1523
1524 // This makes the console re-translate
1525 last_message_count = 0;
1526 gConsole.clear();
1527 gConsoleColor.clear();
1528
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001529 return ret_val;
1530}
1531
1532void PageManager::RequestReload() {
1533 mReloadTheme = true;
1534}
1535
Ethan Yonkerafde0982016-01-23 08:55:35 -06001536void PageManager::SetStartPage(const std::string& page_name) {
1537 mStartPage = page_name;
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
that10ae24f2015-12-26 20:53:51 +01001547std::string PageManager::GetCurrentPage()
1548{
1549 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1550}
1551
Dees_Troy51a0e822012-09-05 15:24:24 -04001552int PageManager::ChangeOverlay(std::string name)
1553{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001554 if (name.empty())
1555 return mCurrentSet->SetOverlay(NULL);
1556 else
1557 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001558 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001559 return mCurrentSet->SetOverlay(page);
1560 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001561}
1562
that74ac6062015-03-04 22:39:34 +01001563const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001564{
that74ac6062015-03-04 22:39:34 +01001565 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001566}
1567
Dees_Troy51a0e822012-09-05 15:24:24 -04001568int PageManager::IsCurrentPage(Page* page)
1569{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001570 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001571}
1572
1573int PageManager::Render(void)
1574{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001575 if(blankTimer.isScreenOff())
1576 return 0;
1577
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001578 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1579 if(mMouseCursor)
1580 mMouseCursor->Render();
1581 return res;
1582}
1583
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001584HardwareKeyboard *PageManager::GetHardwareKeyboard()
1585{
1586 if(!mHardwareKeyboard)
1587 mHardwareKeyboard = new HardwareKeyboard();
1588 return mHardwareKeyboard;
1589}
1590
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001591xml_node<>* PageManager::FindStyle(std::string name)
1592{
that6a894592016-03-13 17:51:28 +01001593 if (!currentLoadingContext)
1594 {
1595 LOGERR("FindStyle works only while loading a theme.\n");
1596 return NULL;
1597 }
1598
1599 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001600 xml_node<>* node = (*itr)->first_node("style");
1601
1602 while (node) {
1603 if (!node->first_attribute("name"))
1604 continue;
1605
1606 if (name == node->first_attribute("name")->value())
1607 return node;
1608 node = node->next_sibling("style");
1609 }
1610 }
1611 return NULL;
1612}
1613
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001614MouseCursor *PageManager::GetMouseCursor()
1615{
1616 if(!mMouseCursor)
1617 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1618 return mMouseCursor;
1619}
1620
1621void PageManager::LoadCursorData(xml_node<>* node)
1622{
1623 if(!mMouseCursor)
1624 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1625
1626 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001627}
1628
1629int PageManager::Update(void)
1630{
thatfb759d42015-01-11 12:16:53 +01001631 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001632 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001633
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001634 if (RunReload())
1635 return -2;
1636
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001637 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1638
1639 if(mMouseCursor)
1640 {
1641 int c_res = mMouseCursor->Update();
1642 if(c_res > res)
1643 res = c_res;
1644 }
1645 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001646}
1647
1648int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1649{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001650 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001651}
1652
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001653int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001654{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001655 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001656}
1657
that8834a0f2016-01-05 23:29:30 +01001658int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001659{
that8834a0f2016-01-05 23:29:30 +01001660 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001661}
1662
1663int PageManager::SetKeyBoardFocus(int inFocus)
1664{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001665 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001666}
1667
1668int PageManager::NotifyVarChange(std::string varName, std::string value)
1669{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001670 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001671}
1672
Ethan Yonker74db1572015-10-28 12:44:49 -05001673void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1674{
1675 if (mCurrentSet)
1676 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1677}
1678
Dees_Troy51a0e822012-09-05 15:24:24 -04001679extern "C" void gui_notifyVarChange(const char *name, const char* value)
1680{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001681 if (!gGuiRunning)
1682 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001683
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001684 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001685}