blob: cc2f6153dd3e2bf6b0a2084d70976e64a1d56363 [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
bigbiff bigbiff56cf5642016-08-19 17:43:45 -040064#define TW_THEME_VERSION 3
that74bff7f2017-01-18 22:32:36 +010065
Ethan Yonker8e5692f2016-01-21 11:21:06 -060066#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060067
Dees_Troy51a0e822012-09-05 15:24:24 -040068extern int gGuiRunning;
69
70std::map<std::string, PageSet*> PageManager::mPageSets;
71PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010072MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010073HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050074bool PageManager::mReloadTheme = false;
75std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050076std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040077
Ethan Yonker751a85e2014-12-12 16:59:10 -060078int tw_x_offset = 0;
79int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050080int tw_w_offset = 0;
81int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060082
Dees_Troy51a0e822012-09-05 15:24:24 -040083// Helper routine to convert a string to a color declaration
84int ConvertStrToColor(std::string str, COLOR* color)
85{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 // Set the default, solid black
87 memset(color, 0, sizeof(COLOR));
88 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040089
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020090 // Translate variables
91 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050092
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020093 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010094 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020095 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
96 else if (str == "red") { color->red = 255; return 0; }
97 else if (str == "green") { color->green = 255; return 0; }
98 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040099
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200100 // At this point, we require an RGB(A) color
101 if (str[0] != '#')
102 return -1;
103
104 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400105
Dees_Troy30b962e2012-10-19 20:48:59 -0400106 int result;
107 if (str.size() >= 8) {
108 // We have alpha channel
109 string alpha = str.substr(6, 2);
110 result = strtol(alpha.c_str(), NULL, 16);
111 color->alpha = result & 0x000000FF;
112 str.resize(6);
113 result = strtol(str.c_str(), NULL, 16);
114 color->red = (result >> 16) & 0x000000FF;
115 color->green = (result >> 8) & 0x000000FF;
116 color->blue = result & 0x000000FF;
117 } else {
118 result = strtol(str.c_str(), NULL, 16);
119 color->red = (result >> 16) & 0x000000FF;
120 color->green = (result >> 8) & 0x000000FF;
121 color->blue = result & 0x000000FF;
122 }
123 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400124}
125
126// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600127xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
128{
that8d46c092015-02-26 01:30:04 +0100129 if (!parent)
130 return NULL;
131
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600132 xml_node<>* child = parent->first_node(nodename);
133 if (child)
134 return child;
135
136 if (depth == 10) {
137 LOGERR("Too many style loops detected.\n");
138 return NULL;
139 }
140
141 xml_node<>* style = parent->first_node("style");
142 if (style) {
143 while (style) {
144 if (!style->first_attribute("name")) {
145 LOGERR("No name given for style.\n");
146 continue;
147 } else {
148 std::string name = style->first_attribute("name")->value();
149 xml_node<>* node = PageManager::FindStyle(name);
150
151 if (node) {
152 // We found the style that was named
153 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
154 if (stylenode)
155 return stylenode;
156 }
157 }
158 style = style->next_sibling("style");
159 }
160 } else {
that54e9c832015-11-04 21:46:01 +0100161 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600162 xml_attribute<>* attr = parent->first_attribute("style");
163 // If no style is found anywhere else and the node wasn't found in the object itself
164 // as a special case we will search for a style that uses the same style name as the
165 // object type, so <object type="button"> would search for a style named "button"
166 if (!attr)
167 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100168 // if there's no attribute type, the object type must be the element name
169 std::string stylename = attr ? attr->value() : parent->name();
170 xml_node<>* node = PageManager::FindStyle(stylename);
171 if (node) {
172 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
173 if (stylenode)
174 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600175 }
176 }
177 return NULL;
178}
179
thatf6ed8fc2015-02-14 20:23:16 +0100180std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
181{
182 if (!element)
183 return defaultvalue;
184
185 xml_attribute<>* attr = element->first_attribute(attrname);
186 return attr ? attr->value() : defaultvalue;
187}
188
189int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
190{
191 string value = LoadAttrString(element, attrname);
192 // resolve variables
193 DataManager::GetValue(value, value);
194 return value.empty() ? defaultvalue : atoi(value.c_str());
195}
196
197int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
198{
199 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
200}
201
202int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
203{
204 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
205}
206
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600207COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100208{
209 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600210 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100211 // resolve variables
212 DataManager::GetValue(value, value);
213 COLOR ret = defaultvalue;
214 if (ConvertStrToColor(value, &ret) == 0)
215 return ret;
216 else
217 return defaultvalue;
218}
219
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600220COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
221{
222 bool found_color = false;
223 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
224}
225
thatf6ed8fc2015-02-14 20:23:16 +0100226FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
227{
228 std::string name = LoadAttrString(element, attrname, "");
229 if (name.empty())
230 return NULL;
231 else
that74ac6062015-03-04 22:39:34 +0100232 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100233}
234
235ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
236{
237 std::string name = LoadAttrString(element, attrname, "");
238 if (name.empty())
239 return NULL;
240 else
that74ac6062015-03-04 22:39:34 +0100241 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100242}
243
244AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
245{
246 std::string name = LoadAttrString(element, attrname, "");
247 if (name.empty())
248 return NULL;
249 else
that74ac6062015-03-04 22:39:34 +0100250 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100251}
252
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500253bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400254{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 if (!node)
256 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400257
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100259 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200261 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100262 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400263
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200264 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100265 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400266
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200267 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100268 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400269
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200270 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500271 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400272
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200273 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400274}
275
276int ActionObject::SetActionPos(int x, int y, int w, int h)
277{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200278 if (x < 0 || y < 0)
279 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400280
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500281 mActionX = x;
282 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200283 if (w || h)
284 {
285 mActionW = w;
286 mActionH = h;
287 }
288 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400289}
290
thatb63e2f92015-06-27 21:35:11 +0200291Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400292{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200293 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400294
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200295 // We can memset the whole structure, because the alpha channel is ignored
296 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400297
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200298 // With NULL, we make a console-only display
299 if (!page)
300 {
301 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400302
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200303 GUIConsole* element = new GUIConsole(NULL);
304 mRenders.push_back(element);
305 mActions.push_back(element);
306 return;
307 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400308
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200309 if (page->first_attribute("name"))
310 mName = page->first_attribute("name")->value();
311 else
312 {
313 LOGERR("No page name attribute found!\n");
314 return;
315 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400316
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200317 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400318
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200319 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200320 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400321}
322
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100323Page::~Page()
324{
325 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
326 delete *itr;
327}
328
thatb63e2f92015-06-27 21:35:11 +0200329bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400330{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200331 if (depth == 10)
332 {
333 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
334 return false;
335 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400336
thatb63e2f92015-06-27 21:35:11 +0200337 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200338 {
thatb63e2f92015-06-27 21:35:11 +0200339 std::string type = child->name();
340
341 if (type == "background") {
342 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
343 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200344 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400345
thatb63e2f92015-06-27 21:35:11 +0200346 if (type == "object") {
347 // legacy format : <object type="...">
348 xml_attribute<>* attr = child->first_attribute("type");
349 type = attr ? attr->value() : "*unspecified*";
350 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400351
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200352 if (type == "text")
353 {
354 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100355 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200356 mRenders.push_back(element);
357 mActions.push_back(element);
358 }
359 else if (type == "image")
360 {
361 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100362 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200363 mRenders.push_back(element);
364 }
365 else if (type == "fill")
366 {
367 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100368 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200369 mRenders.push_back(element);
370 }
371 else if (type == "action")
372 {
373 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100374 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200375 mActions.push_back(element);
376 }
377 else if (type == "console")
378 {
379 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100380 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200381 mRenders.push_back(element);
382 mActions.push_back(element);
383 }
that1964d192016-01-07 00:41:03 +0100384 else if (type == "terminal")
385 {
386 GUITerminal* element = new GUITerminal(child);
387 mObjects.push_back(element);
388 mRenders.push_back(element);
389 mActions.push_back(element);
390 mInputs.push_back(element);
391 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200392 else if (type == "button")
393 {
394 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100395 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200396 mRenders.push_back(element);
397 mActions.push_back(element);
398 }
399 else if (type == "checkbox")
400 {
401 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100402 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200403 mRenders.push_back(element);
404 mActions.push_back(element);
405 }
406 else if (type == "fileselector")
407 {
408 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100409 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200410 mRenders.push_back(element);
411 mActions.push_back(element);
412 }
413 else if (type == "animation")
414 {
415 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100416 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200417 mRenders.push_back(element);
418 }
419 else if (type == "progressbar")
420 {
421 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100422 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200423 mRenders.push_back(element);
424 mActions.push_back(element);
425 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400426 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200427 {
428 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100429 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200430 mRenders.push_back(element);
431 mActions.push_back(element);
432 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200433 else if (type == "slidervalue")
434 {
435 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100436 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200437 mRenders.push_back(element);
438 mActions.push_back(element);
439 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400440 else if (type == "listbox")
441 {
442 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100443 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400444 mRenders.push_back(element);
445 mActions.push_back(element);
446 }
447 else if (type == "keyboard")
448 {
449 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100450 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400451 mRenders.push_back(element);
452 mActions.push_back(element);
453 }
454 else if (type == "input")
455 {
456 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100457 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400458 mRenders.push_back(element);
459 mActions.push_back(element);
460 mInputs.push_back(element);
461 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500462 else if (type == "partitionlist")
463 {
464 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100465 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500466 mRenders.push_back(element);
467 mActions.push_back(element);
468 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100469 else if (type == "patternpassword")
470 {
471 GUIPatternPassword* element = new GUIPatternPassword(child);
472 mObjects.push_back(element);
473 mRenders.push_back(element);
474 mActions.push_back(element);
475 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500476 else if (type == "textbox")
477 {
478 GUITextBox* element = new GUITextBox(child);
479 mObjects.push_back(element);
480 mRenders.push_back(element);
481 mActions.push_back(element);
482 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200483 else if (type == "template")
484 {
485 if (!templates || !child->first_attribute("name"))
486 {
487 LOGERR("Invalid template request.\n");
488 }
489 else
490 {
491 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500492 xml_node<>* node;
493 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400494
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200495 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500496 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
497 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400498
Ethan Yonker780cd392014-07-21 15:24:39 -0500499 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200500 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500501 if (!node->first_attribute("name"))
502 continue;
503
504 if (name == node->first_attribute("name")->value())
505 {
506 if (!ProcessNode(node, templates, depth + 1))
507 return false;
508 else {
509 node_found = true;
510 break;
511 }
512 }
513 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200514 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500515 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200516 }
thatb63e2f92015-06-27 21:35:11 +0200517 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200518 }
519 }
520 }
521 else
522 {
thatb63e2f92015-06-27 21:35:11 +0200523 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200524 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200525 }
526 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400527}
528
529int Page::Render(void)
530{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200531 // Render background
532 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
533 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400534
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200535 // Render remaining objects
536 std::vector<RenderObject*>::iterator iter;
537 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
538 {
539 if ((*iter)->Render())
540 LOGERR("A render request has failed.\n");
541 }
542 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400543}
544
545int Page::Update(void)
546{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200547 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400548
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200549 std::vector<RenderObject*>::iterator iter;
550 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
551 {
552 int ret = (*iter)->Update();
553 if (ret < 0)
554 LOGERR("An update request has failed.\n");
555 else if (ret > retCode)
556 retCode = ret;
557 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400558
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200559 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400560}
561
562int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
563{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200564 // By default, return 1 to ignore further touches if nobody is listening
565 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400566
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200567 // Don't try to handle a lack of handlers
568 if (mActions.size() == 0)
569 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400570
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200571 // We record mTouchStart so we can pass all the touch stream to the same handler
572 if (state == TOUCH_START)
573 {
574 std::vector<ActionObject*>::reverse_iterator iter;
575 // We work backwards, from top-most element to bottom-most element
576 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
577 {
578 if ((*iter)->IsInRegion(x, y))
579 {
580 mTouchStart = (*iter);
581 ret = mTouchStart->NotifyTouch(state, x, y);
582 if (ret >= 0)
583 break;
584 mTouchStart = NULL;
585 }
586 }
587 }
588 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
589 {
590 ret = mTouchStart->NotifyTouch(state, x, y);
591 mTouchStart = NULL;
592 }
593 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
594 {
595 ret = mTouchStart->NotifyTouch(state, x, y);
596 }
597 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400598}
599
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100600int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400601{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200602 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400603
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100604 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200605 // We work backwards, from top-most element to bottom-most element
606 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
607 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100608 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100609 if (ret == 0)
610 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100611 if (ret < 0) {
612 LOGERR("An action handler has returned an error\n");
613 ret = 1;
614 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100616 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400617}
618
that8834a0f2016-01-05 23:29:30 +0100619int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400620{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200621 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400622
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200623 // We work backwards, from top-most element to bottom-most element
624 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
625 {
that8834a0f2016-01-05 23:29:30 +0100626 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200627 if (ret == 0)
628 return 0;
629 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100630 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 }
632 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400633}
634
635int Page::SetKeyBoardFocus(int inFocus)
636{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200637 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400638
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200639 // We work backwards, from top-most element to bottom-most element
640 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
641 {
642 int ret = (*iter)->SetInputFocus(inFocus);
643 if (ret == 0)
644 return 0;
645 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100646 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200647 }
648 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400649}
650
651void Page::SetPageFocus(int inFocus)
652{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200653 // Render remaining objects
654 std::vector<RenderObject*>::iterator iter;
655 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
656 (*iter)->SetPageFocus(inFocus);
657
658 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400659}
660
661int Page::NotifyVarChange(std::string varName, std::string value)
662{
Vojtech Bocek07220562014-02-08 02:05:33 +0100663 std::vector<GUIObject*>::iterator iter;
664 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200665 {
666 if ((*iter)->NotifyVarChange(varName, value))
667 LOGERR("An action handler errored on NotifyVarChange.\n");
668 }
669 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670}
671
that6a894592016-03-13 17:51:28 +0100672
673// transient data for loading themes
674struct LoadingContext
675{
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500676 ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100677 std::set<std::string> filenames; // to detect cyclic includes
678 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
679 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
680 std::vector<char*> xmlbuffers; // text buffers with xml content
681 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
682 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
683
684 LoadingContext()
685 {
686 zip = NULL;
687 }
688
689 ~LoadingContext()
690 {
691 // free all xml buffers
692 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
693 free(*it);
694 }
695
696};
697
698// for FindStyle
699LoadingContext* PageManager::currentLoadingContext = NULL;
700
701
702PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400703{
that74ac6062015-03-04 22:39:34 +0100704 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200705 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400706
that6a894592016-03-13 17:51:28 +0100707 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400708}
709
710PageSet::~PageSet()
711{
Ethan Yonker1c273312015-03-16 12:18:56 -0500712 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100713 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
714 delete *itr;
715
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200716 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400717}
718
that6a894592016-03-13 17:51:28 +0100719int PageSet::Load(LoadingContext& ctx, const std::string& filename)
720{
721 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
722
723 if (!ctx.filenames.insert(filename).second)
724 // ignore already loaded files to prevent crash with cyclic includes
725 return 0;
726
727 // load XML into buffer
728 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
729 if (!xmlbuffer)
730 return -1; // error already displayed by LoadFileToBuffer
731 ctx.xmlbuffers.push_back(xmlbuffer);
732
733 // parse XML
734 xml_document<>* doc = new xml_document<>();
735 doc->parse<0>(xmlbuffer);
736 ctx.xmldocs.push_back(doc);
737
738 xml_node<>* root = doc->first_node("recovery");
739 if (!root)
740 root = doc->first_node("install");
741 if (!root) {
742 LOGERR("Unknown root element in %s\n", filename.c_str());
743 return -1;
744 }
745
746 if (isMain) {
747 int rc = LoadDetails(ctx, root);
748 if (rc != 0)
749 return rc;
750 }
751
752 LOGINFO("Loading resources...\n");
753 xml_node<>* child = root->first_node("resources");
754 if (child)
755 mResources->LoadResources(child, ctx.zip, "theme");
756
757 LOGINFO("Loading variables...\n");
758 child = root->first_node("variables");
759 if (child)
760 LoadVariables(child);
761
762 LOGINFO("Loading mouse cursor...\n");
763 child = root->first_node("mousecursor");
764 if (child)
765 PageManager::LoadCursorData(child);
766
767 LOGINFO("Loading pages...\n");
768 child = root->first_node("templates");
769 if (child)
770 ctx.templates.push_back(child);
771
772 child = root->first_node("styles");
773 if (child)
774 ctx.styles.push_back(child);
775
776 // Load pages
777 child = root->first_node("pages");
778 if (child) {
779 if (LoadPages(ctx, child)) {
780 LOGERR("PageSet::Load returning -1\n");
781 return -1;
782 }
783 }
784
785 // process includes recursively
786 child = root->first_node("include");
787 if (child) {
788 xml_node<>* include = child->first_node("xmlfile");
789 while (include != NULL) {
790 xml_attribute<>* attr = include->first_attribute("name");
791 if (!attr) {
792 LOGERR("Skipping include/xmlfile with no name\n");
793 continue;
794 }
795
796 string filename = ctx.basepath + attr->value();
797 LOGINFO("Including file: %s...\n", filename.c_str());
798 int rc = Load(ctx, filename);
799 if (rc != 0)
800 return rc;
801
802 include = include->next_sibling("xmlfile");
803 }
804 }
805
806 return 0;
807}
808
809void PageSet::MakeEmergencyConsoleIfNeeded()
810{
811 if (mPages.empty()) {
812 mCurrentPage = new Page(NULL, NULL); // fallback console page
813 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
814 mPages.push_back(mCurrentPage);
815 }
816}
817
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500818int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500819{
820 xml_document<> lang;
821 xml_node<>* parent;
822 xml_node<>* child;
823 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600824 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500825
826 if (languageFile) {
827 printf("parsing languageFile\n");
828 lang.parse<0>(languageFile);
829 printf("parsing languageFile done\n");
830 } else {
831 return -1;
832 }
833
834 parent = lang.first_node("language");
835 if (!parent) {
836 LOGERR("Unable to locate language node in language file.\n");
837 lang.clear();
838 return -1;
839 }
840
841 child = parent->first_node("display");
842 if (child) {
843 DataManager::SetValue("tw_language_display", child->value());
844 resource_source = child->value();
845 } else {
846 LOGERR("language file does not have a display value set\n");
847 DataManager::SetValue("tw_language_display", "Not Set");
848 resource_source = languageFile;
849 }
850
851 child = parent->first_node("resources");
852 if (child)
853 mResources->LoadResources(child, package, resource_source);
854 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600855 ret = -1;
856 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500857 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600858 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500859}
860
that6a894592016-03-13 17:51:28 +0100861int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400862{
that6a894592016-03-13 17:51:28 +0100863 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600864 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600865 int theme_ver = 0;
866 xml_node<>* themeversion = child->first_node("themeversion");
867 if (themeversion && themeversion->value()) {
868 theme_ver = atoi(themeversion->value());
869 } else {
870 LOGINFO("No themeversion in theme.\n");
871 }
872 if (theme_ver != TW_THEME_VERSION) {
873 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100874 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600875 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600876 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600877 } else {
878 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
879 }
880 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600881 xml_node<>* resolution = child->first_node("resolution");
882 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600883 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600884 xml_attribute<>* width_attr = resolution->first_attribute("width");
885 xml_attribute<>* height_attr = resolution->first_attribute("height");
886 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
887 if (width_attr && height_attr && !noscale_attr) {
888 int width = atoi(width_attr->value());
889 int height = atoi(height_attr->value());
890 int offx = 0, offy = 0;
891#ifdef TW_ROUND_SCREEN
892 xml_node<>* roundscreen = child->first_node("roundscreen");
893 if (roundscreen) {
894 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
895 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
896 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
897 if (offx_attr) {
898 offx = atoi(offx_attr->value());
899 }
900 if (offy_attr) {
901 offy = atoi(offy_attr->value());
902 }
903 }
904#endif
905 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500906 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
907 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600908#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500909 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
910 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600911 tw_x_offset = offx * scale_off_w;
912 tw_y_offset = offy * scale_off_h;
913#endif
914 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500915 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
916 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600917 set_scale_values(scale_w, scale_h);
918 }
919 }
920 } else {
921 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
922 }
923 } else {
924 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
925 }
926 } else {
927 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
928 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500929
Ethan Yonker780cd392014-07-21 15:24:39 -0500930 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400931}
932
933int PageSet::SetPage(std::string page)
934{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200935 Page* tmp = FindPage(page);
936 if (tmp)
937 {
938 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
939 mCurrentPage = tmp;
940 mCurrentPage->SetPageFocus(1);
941 mCurrentPage->NotifyVarChange("", "");
942 return 0;
943 }
944 else
945 {
946 LOGERR("Unable to locate page (%s)\n", page.c_str());
947 }
948 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400949}
950
951int PageSet::SetOverlay(Page* page)
952{
Ethan Yonker1c273312015-03-16 12:18:56 -0500953 if (page) {
954 if (mOverlays.size() >= 10) {
955 LOGERR("Too many overlays requested, max is 10.\n");
956 return -1;
957 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500958
959 std::vector<Page*>::iterator iter;
960 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
961 if ((*iter)->GetName() == page->GetName()) {
962 mOverlays.erase(iter);
963 // SetOverlay() is (and should stay) the only function which
964 // adds to mOverlays. Then, each page can appear at most once.
965 break;
966 }
967 }
968
Ethan Yonker1c273312015-03-16 12:18:56 -0500969 page->SetPageFocus(1);
970 page->NotifyVarChange("", "");
971
972 if (!mOverlays.empty())
973 mOverlays.back()->SetPageFocus(0);
974
975 mOverlays.push_back(page);
976 } else {
977 if (!mOverlays.empty()) {
978 mOverlays.back()->SetPageFocus(0);
979 mOverlays.pop_back();
980 if (!mOverlays.empty())
981 mOverlays.back()->SetPageFocus(1);
982 else if (mCurrentPage)
983 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
984 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200985 }
986 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400987}
988
that74ac6062015-03-04 22:39:34 +0100989const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400990{
that74ac6062015-03-04 22:39:34 +0100991 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400992}
993
994Page* PageSet::FindPage(std::string name)
995{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200996 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400997
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200998 for (iter = mPages.begin(); iter != mPages.end(); iter++)
999 {
1000 if (name == (*iter)->GetName())
1001 return (*iter);
1002 }
1003 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001004}
1005
1006int PageSet::LoadVariables(xml_node<>* vars)
1007{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001008 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001009 xml_attribute<> *name, *value, *persist;
1010 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001011
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001012 child = vars->first_node("variable");
1013 while (child)
1014 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001015 name = child->first_attribute("name");
1016 value = child->first_attribute("value");
1017 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001018 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001019 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001020 if (strcmp(name->value(), "tw_x_offset") == 0) {
1021 tw_x_offset = atoi(value->value());
1022 child = child->next_sibling("variable");
1023 continue;
1024 }
1025 if (strcmp(name->value(), "tw_y_offset") == 0) {
1026 tw_y_offset = atoi(value->value());
1027 child = child->next_sibling("variable");
1028 continue;
1029 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001030 if (strcmp(name->value(), "tw_w_offset") == 0) {
1031 tw_w_offset = atoi(value->value());
1032 child = child->next_sibling("variable");
1033 continue;
1034 }
1035 if (strcmp(name->value(), "tw_h_offset") == 0) {
1036 tw_h_offset = atoi(value->value());
1037 child = child->next_sibling("variable");
1038 continue;
1039 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001040 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001041 string temp = value->value();
1042 string valstr = gui_parse_text(temp);
1043
1044 if (valstr.find("+") != string::npos) {
1045 string val1str = valstr;
1046 val1str = val1str.substr(0, val1str.find('+'));
1047 string val2str = valstr;
1048 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1049 int val1 = atoi(val1str.c_str());
1050 int val2 = atoi(val2str.c_str());
1051 int val = val1 + val2;
1052
1053 DataManager::SetValue(name->value(), val, p);
1054 } else if (valstr.find("-") != string::npos) {
1055 string val1str = valstr;
1056 val1str = val1str.substr(0, val1str.find('-'));
1057 string val2str = valstr;
1058 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1059 int val1 = atoi(val1str.c_str());
1060 int val2 = atoi(val2str.c_str());
1061 int val = val1 - val2;
1062
1063 DataManager::SetValue(name->value(), val, p);
1064 } else {
1065 DataManager::SetValue(name->value(), valstr, p);
1066 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001067 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001068
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001069 child = child->next_sibling("variable");
1070 }
1071 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001072}
1073
that6a894592016-03-13 17:51:28 +01001074int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001075{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001076 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001077
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001078 if (!pages)
1079 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001080
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001081 child = pages->first_node("page");
1082 while (child != NULL)
1083 {
that6a894592016-03-13 17:51:28 +01001084 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001085 if (page->GetName().empty())
1086 {
1087 LOGERR("Unable to process load page\n");
1088 delete page;
1089 }
1090 else
1091 {
1092 mPages.push_back(page);
1093 }
1094 child = child->next_sibling("page");
1095 }
1096 if (mPages.size() > 0)
1097 return 0;
1098 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001099}
1100
1101int PageSet::IsCurrentPage(Page* page)
1102{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001103 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001104}
1105
that10ae24f2015-12-26 20:53:51 +01001106std::string PageSet::GetCurrentPage() const
1107{
1108 return mCurrentPage ? mCurrentPage->GetName() : "";
1109}
1110
Dees_Troy51a0e822012-09-05 15:24:24 -04001111int PageSet::Render(void)
1112{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001113 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001114
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001115 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1116 if (ret < 0)
1117 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001118
1119 std::vector<Page*>::iterator iter;
1120
1121 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1122 ret = ((*iter) ? (*iter)->Render() : -1);
1123 if (ret < 0)
1124 return ret;
1125 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001126 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001127}
1128
1129int PageSet::Update(void)
1130{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001131 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001132
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001133 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1134 if (ret < 0 || ret > 1)
1135 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001136
1137 std::vector<Page*>::iterator iter;
1138
1139 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1140 ret = ((*iter) ? (*iter)->Update() : -1);
1141 if (ret < 0)
1142 return ret;
1143 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001144 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001145}
1146
1147int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1148{
Ethan Yonker1c273312015-03-16 12:18:56 -05001149 if (!mOverlays.empty())
1150 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001151
1152 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001153}
1154
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001155int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001156{
Ethan Yonker1c273312015-03-16 12:18:56 -05001157 if (!mOverlays.empty())
1158 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001159
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001160 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001161}
1162
that8834a0f2016-01-05 23:29:30 +01001163int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001164{
Ethan Yonker1c273312015-03-16 12:18:56 -05001165 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001166 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001167
that8834a0f2016-01-05 23:29:30 +01001168 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001169}
1170
1171int PageSet::SetKeyBoardFocus(int inFocus)
1172{
Ethan Yonker1c273312015-03-16 12:18:56 -05001173 if (!mOverlays.empty())
1174 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001175
1176 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001177}
1178
1179int PageSet::NotifyVarChange(std::string varName, std::string value)
1180{
Ethan Yonker1c273312015-03-16 12:18:56 -05001181 std::vector<Page*>::iterator iter;
1182
1183 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1184 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001185
1186 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001187}
1188
Ethan Yonker74db1572015-10-28 12:44:49 -05001189void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1190{
1191 mResources->AddStringResource(resource_source, resource_name, value);
1192}
1193
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001194char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001195 size_t len;
1196 char* buffer = NULL;
1197
1198 if (!package) {
1199 // We can try to load the XML directly...
1200 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1201 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001202 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001203 // This isn't always an error, sometimes we request files that don't exist.
1204 return NULL;
1205 }
1206
1207 len = (size_t)st.st_size;
1208
1209 buffer = (char*) malloc(len + 1);
1210 if (!buffer) {
1211 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1212 return NULL;
1213 }
1214
1215 int fd = open(filename.c_str(), O_RDONLY);
1216 if (fd == -1) {
1217 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1218 free(buffer);
1219 return NULL;
1220 }
1221
1222 if (read(fd, buffer, len) < 0) {
1223 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1224 free(buffer);
1225 close(fd);
1226 return NULL;
1227 }
1228 close(fd);
1229 } else {
1230 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001231 if (!package->EntryExists(filename)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001232 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1233 return NULL;
1234 }
1235
1236 // Allocate the buffer for the file
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001237 len = package->GetUncompressedSize(filename);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001238 buffer = (char*) malloc(len + 1);
1239 if (!buffer)
1240 return NULL;
1241
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001242 if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001243 LOGERR("Unable to extract '%s'\n", filename.c_str());
1244 free(buffer);
1245 return NULL;
1246 }
1247 }
1248 // NULL-terminate the string
1249 buffer[len] = 0x00;
1250 return buffer;
1251}
1252
Ethan Yonker74db1572015-10-28 12:44:49 -05001253void PageManager::LoadLanguageListDir(string dir) {
1254 if (!TWFunc::Path_Exists(dir)) {
1255 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1256 return;
1257 }
1258
1259 DIR *d = opendir(dir.c_str());
1260 struct dirent *p;
1261
1262 if (d == NULL) {
1263 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1264 return;
1265 }
1266
1267 while ((p = readdir(d))) {
1268 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1269 continue;
1270
1271 string file = p->d_name;
1272 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1273 continue;
1274 string path = dir + p->d_name;
1275 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1276 struct language_struct language_entry;
1277 language_entry.filename = file_no_extn;
1278 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1279 if (xmlFile == NULL) {
1280 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1281 continue;
1282 }
1283 xml_document<> *doc = new xml_document<>();
1284 doc->parse<0>(xmlFile);
1285
1286 xml_node<>* parent = doc->first_node("language");
1287 if (!parent) {
1288 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1289 } else {
1290 xml_node<>* child = parent->first_node("display");
1291 if (child) {
1292 language_entry.displayvalue = child->value();
1293 } else {
1294 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1295 language_entry.displayvalue = language_entry.filename;
1296 }
1297 Language_List.push_back(language_entry);
1298 }
1299 doc->clear();
1300 delete doc;
1301 free(xmlFile);
1302 }
1303 closedir(d);
1304}
1305
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001306void PageManager::LoadLanguageList(ZipWrap* package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001307 Language_List.clear();
1308 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1309 TWFunc::removeDir(TWRES "customlanguages", true);
1310 if (package) {
1311 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001312 package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001313 LoadLanguageListDir(TWRES "customlanguages/");
1314 } else {
1315 LoadLanguageListDir(TWRES "languages/");
1316 }
Xuefercac6ace2016-02-01 02:28:55 +08001317
1318 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001319}
1320
1321void PageManager::LoadLanguage(string filename) {
1322 string actual_filename;
1323 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1324 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1325 else
1326 actual_filename = TWRES "languages/" + filename + ".xml";
1327 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1328 if (xmlFile == NULL)
1329 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1330 else {
1331 mCurrentSet->LoadLanguage(xmlFile, NULL);
1332 free(xmlFile);
1333 }
1334 PartitionManager.Translate_Partition_Display_Names();
1335}
1336
Dees_Troy51a0e822012-09-05 15:24:24 -04001337int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1338{
that6a894592016-03-13 17:51:28 +01001339 std::string mainxmlfilename = package;
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001340 ZipWrap zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001341 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001342 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001343 PageSet* pageSet = NULL;
1344 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001345 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001346
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001347 mReloadTheme = false;
1348 mStartPage = startpage;
1349
that6a894592016-03-13 17:51:28 +01001350 // init the loading context
1351 LoadingContext ctx;
1352
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001353 // Open the XML file
1354 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001355 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001356 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001357 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001358 tw_x_offset = TW_X_OFFSET;
1359 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001360 tw_w_offset = TW_W_OFFSET;
1361 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001362 if (name != "splash") {
1363 LoadLanguageList(NULL);
1364 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1365 }
that6a894592016-03-13 17:51:28 +01001366 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001367 }
1368 else
1369 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001370 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001371 tw_x_offset = 0;
1372 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001373 tw_w_offset = 0;
1374 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001375 if (!TWFunc::Path_Exists(package))
1376 return -1;
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001377#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001378 if (sysMapFile(package.c_str(), &map) != 0) {
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001379#else
1380 if (!map.MapFile(package)) {
1381#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001382 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001383 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001384 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001385 if (!zip.Open(package.c_str(), &map)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001386 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001387#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001388 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001389#endif
Ethan Yonker561c58d2015-10-05 08:48:22 -05001390 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001391 }
that6a894592016-03-13 17:51:28 +01001392 ctx.zip = &zip;
1393 mainxmlfilename = "ui.xml";
1394 LoadLanguageList(ctx.zip);
1395 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001396 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001397 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001398
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001399 // Before loading, mCurrentSet must be the loading package so we can find resources
1400 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001401 mCurrentSet = new PageSet();
1402
1403 if (baseLanguageFile) {
1404 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1405 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001406 }
that6a894592016-03-13 17:51:28 +01001407
1408 if (languageFile) {
1409 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1410 free(languageFile);
1411 }
1412
1413 // Load and parse the XML and all includes
1414 currentLoadingContext = &ctx; // required to find styles
1415 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1416 currentLoadingContext = NULL;
1417
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001418 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001419 mCurrentSet->SetPage(startpage);
1420 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001421 } else {
1422 if (ret != TW_THEME_VER_ERR)
1423 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001424 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001425
that6a894592016-03-13 17:51:28 +01001426 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001427 mCurrentSet = pageSet;
1428
that6a894592016-03-13 17:51:28 +01001429 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001430 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001431#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001432 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001433#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001434 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001435 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001436
1437error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001438 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001439 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001440 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001441#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001442 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001443#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001444 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001445 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001446}
1447
1448PageSet* PageManager::FindPackage(std::string name)
1449{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001450 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001451
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001452 iter = mPageSets.find(name);
1453 if (iter != mPageSets.end())
1454 return (*iter).second;
1455
1456 LOGERR("Unable to locate package %s\n", name.c_str());
1457 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001458}
1459
1460PageSet* PageManager::SelectPackage(std::string name)
1461{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001462 LOGINFO("Switching packages (%s)\n", name.c_str());
1463 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001464
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001465 tmp = FindPackage(name);
1466 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001467 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001469 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001470 mCurrentSet->NotifyVarChange("", "");
1471 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001472 else
1473 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001474
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001475 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001476}
1477
1478int PageManager::ReloadPackage(std::string name, std::string package)
1479{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001480 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001481
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001482 mReloadTheme = false;
1483
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001484 iter = mPageSets.find(name);
1485 if (iter == mPageSets.end())
1486 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001487
Matt Mowera8a89d12016-12-30 18:10:37 -06001488 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001489 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1490
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001491 PageSet* set = (*iter).second;
1492 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001493
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001494 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001495 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001496 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001497 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1498 return -1;
1499 }
1500 if (mCurrentSet == set)
1501 SelectPackage(name);
1502 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001503 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001504 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001505}
1506
1507void PageManager::ReleasePackage(std::string name)
1508{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001509 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001510
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001511 iter = mPageSets.find(name);
1512 if (iter == mPageSets.end())
1513 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001514
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001515 PageSet* set = (*iter).second;
1516 mPageSets.erase(iter);
1517 delete set;
that235c6482016-01-24 21:59:00 +01001518 if (set == mCurrentSet)
1519 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001520 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001521}
1522
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001523int PageManager::RunReload() {
1524 int ret_val = 0;
1525 std::string theme_path;
1526
1527 if (!mReloadTheme)
1528 return 0;
1529
1530 mReloadTheme = false;
1531 theme_path = DataManager::GetSettingsStoragePath();
1532 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1533 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1534 ret_val = 1;
1535 }
1536
1537 theme_path += "/TWRP/theme/ui.zip";
1538 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1539 {
1540 // Loading the custom theme failed - try loading the stock theme
1541 LOGINFO("Attempting to reload stock theme...\n");
1542 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1543 {
1544 LOGERR("Failed to load base packages.\n");
1545 ret_val = 1;
1546 }
1547 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001548 if (ret_val == 0) {
1549 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1550 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1551 LoadLanguage(DataManager::GetStrValue("tw_language"));
1552 }
1553 }
1554
1555 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001556 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001557
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001558 return ret_val;
1559}
1560
1561void PageManager::RequestReload() {
1562 mReloadTheme = true;
1563}
1564
Ethan Yonkerafde0982016-01-23 08:55:35 -06001565void PageManager::SetStartPage(const std::string& page_name) {
1566 mStartPage = page_name;
1567}
1568
Dees_Troy51a0e822012-09-05 15:24:24 -04001569int PageManager::ChangePage(std::string name)
1570{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001571 DataManager::SetValue("tw_operation_state", 0);
1572 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1573 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001574}
1575
that10ae24f2015-12-26 20:53:51 +01001576std::string PageManager::GetCurrentPage()
1577{
1578 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1579}
1580
Dees_Troy51a0e822012-09-05 15:24:24 -04001581int PageManager::ChangeOverlay(std::string name)
1582{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001583 if (name.empty())
1584 return mCurrentSet->SetOverlay(NULL);
1585 else
1586 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001587 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001588 return mCurrentSet->SetOverlay(page);
1589 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001590}
1591
that74ac6062015-03-04 22:39:34 +01001592const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001593{
that74ac6062015-03-04 22:39:34 +01001594 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001595}
1596
Dees_Troy51a0e822012-09-05 15:24:24 -04001597int PageManager::IsCurrentPage(Page* page)
1598{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001599 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001600}
1601
1602int PageManager::Render(void)
1603{
Matt Mowera8a89d12016-12-30 18:10:37 -06001604 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001605 return 0;
1606
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001607 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001608 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001609 mMouseCursor->Render();
1610 return res;
1611}
1612
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001613HardwareKeyboard *PageManager::GetHardwareKeyboard()
1614{
Matt Mowera8a89d12016-12-30 18:10:37 -06001615 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001616 mHardwareKeyboard = new HardwareKeyboard();
1617 return mHardwareKeyboard;
1618}
1619
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001620xml_node<>* PageManager::FindStyle(std::string name)
1621{
that6a894592016-03-13 17:51:28 +01001622 if (!currentLoadingContext)
1623 {
1624 LOGERR("FindStyle works only while loading a theme.\n");
1625 return NULL;
1626 }
1627
1628 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001629 xml_node<>* node = (*itr)->first_node("style");
1630
1631 while (node) {
1632 if (!node->first_attribute("name"))
1633 continue;
1634
1635 if (name == node->first_attribute("name")->value())
1636 return node;
1637 node = node->next_sibling("style");
1638 }
1639 }
1640 return NULL;
1641}
1642
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001643MouseCursor *PageManager::GetMouseCursor()
1644{
Matt Mowera8a89d12016-12-30 18:10:37 -06001645 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001646 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1647 return mMouseCursor;
1648}
1649
1650void PageManager::LoadCursorData(xml_node<>* node)
1651{
Matt Mowera8a89d12016-12-30 18:10:37 -06001652 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001653 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1654
1655 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001656}
1657
1658int PageManager::Update(void)
1659{
Matt Mowera8a89d12016-12-30 18:10:37 -06001660 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001661 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001662
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001663 if (RunReload())
1664 return -2;
1665
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001666 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1667
Matt Mowera8a89d12016-12-30 18:10:37 -06001668 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001669 {
1670 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001671 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001672 res = c_res;
1673 }
1674 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001675}
1676
1677int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1678{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001679 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001680}
1681
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001682int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001683{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001684 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001685}
1686
that8834a0f2016-01-05 23:29:30 +01001687int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001688{
that8834a0f2016-01-05 23:29:30 +01001689 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001690}
1691
1692int PageManager::SetKeyBoardFocus(int inFocus)
1693{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001694 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001695}
1696
1697int PageManager::NotifyVarChange(std::string varName, std::string value)
1698{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001699 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001700}
1701
Ethan Yonker74db1572015-10-28 12:44:49 -05001702void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1703{
1704 if (mCurrentSet)
1705 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1706}
1707
Dees_Troy51a0e822012-09-05 15:24:24 -04001708extern "C" void gui_notifyVarChange(const char *name, const char* value)
1709{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001710 if (!gGuiRunning)
1711 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001712
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001713 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001714}