blob: ebd2dbbf949aab99bfba402da998d060c427d75e [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
Ethan Yonker8373cfe2017-09-08 06:50:54 -050042#ifdef USE_MINZIP
43#include "../minzip/SysUtil.h"
44#else
bigbiffd58ba182020-03-23 10:02:29 -040045#ifdef USE_OTAUTIL_ZIPARCHIVE
Ethan Yonker58f21322018-08-24 11:17:36 -050046#include <otautil/SysUtil.h>
bigbiffd58ba182020-03-23 10:02:29 -040047#else
48#include <ziparchive/zip_archive.h>
49#endif
Ethan Yonker8373cfe2017-09-08 06:50:54 -050050#endif
51
Dees_Troy51a0e822012-09-05 15:24:24 -040052extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000053#include "../twcommon.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060054#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040055}
bigbiffd58ba182020-03-23 10:02:29 -040056#include "zipwrap.hpp"
Ethan Yonkerfbb43532015-12-28 21:54:50 +010057#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040058
59#include "rapidxml.hpp"
60#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020061#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040062
that74bff7f2017-01-18 22:32:36 +010063// version 2 requires theme to handle power button as action togglebacklight
Captain Throwback3b339542020-10-22 09:33:29 -040064// version 4 adds fastbootd support
65#define TW_THEME_VERSION 4
that74bff7f2017-01-18 22:32:36 +010066
Ethan Yonker8e5692f2016-01-21 11:21:06 -060067#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060068
Dees_Troy51a0e822012-09-05 15:24:24 -040069extern int gGuiRunning;
Mohd Farazd59a6042020-08-12 12:29:42 +000070GUITerminal* term = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040071
72std::map<std::string, PageSet*> PageManager::mPageSets;
73PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010074MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010075HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050076bool PageManager::mReloadTheme = false;
77std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050078std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040079
Ethan Yonker751a85e2014-12-12 16:59:10 -060080int tw_x_offset = 0;
81int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050082int tw_w_offset = 0;
83int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060084
Dees_Troy51a0e822012-09-05 15:24:24 -040085// Helper routine to convert a string to a color declaration
86int ConvertStrToColor(std::string str, COLOR* color)
87{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020088 // Set the default, solid black
89 memset(color, 0, sizeof(COLOR));
90 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040091
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020092 // Translate variables
93 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050094
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020095 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010096 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020097 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
98 else if (str == "red") { color->red = 255; return 0; }
99 else if (str == "green") { color->green = 255; return 0; }
100 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -0400101
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200102 // At this point, we require an RGB(A) color
103 if (str[0] != '#')
104 return -1;
105
106 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400107
Dees_Troy30b962e2012-10-19 20:48:59 -0400108 int result;
109 if (str.size() >= 8) {
110 // We have alpha channel
111 string alpha = str.substr(6, 2);
112 result = strtol(alpha.c_str(), NULL, 16);
113 color->alpha = result & 0x000000FF;
114 str.resize(6);
115 result = strtol(str.c_str(), NULL, 16);
116 color->red = (result >> 16) & 0x000000FF;
117 color->green = (result >> 8) & 0x000000FF;
118 color->blue = result & 0x000000FF;
119 } else {
120 result = strtol(str.c_str(), NULL, 16);
121 color->red = (result >> 16) & 0x000000FF;
122 color->green = (result >> 8) & 0x000000FF;
123 color->blue = result & 0x000000FF;
124 }
125 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400126}
127
128// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600129xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
130{
that8d46c092015-02-26 01:30:04 +0100131 if (!parent)
132 return NULL;
133
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600134 xml_node<>* child = parent->first_node(nodename);
135 if (child)
136 return child;
137
138 if (depth == 10) {
139 LOGERR("Too many style loops detected.\n");
140 return NULL;
141 }
142
143 xml_node<>* style = parent->first_node("style");
144 if (style) {
145 while (style) {
146 if (!style->first_attribute("name")) {
147 LOGERR("No name given for style.\n");
148 continue;
149 } else {
150 std::string name = style->first_attribute("name")->value();
151 xml_node<>* node = PageManager::FindStyle(name);
152
153 if (node) {
154 // We found the style that was named
155 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
156 if (stylenode)
157 return stylenode;
158 }
159 }
160 style = style->next_sibling("style");
161 }
162 } else {
that54e9c832015-11-04 21:46:01 +0100163 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600164 xml_attribute<>* attr = parent->first_attribute("style");
165 // If no style is found anywhere else and the node wasn't found in the object itself
166 // as a special case we will search for a style that uses the same style name as the
167 // object type, so <object type="button"> would search for a style named "button"
168 if (!attr)
169 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100170 // if there's no attribute type, the object type must be the element name
171 std::string stylename = attr ? attr->value() : parent->name();
172 xml_node<>* node = PageManager::FindStyle(stylename);
173 if (node) {
174 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
175 if (stylenode)
176 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600177 }
178 }
179 return NULL;
180}
181
thatf6ed8fc2015-02-14 20:23:16 +0100182std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
183{
184 if (!element)
185 return defaultvalue;
186
187 xml_attribute<>* attr = element->first_attribute(attrname);
188 return attr ? attr->value() : defaultvalue;
189}
190
191int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
192{
193 string value = LoadAttrString(element, attrname);
194 // resolve variables
195 DataManager::GetValue(value, value);
196 return value.empty() ? defaultvalue : atoi(value.c_str());
197}
198
199int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
200{
201 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
202}
203
204int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
205{
206 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
207}
208
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600209COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100210{
211 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600212 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100213 // resolve variables
214 DataManager::GetValue(value, value);
215 COLOR ret = defaultvalue;
216 if (ConvertStrToColor(value, &ret) == 0)
217 return ret;
218 else
219 return defaultvalue;
220}
221
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600222COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
223{
224 bool found_color = false;
225 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
226}
227
thatf6ed8fc2015-02-14 20:23:16 +0100228FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
229{
230 std::string name = LoadAttrString(element, attrname, "");
231 if (name.empty())
232 return NULL;
233 else
that74ac6062015-03-04 22:39:34 +0100234 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100235}
236
237ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
238{
239 std::string name = LoadAttrString(element, attrname, "");
240 if (name.empty())
241 return NULL;
242 else
that74ac6062015-03-04 22:39:34 +0100243 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100244}
245
246AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
247{
248 std::string name = LoadAttrString(element, attrname, "");
249 if (name.empty())
250 return NULL;
251 else
that74ac6062015-03-04 22:39:34 +0100252 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100253}
254
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500255bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400256{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 if (!node)
258 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400259
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100261 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400262
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200263 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100264 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400265
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200266 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100267 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400268
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200269 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100270 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400271
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200272 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500273 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400274
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400276}
277
278int ActionObject::SetActionPos(int x, int y, int w, int h)
279{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200280 if (x < 0 || y < 0)
281 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400282
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500283 mActionX = x;
284 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200285 if (w || h)
286 {
287 mActionW = w;
288 mActionH = h;
289 }
290 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400291}
292
thatb63e2f92015-06-27 21:35:11 +0200293Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400294{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200295 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400296
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200297 // We can memset the whole structure, because the alpha channel is ignored
298 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400299
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200300 // With NULL, we make a console-only display
301 if (!page)
302 {
303 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400304
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200305 GUIConsole* element = new GUIConsole(NULL);
306 mRenders.push_back(element);
307 mActions.push_back(element);
308 return;
309 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400310
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200311 if (page->first_attribute("name"))
312 mName = page->first_attribute("name")->value();
313 else
314 {
315 LOGERR("No page name attribute found!\n");
316 return;
317 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400318
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200319 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400320
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200321 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200322 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400323}
324
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100325Page::~Page()
326{
327 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
328 delete *itr;
329}
330
thatb63e2f92015-06-27 21:35:11 +0200331bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400332{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200333 if (depth == 10)
334 {
335 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
336 return false;
337 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400338
thatb63e2f92015-06-27 21:35:11 +0200339 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200340 {
thatb63e2f92015-06-27 21:35:11 +0200341 std::string type = child->name();
342
343 if (type == "background") {
344 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
345 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200346 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400347
thatb63e2f92015-06-27 21:35:11 +0200348 if (type == "object") {
349 // legacy format : <object type="...">
350 xml_attribute<>* attr = child->first_attribute("type");
351 type = attr ? attr->value() : "*unspecified*";
352 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400353
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200354 if (type == "text")
355 {
356 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100357 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200358 mRenders.push_back(element);
359 mActions.push_back(element);
360 }
361 else if (type == "image")
362 {
363 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100364 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200365 mRenders.push_back(element);
366 }
367 else if (type == "fill")
368 {
369 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100370 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200371 mRenders.push_back(element);
372 }
373 else if (type == "action")
374 {
375 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100376 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200377 mActions.push_back(element);
378 }
379 else if (type == "console")
380 {
381 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100382 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200383 mRenders.push_back(element);
384 mActions.push_back(element);
385 }
that1964d192016-01-07 00:41:03 +0100386 else if (type == "terminal")
387 {
388 GUITerminal* element = new GUITerminal(child);
389 mObjects.push_back(element);
390 mRenders.push_back(element);
391 mActions.push_back(element);
392 mInputs.push_back(element);
Mohd Farazd59a6042020-08-12 12:29:42 +0000393 term = element;
that1964d192016-01-07 00:41:03 +0100394 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200395 else if (type == "button")
396 {
397 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100398 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200399 mRenders.push_back(element);
400 mActions.push_back(element);
401 }
402 else if (type == "checkbox")
403 {
404 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100405 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200406 mRenders.push_back(element);
407 mActions.push_back(element);
408 }
409 else if (type == "fileselector")
410 {
411 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100412 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 mRenders.push_back(element);
414 mActions.push_back(element);
415 }
416 else if (type == "animation")
417 {
418 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100419 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200420 mRenders.push_back(element);
421 }
422 else if (type == "progressbar")
423 {
424 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100425 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200426 mRenders.push_back(element);
427 mActions.push_back(element);
428 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400429 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200430 {
431 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100432 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200433 mRenders.push_back(element);
434 mActions.push_back(element);
435 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200436 else if (type == "slidervalue")
437 {
438 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100439 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200440 mRenders.push_back(element);
441 mActions.push_back(element);
442 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400443 else if (type == "listbox")
444 {
445 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100446 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400447 mRenders.push_back(element);
448 mActions.push_back(element);
449 }
450 else if (type == "keyboard")
451 {
452 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100453 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400454 mRenders.push_back(element);
455 mActions.push_back(element);
456 }
457 else if (type == "input")
458 {
459 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100460 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400461 mRenders.push_back(element);
462 mActions.push_back(element);
463 mInputs.push_back(element);
464 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500465 else if (type == "partitionlist")
466 {
467 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100468 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500469 mRenders.push_back(element);
470 mActions.push_back(element);
471 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100472 else if (type == "patternpassword")
473 {
474 GUIPatternPassword* element = new GUIPatternPassword(child);
475 mObjects.push_back(element);
476 mRenders.push_back(element);
477 mActions.push_back(element);
478 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500479 else if (type == "textbox")
480 {
481 GUITextBox* element = new GUITextBox(child);
482 mObjects.push_back(element);
483 mRenders.push_back(element);
484 mActions.push_back(element);
485 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200486 else if (type == "template")
487 {
488 if (!templates || !child->first_attribute("name"))
489 {
490 LOGERR("Invalid template request.\n");
491 }
492 else
493 {
494 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500495 xml_node<>* node;
496 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400497
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200498 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500499 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
500 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400501
Ethan Yonker780cd392014-07-21 15:24:39 -0500502 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200503 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500504 if (!node->first_attribute("name"))
505 continue;
506
507 if (name == node->first_attribute("name")->value())
508 {
509 if (!ProcessNode(node, templates, depth + 1))
510 return false;
511 else {
512 node_found = true;
513 break;
514 }
515 }
516 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500518 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200519 }
thatb63e2f92015-06-27 21:35:11 +0200520 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200521 }
522 }
523 }
524 else
525 {
thatb63e2f92015-06-27 21:35:11 +0200526 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200527 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200528 }
529 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400530}
531
532int Page::Render(void)
533{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200534 // Render background
535 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
536 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400537
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200538 // Render remaining objects
539 std::vector<RenderObject*>::iterator iter;
540 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
541 {
542 if ((*iter)->Render())
543 LOGERR("A render request has failed.\n");
544 }
545 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400546}
547
548int Page::Update(void)
549{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400551
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200552 std::vector<RenderObject*>::iterator iter;
553 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
554 {
555 int ret = (*iter)->Update();
556 if (ret < 0)
557 LOGERR("An update request has failed.\n");
558 else if (ret > retCode)
559 retCode = ret;
560 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400561
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200562 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400563}
564
565int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
566{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200567 // By default, return 1 to ignore further touches if nobody is listening
568 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400569
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200570 // Don't try to handle a lack of handlers
571 if (mActions.size() == 0)
572 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400573
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200574 // We record mTouchStart so we can pass all the touch stream to the same handler
575 if (state == TOUCH_START)
576 {
577 std::vector<ActionObject*>::reverse_iterator iter;
578 // We work backwards, from top-most element to bottom-most element
579 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
580 {
581 if ((*iter)->IsInRegion(x, y))
582 {
583 mTouchStart = (*iter);
584 ret = mTouchStart->NotifyTouch(state, x, y);
585 if (ret >= 0)
586 break;
587 mTouchStart = NULL;
588 }
589 }
590 }
591 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
592 {
593 ret = mTouchStart->NotifyTouch(state, x, y);
594 mTouchStart = NULL;
595 }
596 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
597 {
598 ret = mTouchStart->NotifyTouch(state, x, y);
599 }
600 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400601}
602
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100603int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400604{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200605 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400606
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100607 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 // We work backwards, from top-most element to bottom-most element
609 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
610 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100611 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100612 if (ret == 0)
613 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100614 if (ret < 0) {
615 LOGERR("An action handler has returned an error\n");
616 ret = 1;
617 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200618 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100619 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400620}
621
that8834a0f2016-01-05 23:29:30 +0100622int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400623{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200624 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400625
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200626 // We work backwards, from top-most element to bottom-most element
627 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
628 {
that8834a0f2016-01-05 23:29:30 +0100629 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200630 if (ret == 0)
631 return 0;
632 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100633 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200634 }
635 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400636}
637
638int Page::SetKeyBoardFocus(int inFocus)
639{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200640 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400641
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200642 // We work backwards, from top-most element to bottom-most element
643 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
644 {
645 int ret = (*iter)->SetInputFocus(inFocus);
646 if (ret == 0)
647 return 0;
648 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100649 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200650 }
651 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400652}
653
654void Page::SetPageFocus(int inFocus)
655{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200656 // Render remaining objects
657 std::vector<RenderObject*>::iterator iter;
658 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
659 (*iter)->SetPageFocus(inFocus);
660
661 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400662}
663
664int Page::NotifyVarChange(std::string varName, std::string value)
665{
Vojtech Bocek07220562014-02-08 02:05:33 +0100666 std::vector<GUIObject*>::iterator iter;
667 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200668 {
669 if ((*iter)->NotifyVarChange(varName, value))
670 LOGERR("An action handler errored on NotifyVarChange.\n");
671 }
672 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400673}
674
that6a894592016-03-13 17:51:28 +0100675
676// transient data for loading themes
677struct LoadingContext
678{
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500679 ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100680 std::set<std::string> filenames; // to detect cyclic includes
681 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
682 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
683 std::vector<char*> xmlbuffers; // text buffers with xml content
684 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
685 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
686
687 LoadingContext()
688 {
689 zip = NULL;
690 }
691
692 ~LoadingContext()
693 {
694 // free all xml buffers
695 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
696 free(*it);
697 }
698
699};
700
701// for FindStyle
702LoadingContext* PageManager::currentLoadingContext = NULL;
703
704
705PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400706{
that74ac6062015-03-04 22:39:34 +0100707 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200708 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400709
that6a894592016-03-13 17:51:28 +0100710 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400711}
712
713PageSet::~PageSet()
714{
Ethan Yonker1c273312015-03-16 12:18:56 -0500715 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100716 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
717 delete *itr;
718
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200719 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400720}
721
that6a894592016-03-13 17:51:28 +0100722int PageSet::Load(LoadingContext& ctx, const std::string& filename)
723{
724 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
725
726 if (!ctx.filenames.insert(filename).second)
727 // ignore already loaded files to prevent crash with cyclic includes
728 return 0;
729
730 // load XML into buffer
731 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
732 if (!xmlbuffer)
733 return -1; // error already displayed by LoadFileToBuffer
734 ctx.xmlbuffers.push_back(xmlbuffer);
735
736 // parse XML
737 xml_document<>* doc = new xml_document<>();
738 doc->parse<0>(xmlbuffer);
739 ctx.xmldocs.push_back(doc);
740
741 xml_node<>* root = doc->first_node("recovery");
742 if (!root)
743 root = doc->first_node("install");
744 if (!root) {
745 LOGERR("Unknown root element in %s\n", filename.c_str());
746 return -1;
747 }
748
749 if (isMain) {
750 int rc = LoadDetails(ctx, root);
751 if (rc != 0)
752 return rc;
753 }
754
755 LOGINFO("Loading resources...\n");
756 xml_node<>* child = root->first_node("resources");
757 if (child)
758 mResources->LoadResources(child, ctx.zip, "theme");
759
760 LOGINFO("Loading variables...\n");
761 child = root->first_node("variables");
762 if (child)
763 LoadVariables(child);
764
765 LOGINFO("Loading mouse cursor...\n");
766 child = root->first_node("mousecursor");
767 if (child)
768 PageManager::LoadCursorData(child);
769
770 LOGINFO("Loading pages...\n");
771 child = root->first_node("templates");
772 if (child)
773 ctx.templates.push_back(child);
774
775 child = root->first_node("styles");
776 if (child)
777 ctx.styles.push_back(child);
778
779 // Load pages
780 child = root->first_node("pages");
781 if (child) {
782 if (LoadPages(ctx, child)) {
783 LOGERR("PageSet::Load returning -1\n");
784 return -1;
785 }
786 }
787
788 // process includes recursively
789 child = root->first_node("include");
790 if (child) {
791 xml_node<>* include = child->first_node("xmlfile");
792 while (include != NULL) {
793 xml_attribute<>* attr = include->first_attribute("name");
794 if (!attr) {
795 LOGERR("Skipping include/xmlfile with no name\n");
796 continue;
797 }
798
799 string filename = ctx.basepath + attr->value();
800 LOGINFO("Including file: %s...\n", filename.c_str());
801 int rc = Load(ctx, filename);
802 if (rc != 0)
803 return rc;
804
805 include = include->next_sibling("xmlfile");
806 }
807 }
808
809 return 0;
810}
811
812void PageSet::MakeEmergencyConsoleIfNeeded()
813{
814 if (mPages.empty()) {
815 mCurrentPage = new Page(NULL, NULL); // fallback console page
816 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
817 mPages.push_back(mCurrentPage);
818 }
819}
820
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500821int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500822{
823 xml_document<> lang;
824 xml_node<>* parent;
825 xml_node<>* child;
826 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600827 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500828
829 if (languageFile) {
830 printf("parsing languageFile\n");
831 lang.parse<0>(languageFile);
832 printf("parsing languageFile done\n");
833 } else {
834 return -1;
835 }
836
837 parent = lang.first_node("language");
838 if (!parent) {
839 LOGERR("Unable to locate language node in language file.\n");
840 lang.clear();
841 return -1;
842 }
843
844 child = parent->first_node("display");
845 if (child) {
846 DataManager::SetValue("tw_language_display", child->value());
847 resource_source = child->value();
848 } else {
849 LOGERR("language file does not have a display value set\n");
850 DataManager::SetValue("tw_language_display", "Not Set");
851 resource_source = languageFile;
852 }
853
854 child = parent->first_node("resources");
855 if (child)
856 mResources->LoadResources(child, package, resource_source);
857 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600858 ret = -1;
859 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500860 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600861 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500862}
863
that6a894592016-03-13 17:51:28 +0100864int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400865{
that6a894592016-03-13 17:51:28 +0100866 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600867 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600868 int theme_ver = 0;
869 xml_node<>* themeversion = child->first_node("themeversion");
870 if (themeversion && themeversion->value()) {
871 theme_ver = atoi(themeversion->value());
872 } else {
873 LOGINFO("No themeversion in theme.\n");
874 }
875 if (theme_ver != TW_THEME_VERSION) {
876 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100877 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600878 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600879 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600880 } else {
881 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
882 }
883 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600884 xml_node<>* resolution = child->first_node("resolution");
885 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600886 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600887 xml_attribute<>* width_attr = resolution->first_attribute("width");
888 xml_attribute<>* height_attr = resolution->first_attribute("height");
889 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
890 if (width_attr && height_attr && !noscale_attr) {
891 int width = atoi(width_attr->value());
892 int height = atoi(height_attr->value());
893 int offx = 0, offy = 0;
894#ifdef TW_ROUND_SCREEN
895 xml_node<>* roundscreen = child->first_node("roundscreen");
896 if (roundscreen) {
897 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
898 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
899 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
900 if (offx_attr) {
901 offx = atoi(offx_attr->value());
902 }
903 if (offy_attr) {
904 offy = atoi(offy_attr->value());
905 }
906 }
907#endif
908 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500909 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
910 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600911#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500912 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
913 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600914 tw_x_offset = offx * scale_off_w;
915 tw_y_offset = offy * scale_off_h;
916#endif
917 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500918 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
919 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600920 set_scale_values(scale_w, scale_h);
921 }
922 }
923 } else {
924 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
925 }
926 } else {
927 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
928 }
929 } else {
930 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
931 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500932
Ethan Yonker780cd392014-07-21 15:24:39 -0500933 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400934}
935
936int PageSet::SetPage(std::string page)
937{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200938 Page* tmp = FindPage(page);
939 if (tmp)
940 {
941 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
942 mCurrentPage = tmp;
943 mCurrentPage->SetPageFocus(1);
944 mCurrentPage->NotifyVarChange("", "");
945 return 0;
946 }
947 else
948 {
949 LOGERR("Unable to locate page (%s)\n", page.c_str());
950 }
951 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400952}
953
954int PageSet::SetOverlay(Page* page)
955{
Ethan Yonker1c273312015-03-16 12:18:56 -0500956 if (page) {
957 if (mOverlays.size() >= 10) {
958 LOGERR("Too many overlays requested, max is 10.\n");
959 return -1;
960 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500961
962 std::vector<Page*>::iterator iter;
963 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
964 if ((*iter)->GetName() == page->GetName()) {
965 mOverlays.erase(iter);
966 // SetOverlay() is (and should stay) the only function which
967 // adds to mOverlays. Then, each page can appear at most once.
968 break;
969 }
970 }
971
Ethan Yonker1c273312015-03-16 12:18:56 -0500972 page->SetPageFocus(1);
973 page->NotifyVarChange("", "");
974
975 if (!mOverlays.empty())
976 mOverlays.back()->SetPageFocus(0);
977
978 mOverlays.push_back(page);
979 } else {
980 if (!mOverlays.empty()) {
981 mOverlays.back()->SetPageFocus(0);
982 mOverlays.pop_back();
983 if (!mOverlays.empty())
984 mOverlays.back()->SetPageFocus(1);
985 else if (mCurrentPage)
986 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
987 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200988 }
989 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400990}
991
that74ac6062015-03-04 22:39:34 +0100992const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400993{
that74ac6062015-03-04 22:39:34 +0100994 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400995}
996
997Page* PageSet::FindPage(std::string name)
998{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200999 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001000
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001001 for (iter = mPages.begin(); iter != mPages.end(); iter++)
1002 {
1003 if (name == (*iter)->GetName())
1004 return (*iter);
1005 }
1006 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001007}
1008
1009int PageSet::LoadVariables(xml_node<>* vars)
1010{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001011 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001012 xml_attribute<> *name, *value, *persist;
1013 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001014
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001015 child = vars->first_node("variable");
1016 while (child)
1017 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001018 name = child->first_attribute("name");
1019 value = child->first_attribute("value");
1020 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001021 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001022 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001023 if (strcmp(name->value(), "tw_x_offset") == 0) {
1024 tw_x_offset = atoi(value->value());
1025 child = child->next_sibling("variable");
1026 continue;
1027 }
1028 if (strcmp(name->value(), "tw_y_offset") == 0) {
1029 tw_y_offset = atoi(value->value());
1030 child = child->next_sibling("variable");
1031 continue;
1032 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001033 if (strcmp(name->value(), "tw_w_offset") == 0) {
1034 tw_w_offset = atoi(value->value());
1035 child = child->next_sibling("variable");
1036 continue;
1037 }
1038 if (strcmp(name->value(), "tw_h_offset") == 0) {
1039 tw_h_offset = atoi(value->value());
1040 child = child->next_sibling("variable");
1041 continue;
1042 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001043 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001044 string temp = value->value();
1045 string valstr = gui_parse_text(temp);
1046
1047 if (valstr.find("+") != string::npos) {
1048 string val1str = valstr;
1049 val1str = val1str.substr(0, val1str.find('+'));
1050 string val2str = valstr;
1051 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1052 int val1 = atoi(val1str.c_str());
1053 int val2 = atoi(val2str.c_str());
1054 int val = val1 + val2;
1055
1056 DataManager::SetValue(name->value(), val, p);
1057 } else if (valstr.find("-") != string::npos) {
1058 string val1str = valstr;
1059 val1str = val1str.substr(0, val1str.find('-'));
1060 string val2str = valstr;
1061 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1062 int val1 = atoi(val1str.c_str());
1063 int val2 = atoi(val2str.c_str());
1064 int val = val1 - val2;
1065
1066 DataManager::SetValue(name->value(), val, p);
1067 } else {
1068 DataManager::SetValue(name->value(), valstr, p);
1069 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001070 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001071
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001072 child = child->next_sibling("variable");
1073 }
1074 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001075}
1076
that6a894592016-03-13 17:51:28 +01001077int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001078{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001079 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001080
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001081 if (!pages)
1082 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001083
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001084 child = pages->first_node("page");
1085 while (child != NULL)
1086 {
that6a894592016-03-13 17:51:28 +01001087 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001088 if (page->GetName().empty())
1089 {
1090 LOGERR("Unable to process load page\n");
1091 delete page;
1092 }
1093 else
1094 {
1095 mPages.push_back(page);
1096 }
1097 child = child->next_sibling("page");
1098 }
1099 if (mPages.size() > 0)
1100 return 0;
1101 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001102}
1103
1104int PageSet::IsCurrentPage(Page* page)
1105{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001106 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001107}
1108
that10ae24f2015-12-26 20:53:51 +01001109std::string PageSet::GetCurrentPage() const
1110{
1111 return mCurrentPage ? mCurrentPage->GetName() : "";
1112}
1113
Dees_Troy51a0e822012-09-05 15:24:24 -04001114int PageSet::Render(void)
1115{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001116 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001117
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001118 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1119 if (ret < 0)
1120 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001121
1122 std::vector<Page*>::iterator iter;
1123
1124 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1125 ret = ((*iter) ? (*iter)->Render() : -1);
1126 if (ret < 0)
1127 return ret;
1128 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001129 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001130}
1131
1132int PageSet::Update(void)
1133{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001134 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001135
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001136 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1137 if (ret < 0 || ret > 1)
1138 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001139
1140 std::vector<Page*>::iterator iter;
1141
1142 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1143 ret = ((*iter) ? (*iter)->Update() : -1);
1144 if (ret < 0)
1145 return ret;
1146 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001147 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001148}
1149
1150int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1151{
Ethan Yonker1c273312015-03-16 12:18:56 -05001152 if (!mOverlays.empty())
1153 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001154
1155 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001156}
1157
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001158int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001159{
Ethan Yonker1c273312015-03-16 12:18:56 -05001160 if (!mOverlays.empty())
1161 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001162
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001163 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001164}
1165
that8834a0f2016-01-05 23:29:30 +01001166int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001167{
Ethan Yonker1c273312015-03-16 12:18:56 -05001168 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001169 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001170
that8834a0f2016-01-05 23:29:30 +01001171 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001172}
1173
1174int PageSet::SetKeyBoardFocus(int inFocus)
1175{
Ethan Yonker1c273312015-03-16 12:18:56 -05001176 if (!mOverlays.empty())
1177 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001178
1179 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001180}
1181
1182int PageSet::NotifyVarChange(std::string varName, std::string value)
1183{
Ethan Yonker1c273312015-03-16 12:18:56 -05001184 std::vector<Page*>::iterator iter;
1185
1186 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1187 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001188
1189 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001190}
1191
Ethan Yonker74db1572015-10-28 12:44:49 -05001192void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1193{
1194 mResources->AddStringResource(resource_source, resource_name, value);
1195}
1196
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001197char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001198 size_t len;
1199 char* buffer = NULL;
1200
1201 if (!package) {
1202 // We can try to load the XML directly...
1203 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1204 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001205 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001206 // This isn't always an error, sometimes we request files that don't exist.
1207 return NULL;
1208 }
1209
1210 len = (size_t)st.st_size;
1211
1212 buffer = (char*) malloc(len + 1);
1213 if (!buffer) {
1214 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1215 return NULL;
1216 }
1217
1218 int fd = open(filename.c_str(), O_RDONLY);
1219 if (fd == -1) {
1220 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1221 free(buffer);
1222 return NULL;
1223 }
1224
1225 if (read(fd, buffer, len) < 0) {
1226 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1227 free(buffer);
1228 close(fd);
1229 return NULL;
1230 }
1231 close(fd);
1232 } else {
1233 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001234 if (!package->EntryExists(filename)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001235 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1236 return NULL;
1237 }
1238
1239 // Allocate the buffer for the file
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001240 len = package->GetUncompressedSize(filename);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001241 buffer = (char*) malloc(len + 1);
1242 if (!buffer)
1243 return NULL;
1244
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001245 if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001246 LOGERR("Unable to extract '%s'\n", filename.c_str());
1247 free(buffer);
1248 return NULL;
1249 }
1250 }
1251 // NULL-terminate the string
1252 buffer[len] = 0x00;
1253 return buffer;
1254}
1255
Ethan Yonker74db1572015-10-28 12:44:49 -05001256void PageManager::LoadLanguageListDir(string dir) {
1257 if (!TWFunc::Path_Exists(dir)) {
1258 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1259 return;
1260 }
1261
1262 DIR *d = opendir(dir.c_str());
1263 struct dirent *p;
1264
1265 if (d == NULL) {
1266 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1267 return;
1268 }
1269
1270 while ((p = readdir(d))) {
1271 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1272 continue;
1273
1274 string file = p->d_name;
1275 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1276 continue;
1277 string path = dir + p->d_name;
1278 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1279 struct language_struct language_entry;
1280 language_entry.filename = file_no_extn;
1281 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1282 if (xmlFile == NULL) {
1283 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1284 continue;
1285 }
1286 xml_document<> *doc = new xml_document<>();
1287 doc->parse<0>(xmlFile);
1288
1289 xml_node<>* parent = doc->first_node("language");
1290 if (!parent) {
1291 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1292 } else {
1293 xml_node<>* child = parent->first_node("display");
1294 if (child) {
1295 language_entry.displayvalue = child->value();
1296 } else {
1297 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1298 language_entry.displayvalue = language_entry.filename;
1299 }
1300 Language_List.push_back(language_entry);
1301 }
1302 doc->clear();
1303 delete doc;
1304 free(xmlFile);
1305 }
1306 closedir(d);
1307}
1308
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001309void PageManager::LoadLanguageList(ZipWrap* package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001310 Language_List.clear();
1311 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1312 TWFunc::removeDir(TWRES "customlanguages", true);
1313 if (package) {
1314 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001315 package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001316 LoadLanguageListDir(TWRES "customlanguages/");
1317 } else {
1318 LoadLanguageListDir(TWRES "languages/");
1319 }
Xuefercac6ace2016-02-01 02:28:55 +08001320
1321 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001322}
1323
1324void PageManager::LoadLanguage(string filename) {
1325 string actual_filename;
1326 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1327 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1328 else
1329 actual_filename = TWRES "languages/" + filename + ".xml";
1330 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1331 if (xmlFile == NULL)
1332 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1333 else {
1334 mCurrentSet->LoadLanguage(xmlFile, NULL);
1335 free(xmlFile);
1336 }
1337 PartitionManager.Translate_Partition_Display_Names();
1338}
1339
Dees_Troy51a0e822012-09-05 15:24:24 -04001340int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1341{
that6a894592016-03-13 17:51:28 +01001342 std::string mainxmlfilename = package;
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001343 ZipWrap zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001344 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001345 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001346 PageSet* pageSet = NULL;
1347 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001348 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001349
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001350 mReloadTheme = false;
1351 mStartPage = startpage;
1352
that6a894592016-03-13 17:51:28 +01001353 // init the loading context
1354 LoadingContext ctx;
1355
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001356 // Open the XML file
1357 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001358 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001359 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001360 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001361 tw_x_offset = TW_X_OFFSET;
1362 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001363 tw_w_offset = TW_W_OFFSET;
1364 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001365 if (name != "splash") {
1366 LoadLanguageList(NULL);
1367 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1368 }
that6a894592016-03-13 17:51:28 +01001369 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001370 }
1371 else
1372 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001373 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001374 tw_x_offset = 0;
1375 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001376 tw_w_offset = 0;
1377 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001378 if (!TWFunc::Path_Exists(package))
1379 return -1;
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001380#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001381 if (sysMapFile(package.c_str(), &map) != 0) {
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001382#else
1383 if (!map.MapFile(package)) {
1384#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001385 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001386 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001387 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001388 if (!zip.Open(package.c_str(), &map)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001389 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001390#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001391 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001392#endif
Ethan Yonker561c58d2015-10-05 08:48:22 -05001393 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001394 }
that6a894592016-03-13 17:51:28 +01001395 ctx.zip = &zip;
1396 mainxmlfilename = "ui.xml";
1397 LoadLanguageList(ctx.zip);
1398 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001399 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001400 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001401
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001402 // Before loading, mCurrentSet must be the loading package so we can find resources
1403 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001404 mCurrentSet = new PageSet();
1405
1406 if (baseLanguageFile) {
1407 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1408 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001409 }
that6a894592016-03-13 17:51:28 +01001410
1411 if (languageFile) {
1412 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1413 free(languageFile);
1414 }
1415
1416 // Load and parse the XML and all includes
1417 currentLoadingContext = &ctx; // required to find styles
1418 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1419 currentLoadingContext = NULL;
1420
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001421 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001422 mCurrentSet->SetPage(startpage);
1423 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001424 } else {
1425 if (ret != TW_THEME_VER_ERR)
1426 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001427 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001428
that6a894592016-03-13 17:51:28 +01001429 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001430 mCurrentSet = pageSet;
1431
that6a894592016-03-13 17:51:28 +01001432 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001433 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001434#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001435 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001436#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001437 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001438 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001439
1440error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001441 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001442 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001443 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001444#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001445 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001446#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001447 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001448 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001449}
1450
1451PageSet* PageManager::FindPackage(std::string name)
1452{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001453 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001454
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001455 iter = mPageSets.find(name);
1456 if (iter != mPageSets.end())
1457 return (*iter).second;
1458
1459 LOGERR("Unable to locate package %s\n", name.c_str());
1460 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001461}
1462
1463PageSet* PageManager::SelectPackage(std::string name)
1464{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001465 LOGINFO("Switching packages (%s)\n", name.c_str());
1466 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001467
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 tmp = FindPackage(name);
1469 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001470 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001471 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001472 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001473 mCurrentSet->NotifyVarChange("", "");
1474 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001475 else
1476 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001477
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001478 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001479}
1480
1481int PageManager::ReloadPackage(std::string name, std::string package)
1482{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001483 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001484
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001485 mReloadTheme = false;
1486
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001487 iter = mPageSets.find(name);
1488 if (iter == mPageSets.end())
1489 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001490
Matt Mowera8a89d12016-12-30 18:10:37 -06001491 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001492 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1493
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001494 PageSet* set = (*iter).second;
1495 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001496
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001497 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001498 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001499 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001500 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1501 return -1;
1502 }
1503 if (mCurrentSet == set)
1504 SelectPackage(name);
1505 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001506 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001507 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001508}
1509
1510void PageManager::ReleasePackage(std::string name)
1511{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001512 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001513
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001514 iter = mPageSets.find(name);
1515 if (iter == mPageSets.end())
1516 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001517
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001518 PageSet* set = (*iter).second;
1519 mPageSets.erase(iter);
1520 delete set;
that235c6482016-01-24 21:59:00 +01001521 if (set == mCurrentSet)
1522 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001523 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001524}
1525
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001526int PageManager::RunReload() {
1527 int ret_val = 0;
1528 std::string theme_path;
1529
1530 if (!mReloadTheme)
1531 return 0;
1532
1533 mReloadTheme = false;
1534 theme_path = DataManager::GetSettingsStoragePath();
1535 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1536 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1537 ret_val = 1;
1538 }
1539
1540 theme_path += "/TWRP/theme/ui.zip";
1541 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1542 {
1543 // Loading the custom theme failed - try loading the stock theme
1544 LOGINFO("Attempting to reload stock theme...\n");
1545 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1546 {
1547 LOGERR("Failed to load base packages.\n");
1548 ret_val = 1;
1549 }
1550 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001551 if (ret_val == 0) {
1552 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1553 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1554 LoadLanguage(DataManager::GetStrValue("tw_language"));
1555 }
1556 }
1557
1558 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001559 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001560
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001561 return ret_val;
1562}
1563
1564void PageManager::RequestReload() {
1565 mReloadTheme = true;
1566}
1567
Ethan Yonkerafde0982016-01-23 08:55:35 -06001568void PageManager::SetStartPage(const std::string& page_name) {
1569 mStartPage = page_name;
1570}
1571
Dees_Troy51a0e822012-09-05 15:24:24 -04001572int PageManager::ChangePage(std::string name)
1573{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001574 DataManager::SetValue("tw_operation_state", 0);
1575 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1576 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001577}
1578
that10ae24f2015-12-26 20:53:51 +01001579std::string PageManager::GetCurrentPage()
1580{
1581 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1582}
1583
Dees_Troy51a0e822012-09-05 15:24:24 -04001584int PageManager::ChangeOverlay(std::string name)
1585{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001586 if (name.empty())
1587 return mCurrentSet->SetOverlay(NULL);
1588 else
1589 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001590 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001591 return mCurrentSet->SetOverlay(page);
1592 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001593}
1594
that74ac6062015-03-04 22:39:34 +01001595const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001596{
that74ac6062015-03-04 22:39:34 +01001597 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001598}
1599
Dees_Troy51a0e822012-09-05 15:24:24 -04001600int PageManager::IsCurrentPage(Page* page)
1601{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001602 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001603}
1604
1605int PageManager::Render(void)
1606{
Matt Mowera8a89d12016-12-30 18:10:37 -06001607 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001608 return 0;
1609
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001610 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001611 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001612 mMouseCursor->Render();
1613 return res;
1614}
1615
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001616HardwareKeyboard *PageManager::GetHardwareKeyboard()
1617{
Matt Mowera8a89d12016-12-30 18:10:37 -06001618 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001619 mHardwareKeyboard = new HardwareKeyboard();
1620 return mHardwareKeyboard;
1621}
1622
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001623xml_node<>* PageManager::FindStyle(std::string name)
1624{
that6a894592016-03-13 17:51:28 +01001625 if (!currentLoadingContext)
1626 {
1627 LOGERR("FindStyle works only while loading a theme.\n");
1628 return NULL;
1629 }
1630
1631 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001632 xml_node<>* node = (*itr)->first_node("style");
1633
1634 while (node) {
1635 if (!node->first_attribute("name"))
1636 continue;
1637
1638 if (name == node->first_attribute("name")->value())
1639 return node;
1640 node = node->next_sibling("style");
1641 }
1642 }
1643 return NULL;
1644}
1645
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001646MouseCursor *PageManager::GetMouseCursor()
1647{
Matt Mowera8a89d12016-12-30 18:10:37 -06001648 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001649 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1650 return mMouseCursor;
1651}
1652
1653void PageManager::LoadCursorData(xml_node<>* node)
1654{
Matt Mowera8a89d12016-12-30 18:10:37 -06001655 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001656 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1657
1658 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001659}
1660
1661int PageManager::Update(void)
1662{
Matt Mowera8a89d12016-12-30 18:10:37 -06001663 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001664 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001665
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001666 if (RunReload())
1667 return -2;
1668
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001669 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1670
Matt Mowera8a89d12016-12-30 18:10:37 -06001671 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001672 {
1673 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001674 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001675 res = c_res;
1676 }
1677 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001678}
1679
1680int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1681{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001682 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001683}
1684
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001685int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001686{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001687 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001688}
1689
that8834a0f2016-01-05 23:29:30 +01001690int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001691{
that8834a0f2016-01-05 23:29:30 +01001692 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001693}
1694
1695int PageManager::SetKeyBoardFocus(int inFocus)
1696{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001697 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001698}
1699
1700int PageManager::NotifyVarChange(std::string varName, std::string value)
1701{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001702 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001703}
1704
Ethan Yonker74db1572015-10-28 12:44:49 -05001705void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1706{
1707 if (mCurrentSet)
1708 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1709}
1710
Dees_Troy51a0e822012-09-05 15:24:24 -04001711extern "C" void gui_notifyVarChange(const char *name, const char* value)
1712{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001713 if (!gGuiRunning)
1714 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001715
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001716 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001717}