blob: 366bc39363f9fe7923f63b6b57f4194554bae60f [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
Ethan Yonker58f21322018-08-24 11:17:36 -050045#include <otautil/SysUtil.h>
Ethan Yonker8373cfe2017-09-08 06:50:54 -050046#endif
47
Dees_Troy51a0e822012-09-05 15:24:24 -040048extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000049#include "../twcommon.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060050#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040051}
Ethan Yonker8373cfe2017-09-08 06:50:54 -050052#include "../zipwrap.hpp"
Ethan Yonkerfbb43532015-12-28 21:54:50 +010053#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040054
55#include "rapidxml.hpp"
56#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020057#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040058
that74bff7f2017-01-18 22:32:36 +010059// version 2 requires theme to handle power button as action togglebacklight
Captain Throwback268091d2020-10-22 09:33:29 -040060// version 4 adds listbox support to reboot page
61#define TW_THEME_VERSION 4
that74bff7f2017-01-18 22:32:36 +010062
Ethan Yonker8e5692f2016-01-21 11:21:06 -060063#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060064
Dees_Troy51a0e822012-09-05 15:24:24 -040065extern int gGuiRunning;
66
67std::map<std::string, PageSet*> PageManager::mPageSets;
68PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010069MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010070HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050071bool PageManager::mReloadTheme = false;
72std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050073std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040074
Ethan Yonker751a85e2014-12-12 16:59:10 -060075int tw_x_offset = 0;
76int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050077int tw_w_offset = 0;
78int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060079
Dees_Troy51a0e822012-09-05 15:24:24 -040080// Helper routine to convert a string to a color declaration
81int ConvertStrToColor(std::string str, COLOR* color)
82{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020083 // Set the default, solid black
84 memset(color, 0, sizeof(COLOR));
85 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040086
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 // Translate variables
88 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050089
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020090 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010091 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020092 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
93 else if (str == "red") { color->red = 255; return 0; }
94 else if (str == "green") { color->green = 255; return 0; }
95 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040096
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020097 // At this point, we require an RGB(A) color
98 if (str[0] != '#')
99 return -1;
100
101 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400102
Dees_Troy30b962e2012-10-19 20:48:59 -0400103 int result;
104 if (str.size() >= 8) {
105 // We have alpha channel
106 string alpha = str.substr(6, 2);
107 result = strtol(alpha.c_str(), NULL, 16);
108 color->alpha = result & 0x000000FF;
109 str.resize(6);
110 result = strtol(str.c_str(), NULL, 16);
111 color->red = (result >> 16) & 0x000000FF;
112 color->green = (result >> 8) & 0x000000FF;
113 color->blue = result & 0x000000FF;
114 } else {
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 }
120 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400121}
122
123// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600124xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
125{
that8d46c092015-02-26 01:30:04 +0100126 if (!parent)
127 return NULL;
128
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600129 xml_node<>* child = parent->first_node(nodename);
130 if (child)
131 return child;
132
133 if (depth == 10) {
134 LOGERR("Too many style loops detected.\n");
135 return NULL;
136 }
137
138 xml_node<>* style = parent->first_node("style");
139 if (style) {
140 while (style) {
141 if (!style->first_attribute("name")) {
142 LOGERR("No name given for style.\n");
143 continue;
144 } else {
145 std::string name = style->first_attribute("name")->value();
146 xml_node<>* node = PageManager::FindStyle(name);
147
148 if (node) {
149 // We found the style that was named
150 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
151 if (stylenode)
152 return stylenode;
153 }
154 }
155 style = style->next_sibling("style");
156 }
157 } else {
that54e9c832015-11-04 21:46:01 +0100158 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600159 xml_attribute<>* attr = parent->first_attribute("style");
160 // If no style is found anywhere else and the node wasn't found in the object itself
161 // as a special case we will search for a style that uses the same style name as the
162 // object type, so <object type="button"> would search for a style named "button"
163 if (!attr)
164 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100165 // if there's no attribute type, the object type must be the element name
166 std::string stylename = attr ? attr->value() : parent->name();
167 xml_node<>* node = PageManager::FindStyle(stylename);
168 if (node) {
169 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
170 if (stylenode)
171 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600172 }
173 }
174 return NULL;
175}
176
thatf6ed8fc2015-02-14 20:23:16 +0100177std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
178{
179 if (!element)
180 return defaultvalue;
181
182 xml_attribute<>* attr = element->first_attribute(attrname);
183 return attr ? attr->value() : defaultvalue;
184}
185
186int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
187{
188 string value = LoadAttrString(element, attrname);
189 // resolve variables
190 DataManager::GetValue(value, value);
191 return value.empty() ? defaultvalue : atoi(value.c_str());
192}
193
194int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
195{
196 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
197}
198
199int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
200{
201 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
202}
203
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600204COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100205{
206 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600207 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100208 // resolve variables
209 DataManager::GetValue(value, value);
210 COLOR ret = defaultvalue;
211 if (ConvertStrToColor(value, &ret) == 0)
212 return ret;
213 else
214 return defaultvalue;
215}
216
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600217COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
218{
219 bool found_color = false;
220 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
221}
222
thatf6ed8fc2015-02-14 20:23:16 +0100223FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
224{
225 std::string name = LoadAttrString(element, attrname, "");
226 if (name.empty())
227 return NULL;
228 else
that74ac6062015-03-04 22:39:34 +0100229 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100230}
231
232ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
233{
234 std::string name = LoadAttrString(element, attrname, "");
235 if (name.empty())
236 return NULL;
237 else
that74ac6062015-03-04 22:39:34 +0100238 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100239}
240
241AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
242{
243 std::string name = LoadAttrString(element, attrname, "");
244 if (name.empty())
245 return NULL;
246 else
that74ac6062015-03-04 22:39:34 +0100247 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100248}
249
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500250bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400251{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 if (!node)
253 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400254
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100256 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400257
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100259 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200261 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100262 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400263
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200264 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100265 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400266
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200267 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500268 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400269
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200270 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400271}
272
273int ActionObject::SetActionPos(int x, int y, int w, int h)
274{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200275 if (x < 0 || y < 0)
276 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400277
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500278 mActionX = x;
279 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200280 if (w || h)
281 {
282 mActionW = w;
283 mActionH = h;
284 }
285 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400286}
287
thatb63e2f92015-06-27 21:35:11 +0200288Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400289{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200290 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400291
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200292 // We can memset the whole structure, because the alpha channel is ignored
293 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400294
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200295 // With NULL, we make a console-only display
296 if (!page)
297 {
298 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400299
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200300 GUIConsole* element = new GUIConsole(NULL);
301 mRenders.push_back(element);
302 mActions.push_back(element);
303 return;
304 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400305
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200306 if (page->first_attribute("name"))
307 mName = page->first_attribute("name")->value();
308 else
309 {
310 LOGERR("No page name attribute found!\n");
311 return;
312 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400313
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200314 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400315
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200316 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200317 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400318}
319
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100320Page::~Page()
321{
322 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
323 delete *itr;
324}
325
thatb63e2f92015-06-27 21:35:11 +0200326bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400327{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200328 if (depth == 10)
329 {
330 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
331 return false;
332 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400333
thatb63e2f92015-06-27 21:35:11 +0200334 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200335 {
thatb63e2f92015-06-27 21:35:11 +0200336 std::string type = child->name();
337
338 if (type == "background") {
339 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
340 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200341 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400342
thatb63e2f92015-06-27 21:35:11 +0200343 if (type == "object") {
344 // legacy format : <object type="...">
345 xml_attribute<>* attr = child->first_attribute("type");
346 type = attr ? attr->value() : "*unspecified*";
347 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400348
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 if (type == "text")
350 {
351 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100352 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200353 mRenders.push_back(element);
354 mActions.push_back(element);
355 }
356 else if (type == "image")
357 {
358 GUIImage* element = new GUIImage(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 == "fill")
363 {
364 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100365 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200366 mRenders.push_back(element);
367 }
368 else if (type == "action")
369 {
370 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100371 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200372 mActions.push_back(element);
373 }
374 else if (type == "console")
375 {
376 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100377 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200378 mRenders.push_back(element);
379 mActions.push_back(element);
380 }
that1964d192016-01-07 00:41:03 +0100381 else if (type == "terminal")
382 {
383 GUITerminal* element = new GUITerminal(child);
384 mObjects.push_back(element);
385 mRenders.push_back(element);
386 mActions.push_back(element);
387 mInputs.push_back(element);
388 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200389 else if (type == "button")
390 {
391 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100392 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200393 mRenders.push_back(element);
394 mActions.push_back(element);
395 }
396 else if (type == "checkbox")
397 {
398 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100399 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200400 mRenders.push_back(element);
401 mActions.push_back(element);
402 }
403 else if (type == "fileselector")
404 {
405 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100406 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200407 mRenders.push_back(element);
408 mActions.push_back(element);
409 }
410 else if (type == "animation")
411 {
412 GUIAnimation* element = new GUIAnimation(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 }
416 else if (type == "progressbar")
417 {
418 GUIProgressBar* element = new GUIProgressBar(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 mActions.push_back(element);
422 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400423 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200424 {
425 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100426 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200427 mRenders.push_back(element);
428 mActions.push_back(element);
429 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200430 else if (type == "slidervalue")
431 {
432 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100433 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200434 mRenders.push_back(element);
435 mActions.push_back(element);
436 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400437 else if (type == "listbox")
438 {
439 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100440 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400441 mRenders.push_back(element);
442 mActions.push_back(element);
443 }
444 else if (type == "keyboard")
445 {
446 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100447 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400448 mRenders.push_back(element);
449 mActions.push_back(element);
450 }
451 else if (type == "input")
452 {
453 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100454 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400455 mRenders.push_back(element);
456 mActions.push_back(element);
457 mInputs.push_back(element);
458 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500459 else if (type == "partitionlist")
460 {
461 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100462 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500463 mRenders.push_back(element);
464 mActions.push_back(element);
465 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100466 else if (type == "patternpassword")
467 {
468 GUIPatternPassword* element = new GUIPatternPassword(child);
469 mObjects.push_back(element);
470 mRenders.push_back(element);
471 mActions.push_back(element);
472 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500473 else if (type == "textbox")
474 {
475 GUITextBox* element = new GUITextBox(child);
476 mObjects.push_back(element);
477 mRenders.push_back(element);
478 mActions.push_back(element);
479 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200480 else if (type == "template")
481 {
482 if (!templates || !child->first_attribute("name"))
483 {
484 LOGERR("Invalid template request.\n");
485 }
486 else
487 {
488 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500489 xml_node<>* node;
490 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400491
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200492 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500493 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
494 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400495
Ethan Yonker780cd392014-07-21 15:24:39 -0500496 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200497 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500498 if (!node->first_attribute("name"))
499 continue;
500
501 if (name == node->first_attribute("name")->value())
502 {
503 if (!ProcessNode(node, templates, depth + 1))
504 return false;
505 else {
506 node_found = true;
507 break;
508 }
509 }
510 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200511 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500512 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200513 }
thatb63e2f92015-06-27 21:35:11 +0200514 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 }
516 }
517 }
518 else
519 {
thatb63e2f92015-06-27 21:35:11 +0200520 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200521 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200522 }
523 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400524}
525
526int Page::Render(void)
527{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200528 // Render background
529 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
530 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400531
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200532 // Render remaining objects
533 std::vector<RenderObject*>::iterator iter;
534 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
535 {
536 if ((*iter)->Render())
537 LOGERR("A render request has failed.\n");
538 }
539 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400540}
541
542int Page::Update(void)
543{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200544 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400545
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200546 std::vector<RenderObject*>::iterator iter;
547 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
548 {
549 int ret = (*iter)->Update();
550 if (ret < 0)
551 LOGERR("An update request has failed.\n");
552 else if (ret > retCode)
553 retCode = ret;
554 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400555
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200556 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400557}
558
559int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
560{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200561 // By default, return 1 to ignore further touches if nobody is listening
562 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400563
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200564 // Don't try to handle a lack of handlers
565 if (mActions.size() == 0)
566 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400567
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200568 // We record mTouchStart so we can pass all the touch stream to the same handler
569 if (state == TOUCH_START)
570 {
571 std::vector<ActionObject*>::reverse_iterator iter;
572 // We work backwards, from top-most element to bottom-most element
573 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
574 {
575 if ((*iter)->IsInRegion(x, y))
576 {
577 mTouchStart = (*iter);
578 ret = mTouchStart->NotifyTouch(state, x, y);
579 if (ret >= 0)
580 break;
581 mTouchStart = NULL;
582 }
583 }
584 }
585 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
586 {
587 ret = mTouchStart->NotifyTouch(state, x, y);
588 mTouchStart = NULL;
589 }
590 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
591 {
592 ret = mTouchStart->NotifyTouch(state, x, y);
593 }
594 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400595}
596
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100597int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400598{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200599 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400600
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100601 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200602 // We work backwards, from top-most element to bottom-most element
603 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
604 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100605 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100606 if (ret == 0)
607 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100608 if (ret < 0) {
609 LOGERR("An action handler has returned an error\n");
610 ret = 1;
611 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200612 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100613 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400614}
615
that8834a0f2016-01-05 23:29:30 +0100616int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400617{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200618 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400619
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200620 // We work backwards, from top-most element to bottom-most element
621 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
622 {
that8834a0f2016-01-05 23:29:30 +0100623 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200624 if (ret == 0)
625 return 0;
626 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100627 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628 }
629 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400630}
631
632int Page::SetKeyBoardFocus(int inFocus)
633{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200634 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400635
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200636 // We work backwards, from top-most element to bottom-most element
637 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
638 {
639 int ret = (*iter)->SetInputFocus(inFocus);
640 if (ret == 0)
641 return 0;
642 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100643 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200644 }
645 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400646}
647
648void Page::SetPageFocus(int inFocus)
649{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200650 // Render remaining objects
651 std::vector<RenderObject*>::iterator iter;
652 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
653 (*iter)->SetPageFocus(inFocus);
654
655 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400656}
657
658int Page::NotifyVarChange(std::string varName, std::string value)
659{
Vojtech Bocek07220562014-02-08 02:05:33 +0100660 std::vector<GUIObject*>::iterator iter;
661 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200662 {
663 if ((*iter)->NotifyVarChange(varName, value))
664 LOGERR("An action handler errored on NotifyVarChange.\n");
665 }
666 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400667}
668
that6a894592016-03-13 17:51:28 +0100669
670// transient data for loading themes
671struct LoadingContext
672{
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500673 ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100674 std::set<std::string> filenames; // to detect cyclic includes
675 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
676 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
677 std::vector<char*> xmlbuffers; // text buffers with xml content
678 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
679 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
680
681 LoadingContext()
682 {
683 zip = NULL;
684 }
685
686 ~LoadingContext()
687 {
688 // free all xml buffers
689 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
690 free(*it);
691 }
692
693};
694
695// for FindStyle
696LoadingContext* PageManager::currentLoadingContext = NULL;
697
698
699PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400700{
that74ac6062015-03-04 22:39:34 +0100701 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200702 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400703
that6a894592016-03-13 17:51:28 +0100704 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400705}
706
707PageSet::~PageSet()
708{
Ethan Yonker1c273312015-03-16 12:18:56 -0500709 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100710 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
711 delete *itr;
712
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200713 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400714}
715
that6a894592016-03-13 17:51:28 +0100716int PageSet::Load(LoadingContext& ctx, const std::string& filename)
717{
718 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
719
720 if (!ctx.filenames.insert(filename).second)
721 // ignore already loaded files to prevent crash with cyclic includes
722 return 0;
723
724 // load XML into buffer
725 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
726 if (!xmlbuffer)
727 return -1; // error already displayed by LoadFileToBuffer
728 ctx.xmlbuffers.push_back(xmlbuffer);
729
730 // parse XML
731 xml_document<>* doc = new xml_document<>();
732 doc->parse<0>(xmlbuffer);
733 ctx.xmldocs.push_back(doc);
734
735 xml_node<>* root = doc->first_node("recovery");
736 if (!root)
737 root = doc->first_node("install");
738 if (!root) {
739 LOGERR("Unknown root element in %s\n", filename.c_str());
740 return -1;
741 }
742
743 if (isMain) {
744 int rc = LoadDetails(ctx, root);
745 if (rc != 0)
746 return rc;
747 }
748
749 LOGINFO("Loading resources...\n");
750 xml_node<>* child = root->first_node("resources");
751 if (child)
752 mResources->LoadResources(child, ctx.zip, "theme");
753
754 LOGINFO("Loading variables...\n");
755 child = root->first_node("variables");
756 if (child)
757 LoadVariables(child);
758
759 LOGINFO("Loading mouse cursor...\n");
760 child = root->first_node("mousecursor");
761 if (child)
762 PageManager::LoadCursorData(child);
763
764 LOGINFO("Loading pages...\n");
765 child = root->first_node("templates");
766 if (child)
767 ctx.templates.push_back(child);
768
769 child = root->first_node("styles");
770 if (child)
771 ctx.styles.push_back(child);
772
773 // Load pages
774 child = root->first_node("pages");
775 if (child) {
776 if (LoadPages(ctx, child)) {
777 LOGERR("PageSet::Load returning -1\n");
778 return -1;
779 }
780 }
781
782 // process includes recursively
783 child = root->first_node("include");
784 if (child) {
785 xml_node<>* include = child->first_node("xmlfile");
786 while (include != NULL) {
787 xml_attribute<>* attr = include->first_attribute("name");
788 if (!attr) {
789 LOGERR("Skipping include/xmlfile with no name\n");
790 continue;
791 }
792
793 string filename = ctx.basepath + attr->value();
794 LOGINFO("Including file: %s...\n", filename.c_str());
795 int rc = Load(ctx, filename);
796 if (rc != 0)
797 return rc;
798
799 include = include->next_sibling("xmlfile");
800 }
801 }
802
803 return 0;
804}
805
806void PageSet::MakeEmergencyConsoleIfNeeded()
807{
808 if (mPages.empty()) {
809 mCurrentPage = new Page(NULL, NULL); // fallback console page
810 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
811 mPages.push_back(mCurrentPage);
812 }
813}
814
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500815int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500816{
817 xml_document<> lang;
818 xml_node<>* parent;
819 xml_node<>* child;
820 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600821 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500822
823 if (languageFile) {
824 printf("parsing languageFile\n");
825 lang.parse<0>(languageFile);
826 printf("parsing languageFile done\n");
827 } else {
828 return -1;
829 }
830
831 parent = lang.first_node("language");
832 if (!parent) {
833 LOGERR("Unable to locate language node in language file.\n");
834 lang.clear();
835 return -1;
836 }
837
838 child = parent->first_node("display");
839 if (child) {
840 DataManager::SetValue("tw_language_display", child->value());
841 resource_source = child->value();
842 } else {
843 LOGERR("language file does not have a display value set\n");
844 DataManager::SetValue("tw_language_display", "Not Set");
845 resource_source = languageFile;
846 }
847
848 child = parent->first_node("resources");
849 if (child)
850 mResources->LoadResources(child, package, resource_source);
851 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600852 ret = -1;
853 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500854 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600855 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500856}
857
that6a894592016-03-13 17:51:28 +0100858int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400859{
that6a894592016-03-13 17:51:28 +0100860 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600861 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600862 int theme_ver = 0;
863 xml_node<>* themeversion = child->first_node("themeversion");
864 if (themeversion && themeversion->value()) {
865 theme_ver = atoi(themeversion->value());
866 } else {
867 LOGINFO("No themeversion in theme.\n");
868 }
869 if (theme_ver != TW_THEME_VERSION) {
870 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100871 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600872 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600873 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600874 } else {
875 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
876 }
877 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600878 xml_node<>* resolution = child->first_node("resolution");
879 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600880 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600881 xml_attribute<>* width_attr = resolution->first_attribute("width");
882 xml_attribute<>* height_attr = resolution->first_attribute("height");
883 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
884 if (width_attr && height_attr && !noscale_attr) {
885 int width = atoi(width_attr->value());
886 int height = atoi(height_attr->value());
887 int offx = 0, offy = 0;
888#ifdef TW_ROUND_SCREEN
889 xml_node<>* roundscreen = child->first_node("roundscreen");
890 if (roundscreen) {
891 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
892 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
893 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
894 if (offx_attr) {
895 offx = atoi(offx_attr->value());
896 }
897 if (offy_attr) {
898 offy = atoi(offy_attr->value());
899 }
900 }
901#endif
902 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500903 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
904 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600905#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500906 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
907 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600908 tw_x_offset = offx * scale_off_w;
909 tw_y_offset = offy * scale_off_h;
910#endif
911 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500912 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
913 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600914 set_scale_values(scale_w, scale_h);
915 }
916 }
917 } else {
918 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
919 }
920 } else {
921 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
922 }
923 } else {
924 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
925 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500926
Ethan Yonker780cd392014-07-21 15:24:39 -0500927 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400928}
929
930int PageSet::SetPage(std::string page)
931{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200932 Page* tmp = FindPage(page);
933 if (tmp)
934 {
935 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
936 mCurrentPage = tmp;
937 mCurrentPage->SetPageFocus(1);
938 mCurrentPage->NotifyVarChange("", "");
939 return 0;
940 }
941 else
942 {
943 LOGERR("Unable to locate page (%s)\n", page.c_str());
944 }
945 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400946}
947
948int PageSet::SetOverlay(Page* page)
949{
Ethan Yonker1c273312015-03-16 12:18:56 -0500950 if (page) {
951 if (mOverlays.size() >= 10) {
952 LOGERR("Too many overlays requested, max is 10.\n");
953 return -1;
954 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500955
956 std::vector<Page*>::iterator iter;
957 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
958 if ((*iter)->GetName() == page->GetName()) {
959 mOverlays.erase(iter);
960 // SetOverlay() is (and should stay) the only function which
961 // adds to mOverlays. Then, each page can appear at most once.
962 break;
963 }
964 }
965
Ethan Yonker1c273312015-03-16 12:18:56 -0500966 page->SetPageFocus(1);
967 page->NotifyVarChange("", "");
968
969 if (!mOverlays.empty())
970 mOverlays.back()->SetPageFocus(0);
971
972 mOverlays.push_back(page);
973 } else {
974 if (!mOverlays.empty()) {
975 mOverlays.back()->SetPageFocus(0);
976 mOverlays.pop_back();
977 if (!mOverlays.empty())
978 mOverlays.back()->SetPageFocus(1);
979 else if (mCurrentPage)
980 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
981 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200982 }
983 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400984}
985
that74ac6062015-03-04 22:39:34 +0100986const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400987{
that74ac6062015-03-04 22:39:34 +0100988 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400989}
990
991Page* PageSet::FindPage(std::string name)
992{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200993 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400994
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200995 for (iter = mPages.begin(); iter != mPages.end(); iter++)
996 {
997 if (name == (*iter)->GetName())
998 return (*iter);
999 }
1000 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001001}
1002
1003int PageSet::LoadVariables(xml_node<>* vars)
1004{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001005 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001006 xml_attribute<> *name, *value, *persist;
1007 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001008
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001009 child = vars->first_node("variable");
1010 while (child)
1011 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001012 name = child->first_attribute("name");
1013 value = child->first_attribute("value");
1014 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001015 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001016 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001017 if (strcmp(name->value(), "tw_x_offset") == 0) {
1018 tw_x_offset = atoi(value->value());
1019 child = child->next_sibling("variable");
1020 continue;
1021 }
1022 if (strcmp(name->value(), "tw_y_offset") == 0) {
1023 tw_y_offset = atoi(value->value());
1024 child = child->next_sibling("variable");
1025 continue;
1026 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001027 if (strcmp(name->value(), "tw_w_offset") == 0) {
1028 tw_w_offset = atoi(value->value());
1029 child = child->next_sibling("variable");
1030 continue;
1031 }
1032 if (strcmp(name->value(), "tw_h_offset") == 0) {
1033 tw_h_offset = atoi(value->value());
1034 child = child->next_sibling("variable");
1035 continue;
1036 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001037 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001038 string temp = value->value();
1039 string valstr = gui_parse_text(temp);
1040
1041 if (valstr.find("+") != string::npos) {
1042 string val1str = valstr;
1043 val1str = val1str.substr(0, val1str.find('+'));
1044 string val2str = valstr;
1045 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1046 int val1 = atoi(val1str.c_str());
1047 int val2 = atoi(val2str.c_str());
1048 int val = val1 + val2;
1049
1050 DataManager::SetValue(name->value(), val, p);
1051 } else if (valstr.find("-") != string::npos) {
1052 string val1str = valstr;
1053 val1str = val1str.substr(0, val1str.find('-'));
1054 string val2str = valstr;
1055 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1056 int val1 = atoi(val1str.c_str());
1057 int val2 = atoi(val2str.c_str());
1058 int val = val1 - val2;
1059
1060 DataManager::SetValue(name->value(), val, p);
1061 } else {
1062 DataManager::SetValue(name->value(), valstr, p);
1063 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001064 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001065
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001066 child = child->next_sibling("variable");
1067 }
1068 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001069}
1070
that6a894592016-03-13 17:51:28 +01001071int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001072{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001073 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001074
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001075 if (!pages)
1076 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001077
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001078 child = pages->first_node("page");
1079 while (child != NULL)
1080 {
that6a894592016-03-13 17:51:28 +01001081 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001082 if (page->GetName().empty())
1083 {
1084 LOGERR("Unable to process load page\n");
1085 delete page;
1086 }
1087 else
1088 {
1089 mPages.push_back(page);
1090 }
1091 child = child->next_sibling("page");
1092 }
1093 if (mPages.size() > 0)
1094 return 0;
1095 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001096}
1097
1098int PageSet::IsCurrentPage(Page* page)
1099{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001100 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001101}
1102
that10ae24f2015-12-26 20:53:51 +01001103std::string PageSet::GetCurrentPage() const
1104{
1105 return mCurrentPage ? mCurrentPage->GetName() : "";
1106}
1107
Dees_Troy51a0e822012-09-05 15:24:24 -04001108int PageSet::Render(void)
1109{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001110 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001111
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001112 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1113 if (ret < 0)
1114 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001115
1116 std::vector<Page*>::iterator iter;
1117
1118 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1119 ret = ((*iter) ? (*iter)->Render() : -1);
1120 if (ret < 0)
1121 return ret;
1122 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001123 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001124}
1125
1126int PageSet::Update(void)
1127{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001128 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001129
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001130 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1131 if (ret < 0 || ret > 1)
1132 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001133
1134 std::vector<Page*>::iterator iter;
1135
1136 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1137 ret = ((*iter) ? (*iter)->Update() : -1);
1138 if (ret < 0)
1139 return ret;
1140 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001141 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001142}
1143
1144int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1145{
Ethan Yonker1c273312015-03-16 12:18:56 -05001146 if (!mOverlays.empty())
1147 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001148
1149 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001150}
1151
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001152int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001153{
Ethan Yonker1c273312015-03-16 12:18:56 -05001154 if (!mOverlays.empty())
1155 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001156
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001157 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001158}
1159
that8834a0f2016-01-05 23:29:30 +01001160int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001161{
Ethan Yonker1c273312015-03-16 12:18:56 -05001162 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001163 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001164
that8834a0f2016-01-05 23:29:30 +01001165 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001166}
1167
1168int PageSet::SetKeyBoardFocus(int inFocus)
1169{
Ethan Yonker1c273312015-03-16 12:18:56 -05001170 if (!mOverlays.empty())
1171 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001172
1173 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001174}
1175
1176int PageSet::NotifyVarChange(std::string varName, std::string value)
1177{
Ethan Yonker1c273312015-03-16 12:18:56 -05001178 std::vector<Page*>::iterator iter;
1179
1180 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1181 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001182
1183 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001184}
1185
Ethan Yonker74db1572015-10-28 12:44:49 -05001186void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1187{
1188 mResources->AddStringResource(resource_source, resource_name, value);
1189}
1190
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001191char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001192 size_t len;
1193 char* buffer = NULL;
1194
1195 if (!package) {
1196 // We can try to load the XML directly...
1197 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1198 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001199 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001200 // This isn't always an error, sometimes we request files that don't exist.
1201 return NULL;
1202 }
1203
1204 len = (size_t)st.st_size;
1205
1206 buffer = (char*) malloc(len + 1);
1207 if (!buffer) {
1208 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1209 return NULL;
1210 }
1211
1212 int fd = open(filename.c_str(), O_RDONLY);
1213 if (fd == -1) {
1214 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1215 free(buffer);
1216 return NULL;
1217 }
1218
1219 if (read(fd, buffer, len) < 0) {
1220 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1221 free(buffer);
1222 close(fd);
1223 return NULL;
1224 }
1225 close(fd);
1226 } else {
1227 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001228 if (!package->EntryExists(filename)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001229 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1230 return NULL;
1231 }
1232
1233 // Allocate the buffer for the file
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001234 len = package->GetUncompressedSize(filename);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001235 buffer = (char*) malloc(len + 1);
1236 if (!buffer)
1237 return NULL;
1238
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001239 if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001240 LOGERR("Unable to extract '%s'\n", filename.c_str());
1241 free(buffer);
1242 return NULL;
1243 }
1244 }
1245 // NULL-terminate the string
1246 buffer[len] = 0x00;
1247 return buffer;
1248}
1249
Ethan Yonker74db1572015-10-28 12:44:49 -05001250void PageManager::LoadLanguageListDir(string dir) {
1251 if (!TWFunc::Path_Exists(dir)) {
1252 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1253 return;
1254 }
1255
1256 DIR *d = opendir(dir.c_str());
1257 struct dirent *p;
1258
1259 if (d == NULL) {
1260 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1261 return;
1262 }
1263
1264 while ((p = readdir(d))) {
1265 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1266 continue;
1267
1268 string file = p->d_name;
1269 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1270 continue;
1271 string path = dir + p->d_name;
1272 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1273 struct language_struct language_entry;
1274 language_entry.filename = file_no_extn;
1275 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1276 if (xmlFile == NULL) {
1277 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1278 continue;
1279 }
1280 xml_document<> *doc = new xml_document<>();
1281 doc->parse<0>(xmlFile);
1282
1283 xml_node<>* parent = doc->first_node("language");
1284 if (!parent) {
1285 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1286 } else {
1287 xml_node<>* child = parent->first_node("display");
1288 if (child) {
1289 language_entry.displayvalue = child->value();
1290 } else {
1291 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1292 language_entry.displayvalue = language_entry.filename;
1293 }
1294 Language_List.push_back(language_entry);
1295 }
1296 doc->clear();
1297 delete doc;
1298 free(xmlFile);
1299 }
1300 closedir(d);
1301}
1302
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001303void PageManager::LoadLanguageList(ZipWrap* package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001304 Language_List.clear();
1305 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1306 TWFunc::removeDir(TWRES "customlanguages", true);
1307 if (package) {
1308 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001309 package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001310 LoadLanguageListDir(TWRES "customlanguages/");
1311 } else {
1312 LoadLanguageListDir(TWRES "languages/");
1313 }
Xuefercac6ace2016-02-01 02:28:55 +08001314
1315 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001316}
1317
1318void PageManager::LoadLanguage(string filename) {
1319 string actual_filename;
1320 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1321 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1322 else
1323 actual_filename = TWRES "languages/" + filename + ".xml";
1324 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1325 if (xmlFile == NULL)
1326 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1327 else {
1328 mCurrentSet->LoadLanguage(xmlFile, NULL);
1329 free(xmlFile);
1330 }
1331 PartitionManager.Translate_Partition_Display_Names();
1332}
1333
Dees_Troy51a0e822012-09-05 15:24:24 -04001334int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1335{
that6a894592016-03-13 17:51:28 +01001336 std::string mainxmlfilename = package;
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001337 ZipWrap zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001338 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001339 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001340 PageSet* pageSet = NULL;
1341 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001342 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001343
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001344 mReloadTheme = false;
1345 mStartPage = startpage;
1346
that6a894592016-03-13 17:51:28 +01001347 // init the loading context
1348 LoadingContext ctx;
1349
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001350 // Open the XML file
1351 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001352 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001353 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001354 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001355 tw_x_offset = TW_X_OFFSET;
1356 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001357 tw_w_offset = TW_W_OFFSET;
1358 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001359 if (name != "splash") {
1360 LoadLanguageList(NULL);
1361 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1362 }
that6a894592016-03-13 17:51:28 +01001363 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001364 }
1365 else
1366 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001367 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001368 tw_x_offset = 0;
1369 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001370 tw_w_offset = 0;
1371 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001372 if (!TWFunc::Path_Exists(package))
1373 return -1;
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001374#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001375 if (sysMapFile(package.c_str(), &map) != 0) {
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001376#else
1377 if (!map.MapFile(package)) {
1378#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001379 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001380 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001381 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001382 if (!zip.Open(package.c_str(), &map)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001383 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001384#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001385 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001386#endif
Ethan Yonker561c58d2015-10-05 08:48:22 -05001387 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001388 }
that6a894592016-03-13 17:51:28 +01001389 ctx.zip = &zip;
1390 mainxmlfilename = "ui.xml";
1391 LoadLanguageList(ctx.zip);
1392 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001393 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001394 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001395
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001396 // Before loading, mCurrentSet must be the loading package so we can find resources
1397 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001398 mCurrentSet = new PageSet();
1399
1400 if (baseLanguageFile) {
1401 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1402 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001403 }
that6a894592016-03-13 17:51:28 +01001404
1405 if (languageFile) {
1406 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1407 free(languageFile);
1408 }
1409
1410 // Load and parse the XML and all includes
1411 currentLoadingContext = &ctx; // required to find styles
1412 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1413 currentLoadingContext = NULL;
1414
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001415 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001416 mCurrentSet->SetPage(startpage);
1417 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001418 } else {
1419 if (ret != TW_THEME_VER_ERR)
1420 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001421 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001422
that6a894592016-03-13 17:51:28 +01001423 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001424 mCurrentSet = pageSet;
1425
that6a894592016-03-13 17:51:28 +01001426 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001427 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001428#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001429 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001430#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001431 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001432 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001433
1434error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001435 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001436 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001437 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001438#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001439 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001440#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001441 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001442 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001443}
1444
1445PageSet* PageManager::FindPackage(std::string name)
1446{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001447 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001448
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001449 iter = mPageSets.find(name);
1450 if (iter != mPageSets.end())
1451 return (*iter).second;
1452
1453 LOGERR("Unable to locate package %s\n", name.c_str());
1454 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001455}
1456
1457PageSet* PageManager::SelectPackage(std::string name)
1458{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001459 LOGINFO("Switching packages (%s)\n", name.c_str());
1460 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001461
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001462 tmp = FindPackage(name);
1463 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001464 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001465 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001466 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001467 mCurrentSet->NotifyVarChange("", "");
1468 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001469 else
1470 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001471
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001472 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001473}
1474
1475int PageManager::ReloadPackage(std::string name, std::string package)
1476{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001477 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001478
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001479 mReloadTheme = false;
1480
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001481 iter = mPageSets.find(name);
1482 if (iter == mPageSets.end())
1483 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001484
Matt Mowera8a89d12016-12-30 18:10:37 -06001485 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001486 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1487
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001488 PageSet* set = (*iter).second;
1489 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001490
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001491 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001492 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001493 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001494 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1495 return -1;
1496 }
1497 if (mCurrentSet == set)
1498 SelectPackage(name);
1499 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001500 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001501 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001502}
1503
1504void PageManager::ReleasePackage(std::string name)
1505{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001506 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001507
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001508 iter = mPageSets.find(name);
1509 if (iter == mPageSets.end())
1510 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001511
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001512 PageSet* set = (*iter).second;
1513 mPageSets.erase(iter);
1514 delete set;
that235c6482016-01-24 21:59:00 +01001515 if (set == mCurrentSet)
1516 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001517 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001518}
1519
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001520int PageManager::RunReload() {
1521 int ret_val = 0;
1522 std::string theme_path;
1523
1524 if (!mReloadTheme)
1525 return 0;
1526
1527 mReloadTheme = false;
1528 theme_path = DataManager::GetSettingsStoragePath();
1529 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1530 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1531 ret_val = 1;
1532 }
1533
1534 theme_path += "/TWRP/theme/ui.zip";
1535 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1536 {
1537 // Loading the custom theme failed - try loading the stock theme
1538 LOGINFO("Attempting to reload stock theme...\n");
1539 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1540 {
1541 LOGERR("Failed to load base packages.\n");
1542 ret_val = 1;
1543 }
1544 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001545 if (ret_val == 0) {
1546 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1547 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1548 LoadLanguage(DataManager::GetStrValue("tw_language"));
1549 }
1550 }
1551
1552 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001553 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001554
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001555 return ret_val;
1556}
1557
1558void PageManager::RequestReload() {
1559 mReloadTheme = true;
1560}
1561
Ethan Yonkerafde0982016-01-23 08:55:35 -06001562void PageManager::SetStartPage(const std::string& page_name) {
1563 mStartPage = page_name;
1564}
1565
Dees_Troy51a0e822012-09-05 15:24:24 -04001566int PageManager::ChangePage(std::string name)
1567{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001568 DataManager::SetValue("tw_operation_state", 0);
1569 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1570 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001571}
1572
that10ae24f2015-12-26 20:53:51 +01001573std::string PageManager::GetCurrentPage()
1574{
1575 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1576}
1577
Dees_Troy51a0e822012-09-05 15:24:24 -04001578int PageManager::ChangeOverlay(std::string name)
1579{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001580 if (name.empty())
1581 return mCurrentSet->SetOverlay(NULL);
1582 else
1583 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001584 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001585 return mCurrentSet->SetOverlay(page);
1586 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001587}
1588
that74ac6062015-03-04 22:39:34 +01001589const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001590{
that74ac6062015-03-04 22:39:34 +01001591 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001592}
1593
Dees_Troy51a0e822012-09-05 15:24:24 -04001594int PageManager::IsCurrentPage(Page* page)
1595{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001596 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001597}
1598
1599int PageManager::Render(void)
1600{
Matt Mowera8a89d12016-12-30 18:10:37 -06001601 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001602 return 0;
1603
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001604 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001605 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001606 mMouseCursor->Render();
1607 return res;
1608}
1609
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001610HardwareKeyboard *PageManager::GetHardwareKeyboard()
1611{
Matt Mowera8a89d12016-12-30 18:10:37 -06001612 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001613 mHardwareKeyboard = new HardwareKeyboard();
1614 return mHardwareKeyboard;
1615}
1616
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001617xml_node<>* PageManager::FindStyle(std::string name)
1618{
that6a894592016-03-13 17:51:28 +01001619 if (!currentLoadingContext)
1620 {
1621 LOGERR("FindStyle works only while loading a theme.\n");
1622 return NULL;
1623 }
1624
1625 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001626 xml_node<>* node = (*itr)->first_node("style");
1627
1628 while (node) {
1629 if (!node->first_attribute("name"))
1630 continue;
1631
1632 if (name == node->first_attribute("name")->value())
1633 return node;
1634 node = node->next_sibling("style");
1635 }
1636 }
1637 return NULL;
1638}
1639
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001640MouseCursor *PageManager::GetMouseCursor()
1641{
Matt Mowera8a89d12016-12-30 18:10:37 -06001642 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001643 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1644 return mMouseCursor;
1645}
1646
1647void PageManager::LoadCursorData(xml_node<>* node)
1648{
Matt Mowera8a89d12016-12-30 18:10:37 -06001649 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001650 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1651
1652 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001653}
1654
1655int PageManager::Update(void)
1656{
Matt Mowera8a89d12016-12-30 18:10:37 -06001657 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001658 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001659
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001660 if (RunReload())
1661 return -2;
1662
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001663 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1664
Matt Mowera8a89d12016-12-30 18:10:37 -06001665 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001666 {
1667 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001668 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001669 res = c_res;
1670 }
1671 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001672}
1673
1674int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1675{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001676 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001677}
1678
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001679int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001680{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001681 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001682}
1683
that8834a0f2016-01-05 23:29:30 +01001684int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001685{
that8834a0f2016-01-05 23:29:30 +01001686 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001687}
1688
1689int PageManager::SetKeyBoardFocus(int inFocus)
1690{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001691 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001692}
1693
1694int PageManager::NotifyVarChange(std::string varName, std::string value)
1695{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001696 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001697}
1698
Ethan Yonker74db1572015-10-28 12:44:49 -05001699void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1700{
1701 if (mCurrentSet)
1702 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1703}
1704
Dees_Troy51a0e822012-09-05 15:24:24 -04001705extern "C" void gui_notifyVarChange(const char *name, const char* value)
1706{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001707 if (!gGuiRunning)
1708 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001709
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001710 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001711}