blob: b901526ff0827cb8ba6a23e170c40ac593e0e6c6 [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
that74bff7f2017-01-18 22:32:36 +010054// version 2 requires theme to handle power button as action togglebacklight
bigbiff bigbiff56cf5642016-08-19 17:43:45 -040055#define TW_THEME_VERSION 3
that74bff7f2017-01-18 22:32:36 +010056
Ethan Yonker8e5692f2016-01-21 11:21:06 -060057#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060058
Dees_Troy51a0e822012-09-05 15:24:24 -040059extern int gGuiRunning;
60
61std::map<std::string, PageSet*> PageManager::mPageSets;
62PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010063MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010064HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050065bool PageManager::mReloadTheme = false;
66std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050067std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040068
Ethan Yonker751a85e2014-12-12 16:59:10 -060069int tw_x_offset = 0;
70int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050071int tw_w_offset = 0;
72int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060073
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 }
that1964d192016-01-07 00:41:03 +0100375 else if (type == "terminal")
376 {
377 GUITerminal* element = new GUITerminal(child);
378 mObjects.push_back(element);
379 mRenders.push_back(element);
380 mActions.push_back(element);
381 mInputs.push_back(element);
382 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200383 else if (type == "button")
384 {
385 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100386 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200387 mRenders.push_back(element);
388 mActions.push_back(element);
389 }
390 else if (type == "checkbox")
391 {
392 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100393 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200394 mRenders.push_back(element);
395 mActions.push_back(element);
396 }
397 else if (type == "fileselector")
398 {
399 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100400 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200401 mRenders.push_back(element);
402 mActions.push_back(element);
403 }
404 else if (type == "animation")
405 {
406 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100407 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200408 mRenders.push_back(element);
409 }
410 else if (type == "progressbar")
411 {
412 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100413 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200414 mRenders.push_back(element);
415 mActions.push_back(element);
416 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400417 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200418 {
419 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100420 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200421 mRenders.push_back(element);
422 mActions.push_back(element);
423 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200424 else if (type == "slidervalue")
425 {
426 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100427 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200428 mRenders.push_back(element);
429 mActions.push_back(element);
430 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400431 else if (type == "listbox")
432 {
433 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100434 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400435 mRenders.push_back(element);
436 mActions.push_back(element);
437 }
438 else if (type == "keyboard")
439 {
440 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100441 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400442 mRenders.push_back(element);
443 mActions.push_back(element);
444 }
445 else if (type == "input")
446 {
447 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100448 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400449 mRenders.push_back(element);
450 mActions.push_back(element);
451 mInputs.push_back(element);
452 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500453 else if (type == "partitionlist")
454 {
455 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100456 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500457 mRenders.push_back(element);
458 mActions.push_back(element);
459 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100460 else if (type == "patternpassword")
461 {
462 GUIPatternPassword* element = new GUIPatternPassword(child);
463 mObjects.push_back(element);
464 mRenders.push_back(element);
465 mActions.push_back(element);
466 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500467 else if (type == "textbox")
468 {
469 GUITextBox* element = new GUITextBox(child);
470 mObjects.push_back(element);
471 mRenders.push_back(element);
472 mActions.push_back(element);
473 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200474 else if (type == "template")
475 {
476 if (!templates || !child->first_attribute("name"))
477 {
478 LOGERR("Invalid template request.\n");
479 }
480 else
481 {
482 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500483 xml_node<>* node;
484 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400485
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200486 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500487 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
488 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400489
Ethan Yonker780cd392014-07-21 15:24:39 -0500490 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200491 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500492 if (!node->first_attribute("name"))
493 continue;
494
495 if (name == node->first_attribute("name")->value())
496 {
497 if (!ProcessNode(node, templates, depth + 1))
498 return false;
499 else {
500 node_found = true;
501 break;
502 }
503 }
504 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200505 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500506 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200507 }
thatb63e2f92015-06-27 21:35:11 +0200508 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200509 }
510 }
511 }
512 else
513 {
thatb63e2f92015-06-27 21:35:11 +0200514 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200516 }
517 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400518}
519
520int Page::Render(void)
521{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200522 // Render background
523 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
524 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400525
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200526 // Render remaining objects
527 std::vector<RenderObject*>::iterator iter;
528 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
529 {
530 if ((*iter)->Render())
531 LOGERR("A render request has failed.\n");
532 }
533 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400534}
535
536int Page::Update(void)
537{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200538 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400539
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200540 std::vector<RenderObject*>::iterator iter;
541 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
542 {
543 int ret = (*iter)->Update();
544 if (ret < 0)
545 LOGERR("An update request has failed.\n");
546 else if (ret > retCode)
547 retCode = ret;
548 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400549
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400551}
552
553int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
554{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200555 // By default, return 1 to ignore further touches if nobody is listening
556 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400557
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200558 // Don't try to handle a lack of handlers
559 if (mActions.size() == 0)
560 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400561
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200562 // We record mTouchStart so we can pass all the touch stream to the same handler
563 if (state == TOUCH_START)
564 {
565 std::vector<ActionObject*>::reverse_iterator iter;
566 // We work backwards, from top-most element to bottom-most element
567 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
568 {
569 if ((*iter)->IsInRegion(x, y))
570 {
571 mTouchStart = (*iter);
572 ret = mTouchStart->NotifyTouch(state, x, y);
573 if (ret >= 0)
574 break;
575 mTouchStart = NULL;
576 }
577 }
578 }
579 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
580 {
581 ret = mTouchStart->NotifyTouch(state, x, y);
582 mTouchStart = NULL;
583 }
584 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
585 {
586 ret = mTouchStart->NotifyTouch(state, x, y);
587 }
588 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400589}
590
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100591int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400592{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200593 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400594
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100595 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 // We work backwards, from top-most element to bottom-most element
597 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
598 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100599 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100600 if (ret == 0)
601 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100602 if (ret < 0) {
603 LOGERR("An action handler has returned an error\n");
604 ret = 1;
605 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200606 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100607 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400608}
609
that8834a0f2016-01-05 23:29:30 +0100610int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400611{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200612 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400613
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200614 // We work backwards, from top-most element to bottom-most element
615 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
616 {
that8834a0f2016-01-05 23:29:30 +0100617 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200618 if (ret == 0)
619 return 0;
620 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100621 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200622 }
623 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400624}
625
626int Page::SetKeyBoardFocus(int inFocus)
627{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400629
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200630 // We work backwards, from top-most element to bottom-most element
631 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
632 {
633 int ret = (*iter)->SetInputFocus(inFocus);
634 if (ret == 0)
635 return 0;
636 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100637 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200638 }
639 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400640}
641
642void Page::SetPageFocus(int inFocus)
643{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200644 // Render remaining objects
645 std::vector<RenderObject*>::iterator iter;
646 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
647 (*iter)->SetPageFocus(inFocus);
648
649 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400650}
651
652int Page::NotifyVarChange(std::string varName, std::string value)
653{
Vojtech Bocek07220562014-02-08 02:05:33 +0100654 std::vector<GUIObject*>::iterator iter;
655 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200656 {
657 if ((*iter)->NotifyVarChange(varName, value))
658 LOGERR("An action handler errored on NotifyVarChange.\n");
659 }
660 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400661}
662
that6a894592016-03-13 17:51:28 +0100663
664// transient data for loading themes
665struct LoadingContext
666{
667 ZipArchive* zip; // zip to load theme from, or NULL for the stock theme
668 std::set<std::string> filenames; // to detect cyclic includes
669 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
670 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
671 std::vector<char*> xmlbuffers; // text buffers with xml content
672 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
673 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
674
675 LoadingContext()
676 {
677 zip = NULL;
678 }
679
680 ~LoadingContext()
681 {
682 // free all xml buffers
683 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
684 free(*it);
685 }
686
687};
688
689// for FindStyle
690LoadingContext* PageManager::currentLoadingContext = NULL;
691
692
693PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400694{
that74ac6062015-03-04 22:39:34 +0100695 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200696 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400697
that6a894592016-03-13 17:51:28 +0100698 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400699}
700
701PageSet::~PageSet()
702{
Ethan Yonker1c273312015-03-16 12:18:56 -0500703 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100704 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
705 delete *itr;
706
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200707 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400708}
709
that6a894592016-03-13 17:51:28 +0100710int PageSet::Load(LoadingContext& ctx, const std::string& filename)
711{
712 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
713
714 if (!ctx.filenames.insert(filename).second)
715 // ignore already loaded files to prevent crash with cyclic includes
716 return 0;
717
718 // load XML into buffer
719 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
720 if (!xmlbuffer)
721 return -1; // error already displayed by LoadFileToBuffer
722 ctx.xmlbuffers.push_back(xmlbuffer);
723
724 // parse XML
725 xml_document<>* doc = new xml_document<>();
726 doc->parse<0>(xmlbuffer);
727 ctx.xmldocs.push_back(doc);
728
729 xml_node<>* root = doc->first_node("recovery");
730 if (!root)
731 root = doc->first_node("install");
732 if (!root) {
733 LOGERR("Unknown root element in %s\n", filename.c_str());
734 return -1;
735 }
736
737 if (isMain) {
738 int rc = LoadDetails(ctx, root);
739 if (rc != 0)
740 return rc;
741 }
742
743 LOGINFO("Loading resources...\n");
744 xml_node<>* child = root->first_node("resources");
745 if (child)
746 mResources->LoadResources(child, ctx.zip, "theme");
747
748 LOGINFO("Loading variables...\n");
749 child = root->first_node("variables");
750 if (child)
751 LoadVariables(child);
752
753 LOGINFO("Loading mouse cursor...\n");
754 child = root->first_node("mousecursor");
755 if (child)
756 PageManager::LoadCursorData(child);
757
758 LOGINFO("Loading pages...\n");
759 child = root->first_node("templates");
760 if (child)
761 ctx.templates.push_back(child);
762
763 child = root->first_node("styles");
764 if (child)
765 ctx.styles.push_back(child);
766
767 // Load pages
768 child = root->first_node("pages");
769 if (child) {
770 if (LoadPages(ctx, child)) {
771 LOGERR("PageSet::Load returning -1\n");
772 return -1;
773 }
774 }
775
776 // process includes recursively
777 child = root->first_node("include");
778 if (child) {
779 xml_node<>* include = child->first_node("xmlfile");
780 while (include != NULL) {
781 xml_attribute<>* attr = include->first_attribute("name");
782 if (!attr) {
783 LOGERR("Skipping include/xmlfile with no name\n");
784 continue;
785 }
786
787 string filename = ctx.basepath + attr->value();
788 LOGINFO("Including file: %s...\n", filename.c_str());
789 int rc = Load(ctx, filename);
790 if (rc != 0)
791 return rc;
792
793 include = include->next_sibling("xmlfile");
794 }
795 }
796
797 return 0;
798}
799
800void PageSet::MakeEmergencyConsoleIfNeeded()
801{
802 if (mPages.empty()) {
803 mCurrentPage = new Page(NULL, NULL); // fallback console page
804 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
805 mPages.push_back(mCurrentPage);
806 }
807}
808
Ethan Yonker74db1572015-10-28 12:44:49 -0500809int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
810{
811 xml_document<> lang;
812 xml_node<>* parent;
813 xml_node<>* child;
814 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600815 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500816
817 if (languageFile) {
818 printf("parsing languageFile\n");
819 lang.parse<0>(languageFile);
820 printf("parsing languageFile done\n");
821 } else {
822 return -1;
823 }
824
825 parent = lang.first_node("language");
826 if (!parent) {
827 LOGERR("Unable to locate language node in language file.\n");
828 lang.clear();
829 return -1;
830 }
831
832 child = parent->first_node("display");
833 if (child) {
834 DataManager::SetValue("tw_language_display", child->value());
835 resource_source = child->value();
836 } else {
837 LOGERR("language file does not have a display value set\n");
838 DataManager::SetValue("tw_language_display", "Not Set");
839 resource_source = languageFile;
840 }
841
842 child = parent->first_node("resources");
843 if (child)
844 mResources->LoadResources(child, package, resource_source);
845 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600846 ret = -1;
847 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500848 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600849 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500850}
851
that6a894592016-03-13 17:51:28 +0100852int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400853{
that6a894592016-03-13 17:51:28 +0100854 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600855 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600856 int theme_ver = 0;
857 xml_node<>* themeversion = child->first_node("themeversion");
858 if (themeversion && themeversion->value()) {
859 theme_ver = atoi(themeversion->value());
860 } else {
861 LOGINFO("No themeversion in theme.\n");
862 }
863 if (theme_ver != TW_THEME_VERSION) {
864 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100865 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600866 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600867 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600868 } else {
869 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
870 }
871 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600872 xml_node<>* resolution = child->first_node("resolution");
873 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600874 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600875 xml_attribute<>* width_attr = resolution->first_attribute("width");
876 xml_attribute<>* height_attr = resolution->first_attribute("height");
877 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
878 if (width_attr && height_attr && !noscale_attr) {
879 int width = atoi(width_attr->value());
880 int height = atoi(height_attr->value());
881 int offx = 0, offy = 0;
882#ifdef TW_ROUND_SCREEN
883 xml_node<>* roundscreen = child->first_node("roundscreen");
884 if (roundscreen) {
885 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
886 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
887 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
888 if (offx_attr) {
889 offx = atoi(offx_attr->value());
890 }
891 if (offy_attr) {
892 offy = atoi(offy_attr->value());
893 }
894 }
895#endif
896 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500897 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
898 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600899#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500900 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
901 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600902 tw_x_offset = offx * scale_off_w;
903 tw_y_offset = offy * scale_off_h;
904#endif
905 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500906 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
907 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600908 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");
Matt Mowera8a89d12016-12-30 18:10:37 -06001009 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001010 {
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 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001021 if (strcmp(name->value(), "tw_w_offset") == 0) {
1022 tw_w_offset = atoi(value->value());
1023 child = child->next_sibling("variable");
1024 continue;
1025 }
1026 if (strcmp(name->value(), "tw_h_offset") == 0) {
1027 tw_h_offset = atoi(value->value());
1028 child = child->next_sibling("variable");
1029 continue;
1030 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001031 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001032 string temp = value->value();
1033 string valstr = gui_parse_text(temp);
1034
1035 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 if (valstr.find("-") != string::npos) {
1046 string val1str = valstr;
1047 val1str = val1str.substr(0, val1str.find('-'));
1048 string val2str = valstr;
1049 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1050 int val1 = atoi(val1str.c_str());
1051 int val2 = atoi(val2str.c_str());
1052 int val = val1 - val2;
1053
1054 DataManager::SetValue(name->value(), val, p);
1055 } else {
1056 DataManager::SetValue(name->value(), valstr, p);
1057 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001058 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001059
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001060 child = child->next_sibling("variable");
1061 }
1062 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001063}
1064
that6a894592016-03-13 17:51:28 +01001065int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001066{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001067 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001068
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001069 if (!pages)
1070 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001071
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001072 child = pages->first_node("page");
1073 while (child != NULL)
1074 {
that6a894592016-03-13 17:51:28 +01001075 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001076 if (page->GetName().empty())
1077 {
1078 LOGERR("Unable to process load page\n");
1079 delete page;
1080 }
1081 else
1082 {
1083 mPages.push_back(page);
1084 }
1085 child = child->next_sibling("page");
1086 }
1087 if (mPages.size() > 0)
1088 return 0;
1089 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001090}
1091
1092int PageSet::IsCurrentPage(Page* page)
1093{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001094 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001095}
1096
that10ae24f2015-12-26 20:53:51 +01001097std::string PageSet::GetCurrentPage() const
1098{
1099 return mCurrentPage ? mCurrentPage->GetName() : "";
1100}
1101
Dees_Troy51a0e822012-09-05 15:24:24 -04001102int PageSet::Render(void)
1103{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001104 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001105
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001106 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1107 if (ret < 0)
1108 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001109
1110 std::vector<Page*>::iterator iter;
1111
1112 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1113 ret = ((*iter) ? (*iter)->Render() : -1);
1114 if (ret < 0)
1115 return ret;
1116 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001117 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001118}
1119
1120int PageSet::Update(void)
1121{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001122 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001123
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001124 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1125 if (ret < 0 || ret > 1)
1126 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001127
1128 std::vector<Page*>::iterator iter;
1129
1130 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1131 ret = ((*iter) ? (*iter)->Update() : -1);
1132 if (ret < 0)
1133 return ret;
1134 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001135 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001136}
1137
1138int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1139{
Ethan Yonker1c273312015-03-16 12:18:56 -05001140 if (!mOverlays.empty())
1141 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001142
1143 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001144}
1145
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001146int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001147{
Ethan Yonker1c273312015-03-16 12:18:56 -05001148 if (!mOverlays.empty())
1149 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001150
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001151 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001152}
1153
that8834a0f2016-01-05 23:29:30 +01001154int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001155{
Ethan Yonker1c273312015-03-16 12:18:56 -05001156 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001157 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001158
that8834a0f2016-01-05 23:29:30 +01001159 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001160}
1161
1162int PageSet::SetKeyBoardFocus(int inFocus)
1163{
Ethan Yonker1c273312015-03-16 12:18:56 -05001164 if (!mOverlays.empty())
1165 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001166
1167 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001168}
1169
1170int PageSet::NotifyVarChange(std::string varName, std::string value)
1171{
Ethan Yonker1c273312015-03-16 12:18:56 -05001172 std::vector<Page*>::iterator iter;
1173
1174 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1175 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001176
1177 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001178}
1179
Ethan Yonker74db1572015-10-28 12:44:49 -05001180void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1181{
1182 mResources->AddStringResource(resource_source, resource_name, value);
1183}
1184
Ethan Yonker561c58d2015-10-05 08:48:22 -05001185char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
1186 size_t len;
1187 char* buffer = NULL;
1188
1189 if (!package) {
1190 // We can try to load the XML directly...
1191 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1192 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001193 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001194 // This isn't always an error, sometimes we request files that don't exist.
1195 return NULL;
1196 }
1197
1198 len = (size_t)st.st_size;
1199
1200 buffer = (char*) malloc(len + 1);
1201 if (!buffer) {
1202 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1203 return NULL;
1204 }
1205
1206 int fd = open(filename.c_str(), O_RDONLY);
1207 if (fd == -1) {
1208 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1209 free(buffer);
1210 return NULL;
1211 }
1212
1213 if (read(fd, buffer, len) < 0) {
1214 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1215 free(buffer);
1216 close(fd);
1217 return NULL;
1218 }
1219 close(fd);
1220 } else {
1221 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
1222 const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
1223 if (zipentry == NULL) {
1224 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1225 return NULL;
1226 }
1227
1228 // Allocate the buffer for the file
1229 len = mzGetZipEntryUncompLen(zipentry);
1230 buffer = (char*) malloc(len + 1);
1231 if (!buffer)
1232 return NULL;
1233
1234 if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
1235 LOGERR("Unable to extract '%s'\n", filename.c_str());
1236 free(buffer);
1237 return NULL;
1238 }
1239 }
1240 // NULL-terminate the string
1241 buffer[len] = 0x00;
1242 return buffer;
1243}
1244
Ethan Yonker74db1572015-10-28 12:44:49 -05001245void PageManager::LoadLanguageListDir(string dir) {
1246 if (!TWFunc::Path_Exists(dir)) {
1247 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1248 return;
1249 }
1250
1251 DIR *d = opendir(dir.c_str());
1252 struct dirent *p;
1253
1254 if (d == NULL) {
1255 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1256 return;
1257 }
1258
1259 while ((p = readdir(d))) {
1260 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1261 continue;
1262
1263 string file = p->d_name;
1264 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1265 continue;
1266 string path = dir + p->d_name;
1267 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1268 struct language_struct language_entry;
1269 language_entry.filename = file_no_extn;
1270 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1271 if (xmlFile == NULL) {
1272 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1273 continue;
1274 }
1275 xml_document<> *doc = new xml_document<>();
1276 doc->parse<0>(xmlFile);
1277
1278 xml_node<>* parent = doc->first_node("language");
1279 if (!parent) {
1280 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1281 } else {
1282 xml_node<>* child = parent->first_node("display");
1283 if (child) {
1284 language_entry.displayvalue = child->value();
1285 } else {
1286 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1287 language_entry.displayvalue = language_entry.filename;
1288 }
1289 Language_List.push_back(language_entry);
1290 }
1291 doc->clear();
1292 delete doc;
1293 free(xmlFile);
1294 }
1295 closedir(d);
1296}
1297
1298void PageManager::LoadLanguageList(ZipArchive* package) {
1299 Language_List.clear();
1300 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1301 TWFunc::removeDir(TWRES "customlanguages", true);
1302 if (package) {
1303 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
1304 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
1305 mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
1306 LoadLanguageListDir(TWRES "customlanguages/");
1307 } else {
1308 LoadLanguageListDir(TWRES "languages/");
1309 }
Xuefercac6ace2016-02-01 02:28:55 +08001310
1311 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001312}
1313
1314void PageManager::LoadLanguage(string filename) {
1315 string actual_filename;
1316 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1317 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1318 else
1319 actual_filename = TWRES "languages/" + filename + ".xml";
1320 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1321 if (xmlFile == NULL)
1322 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1323 else {
1324 mCurrentSet->LoadLanguage(xmlFile, NULL);
1325 free(xmlFile);
1326 }
1327 PartitionManager.Translate_Partition_Display_Names();
1328}
1329
Dees_Troy51a0e822012-09-05 15:24:24 -04001330int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1331{
that6a894592016-03-13 17:51:28 +01001332 std::string mainxmlfilename = package;
1333 ZipArchive zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001334 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001335 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001336 PageSet* pageSet = NULL;
1337 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001338 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001339
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001340 mReloadTheme = false;
1341 mStartPage = startpage;
1342
that6a894592016-03-13 17:51:28 +01001343 // init the loading context
1344 LoadingContext ctx;
1345
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001346 // Open the XML file
1347 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001348 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001349 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001350 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001351 tw_x_offset = TW_X_OFFSET;
1352 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001353 tw_w_offset = TW_W_OFFSET;
1354 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001355 if (name != "splash") {
1356 LoadLanguageList(NULL);
1357 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1358 }
that6a894592016-03-13 17:51:28 +01001359 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001360 }
1361 else
1362 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001363 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001364 tw_x_offset = 0;
1365 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001366 tw_w_offset = 0;
1367 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001368 if (!TWFunc::Path_Exists(package))
1369 return -1;
1370 if (sysMapFile(package.c_str(), &map) != 0) {
1371 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001372 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001373 }
1374 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1375 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1376 sysReleaseMap(&map);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001377 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001378 }
that6a894592016-03-13 17:51:28 +01001379 ctx.zip = &zip;
1380 mainxmlfilename = "ui.xml";
1381 LoadLanguageList(ctx.zip);
1382 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001383 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001384 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001385
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001386 // Before loading, mCurrentSet must be the loading package so we can find resources
1387 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001388 mCurrentSet = new PageSet();
1389
1390 if (baseLanguageFile) {
1391 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1392 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001393 }
that6a894592016-03-13 17:51:28 +01001394
1395 if (languageFile) {
1396 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1397 free(languageFile);
1398 }
1399
1400 // Load and parse the XML and all includes
1401 currentLoadingContext = &ctx; // required to find styles
1402 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1403 currentLoadingContext = NULL;
1404
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001405 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001406 mCurrentSet->SetPage(startpage);
1407 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001408 } else {
1409 if (ret != TW_THEME_VER_ERR)
1410 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001411 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001412
that6a894592016-03-13 17:51:28 +01001413 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001414 mCurrentSet = pageSet;
1415
that6a894592016-03-13 17:51:28 +01001416 if (ctx.zip) {
1417 mzCloseZipArchive(ctx.zip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001418 sysReleaseMap(&map);
1419 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001420 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001421
1422error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001423 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001424 if (ctx.zip) {
1425 mzCloseZipArchive(ctx.zip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001426 sysReleaseMap(&map);
1427 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001428 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001429}
1430
1431PageSet* PageManager::FindPackage(std::string name)
1432{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001433 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001434
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001435 iter = mPageSets.find(name);
1436 if (iter != mPageSets.end())
1437 return (*iter).second;
1438
1439 LOGERR("Unable to locate package %s\n", name.c_str());
1440 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001441}
1442
1443PageSet* PageManager::SelectPackage(std::string name)
1444{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001445 LOGINFO("Switching packages (%s)\n", name.c_str());
1446 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001447
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001448 tmp = FindPackage(name);
1449 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001450 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001451 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001452 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001453 mCurrentSet->NotifyVarChange("", "");
1454 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001455 else
1456 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001457
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001458 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001459}
1460
1461int PageManager::ReloadPackage(std::string name, std::string package)
1462{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001463 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001464
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001465 mReloadTheme = false;
1466
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001467 iter = mPageSets.find(name);
1468 if (iter == mPageSets.end())
1469 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001470
Matt Mowera8a89d12016-12-30 18:10:37 -06001471 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001472 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1473
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001474 PageSet* set = (*iter).second;
1475 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001476
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001477 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001478 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001479 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001480 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1481 return -1;
1482 }
1483 if (mCurrentSet == set)
1484 SelectPackage(name);
1485 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001486 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001487 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001488}
1489
1490void PageManager::ReleasePackage(std::string name)
1491{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001492 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001493
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001494 iter = mPageSets.find(name);
1495 if (iter == mPageSets.end())
1496 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001497
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001498 PageSet* set = (*iter).second;
1499 mPageSets.erase(iter);
1500 delete set;
that235c6482016-01-24 21:59:00 +01001501 if (set == mCurrentSet)
1502 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001503 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001504}
1505
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001506int PageManager::RunReload() {
1507 int ret_val = 0;
1508 std::string theme_path;
1509
1510 if (!mReloadTheme)
1511 return 0;
1512
1513 mReloadTheme = false;
1514 theme_path = DataManager::GetSettingsStoragePath();
1515 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1516 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1517 ret_val = 1;
1518 }
1519
1520 theme_path += "/TWRP/theme/ui.zip";
1521 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1522 {
1523 // Loading the custom theme failed - try loading the stock theme
1524 LOGINFO("Attempting to reload stock theme...\n");
1525 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1526 {
1527 LOGERR("Failed to load base packages.\n");
1528 ret_val = 1;
1529 }
1530 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001531 if (ret_val == 0) {
1532 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1533 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1534 LoadLanguage(DataManager::GetStrValue("tw_language"));
1535 }
1536 }
1537
1538 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001539 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001540
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001541 return ret_val;
1542}
1543
1544void PageManager::RequestReload() {
1545 mReloadTheme = true;
1546}
1547
Ethan Yonkerafde0982016-01-23 08:55:35 -06001548void PageManager::SetStartPage(const std::string& page_name) {
1549 mStartPage = page_name;
1550}
1551
Dees_Troy51a0e822012-09-05 15:24:24 -04001552int PageManager::ChangePage(std::string name)
1553{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001554 DataManager::SetValue("tw_operation_state", 0);
1555 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1556 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001557}
1558
that10ae24f2015-12-26 20:53:51 +01001559std::string PageManager::GetCurrentPage()
1560{
1561 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1562}
1563
Dees_Troy51a0e822012-09-05 15:24:24 -04001564int PageManager::ChangeOverlay(std::string name)
1565{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001566 if (name.empty())
1567 return mCurrentSet->SetOverlay(NULL);
1568 else
1569 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001570 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001571 return mCurrentSet->SetOverlay(page);
1572 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001573}
1574
that74ac6062015-03-04 22:39:34 +01001575const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001576{
that74ac6062015-03-04 22:39:34 +01001577 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001578}
1579
Dees_Troy51a0e822012-09-05 15:24:24 -04001580int PageManager::IsCurrentPage(Page* page)
1581{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001582 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001583}
1584
1585int PageManager::Render(void)
1586{
Matt Mowera8a89d12016-12-30 18:10:37 -06001587 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001588 return 0;
1589
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001590 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001591 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001592 mMouseCursor->Render();
1593 return res;
1594}
1595
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001596HardwareKeyboard *PageManager::GetHardwareKeyboard()
1597{
Matt Mowera8a89d12016-12-30 18:10:37 -06001598 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001599 mHardwareKeyboard = new HardwareKeyboard();
1600 return mHardwareKeyboard;
1601}
1602
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001603xml_node<>* PageManager::FindStyle(std::string name)
1604{
that6a894592016-03-13 17:51:28 +01001605 if (!currentLoadingContext)
1606 {
1607 LOGERR("FindStyle works only while loading a theme.\n");
1608 return NULL;
1609 }
1610
1611 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001612 xml_node<>* node = (*itr)->first_node("style");
1613
1614 while (node) {
1615 if (!node->first_attribute("name"))
1616 continue;
1617
1618 if (name == node->first_attribute("name")->value())
1619 return node;
1620 node = node->next_sibling("style");
1621 }
1622 }
1623 return NULL;
1624}
1625
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001626MouseCursor *PageManager::GetMouseCursor()
1627{
Matt Mowera8a89d12016-12-30 18:10:37 -06001628 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001629 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1630 return mMouseCursor;
1631}
1632
1633void PageManager::LoadCursorData(xml_node<>* node)
1634{
Matt Mowera8a89d12016-12-30 18:10:37 -06001635 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001636 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1637
1638 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001639}
1640
1641int PageManager::Update(void)
1642{
Matt Mowera8a89d12016-12-30 18:10:37 -06001643 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001644 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001645
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001646 if (RunReload())
1647 return -2;
1648
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001649 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1650
Matt Mowera8a89d12016-12-30 18:10:37 -06001651 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001652 {
1653 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001654 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001655 res = c_res;
1656 }
1657 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001658}
1659
1660int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1661{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001662 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001663}
1664
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001665int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001666{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001667 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001668}
1669
that8834a0f2016-01-05 23:29:30 +01001670int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001671{
that8834a0f2016-01-05 23:29:30 +01001672 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001673}
1674
1675int PageManager::SetKeyBoardFocus(int inFocus)
1676{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001677 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001678}
1679
1680int PageManager::NotifyVarChange(std::string varName, std::string value)
1681{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001682 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001683}
1684
Ethan Yonker74db1572015-10-28 12:44:49 -05001685void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1686{
1687 if (mCurrentSet)
1688 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1689}
1690
Dees_Troy51a0e822012-09-05 15:24:24 -04001691extern "C" void gui_notifyVarChange(const char *name, const char* value)
1692{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001693 if (!gGuiRunning)
1694 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001695
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001696 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001697}