blob: a3a1df3254420d47d6b31bfe8ddf951b63a9fef1 [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
45#include "../otautil/SysUtil.h"
46#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
bigbiff bigbiff56cf5642016-08-19 17:43:45 -040060#define TW_THEME_VERSION 3
that74bff7f2017-01-18 22:32:36 +010061
Ethan Yonker8e5692f2016-01-21 11:21:06 -060062#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060063
Dees_Troy51a0e822012-09-05 15:24:24 -040064extern int gGuiRunning;
65
66std::map<std::string, PageSet*> PageManager::mPageSets;
67PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010068MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010069HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050070bool PageManager::mReloadTheme = false;
71std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050072std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040073
Ethan Yonker751a85e2014-12-12 16:59:10 -060074int tw_x_offset = 0;
75int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050076int tw_w_offset = 0;
77int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060078
Dees_Troy51a0e822012-09-05 15:24:24 -040079// Helper routine to convert a string to a color declaration
80int ConvertStrToColor(std::string str, COLOR* color)
81{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020082 // Set the default, solid black
83 memset(color, 0, sizeof(COLOR));
84 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040085
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 // Translate variables
87 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050088
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020089 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010090 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020091 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
92 else if (str == "red") { color->red = 255; return 0; }
93 else if (str == "green") { color->green = 255; return 0; }
94 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040095
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020096 // At this point, we require an RGB(A) color
97 if (str[0] != '#')
98 return -1;
99
100 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400101
Dees_Troy30b962e2012-10-19 20:48:59 -0400102 int result;
103 if (str.size() >= 8) {
104 // We have alpha channel
105 string alpha = str.substr(6, 2);
106 result = strtol(alpha.c_str(), NULL, 16);
107 color->alpha = result & 0x000000FF;
108 str.resize(6);
109 result = strtol(str.c_str(), NULL, 16);
110 color->red = (result >> 16) & 0x000000FF;
111 color->green = (result >> 8) & 0x000000FF;
112 color->blue = result & 0x000000FF;
113 } else {
114 result = strtol(str.c_str(), NULL, 16);
115 color->red = (result >> 16) & 0x000000FF;
116 color->green = (result >> 8) & 0x000000FF;
117 color->blue = result & 0x000000FF;
118 }
119 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400120}
121
122// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600123xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
124{
that8d46c092015-02-26 01:30:04 +0100125 if (!parent)
126 return NULL;
127
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600128 xml_node<>* child = parent->first_node(nodename);
129 if (child)
130 return child;
131
132 if (depth == 10) {
133 LOGERR("Too many style loops detected.\n");
134 return NULL;
135 }
136
137 xml_node<>* style = parent->first_node("style");
138 if (style) {
139 while (style) {
140 if (!style->first_attribute("name")) {
141 LOGERR("No name given for style.\n");
142 continue;
143 } else {
144 std::string name = style->first_attribute("name")->value();
145 xml_node<>* node = PageManager::FindStyle(name);
146
147 if (node) {
148 // We found the style that was named
149 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
150 if (stylenode)
151 return stylenode;
152 }
153 }
154 style = style->next_sibling("style");
155 }
156 } else {
that54e9c832015-11-04 21:46:01 +0100157 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600158 xml_attribute<>* attr = parent->first_attribute("style");
159 // If no style is found anywhere else and the node wasn't found in the object itself
160 // as a special case we will search for a style that uses the same style name as the
161 // object type, so <object type="button"> would search for a style named "button"
162 if (!attr)
163 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100164 // if there's no attribute type, the object type must be the element name
165 std::string stylename = attr ? attr->value() : parent->name();
166 xml_node<>* node = PageManager::FindStyle(stylename);
167 if (node) {
168 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
169 if (stylenode)
170 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600171 }
172 }
173 return NULL;
174}
175
thatf6ed8fc2015-02-14 20:23:16 +0100176std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
177{
178 if (!element)
179 return defaultvalue;
180
181 xml_attribute<>* attr = element->first_attribute(attrname);
182 return attr ? attr->value() : defaultvalue;
183}
184
185int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
186{
187 string value = LoadAttrString(element, attrname);
188 // resolve variables
189 DataManager::GetValue(value, value);
190 return value.empty() ? defaultvalue : atoi(value.c_str());
191}
192
193int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
194{
195 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
196}
197
198int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
199{
200 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
201}
202
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600203COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100204{
205 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600206 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100207 // resolve variables
208 DataManager::GetValue(value, value);
209 COLOR ret = defaultvalue;
210 if (ConvertStrToColor(value, &ret) == 0)
211 return ret;
212 else
213 return defaultvalue;
214}
215
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600216COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
217{
218 bool found_color = false;
219 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
220}
221
thatf6ed8fc2015-02-14 20:23:16 +0100222FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
223{
224 std::string name = LoadAttrString(element, attrname, "");
225 if (name.empty())
226 return NULL;
227 else
that74ac6062015-03-04 22:39:34 +0100228 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100229}
230
231ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
232{
233 std::string name = LoadAttrString(element, attrname, "");
234 if (name.empty())
235 return NULL;
236 else
that74ac6062015-03-04 22:39:34 +0100237 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100238}
239
240AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
241{
242 std::string name = LoadAttrString(element, attrname, "");
243 if (name.empty())
244 return NULL;
245 else
that74ac6062015-03-04 22:39:34 +0100246 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100247}
248
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500249bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400250{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200251 if (!node)
252 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400253
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200254 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100255 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400256
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100258 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400259
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100261 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400262
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200263 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100264 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400265
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200266 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500267 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400268
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200269 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400270}
271
272int ActionObject::SetActionPos(int x, int y, int w, int h)
273{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200274 if (x < 0 || y < 0)
275 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400276
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500277 mActionX = x;
278 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200279 if (w || h)
280 {
281 mActionW = w;
282 mActionH = h;
283 }
284 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400285}
286
thatb63e2f92015-06-27 21:35:11 +0200287Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400288{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200289 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400290
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200291 // We can memset the whole structure, because the alpha channel is ignored
292 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400293
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200294 // With NULL, we make a console-only display
295 if (!page)
296 {
297 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400298
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200299 GUIConsole* element = new GUIConsole(NULL);
300 mRenders.push_back(element);
301 mActions.push_back(element);
302 return;
303 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400304
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200305 if (page->first_attribute("name"))
306 mName = page->first_attribute("name")->value();
307 else
308 {
309 LOGERR("No page name attribute found!\n");
310 return;
311 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400312
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200313 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400314
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200315 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200316 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400317}
318
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100319Page::~Page()
320{
321 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
322 delete *itr;
323}
324
thatb63e2f92015-06-27 21:35:11 +0200325bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400326{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200327 if (depth == 10)
328 {
329 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
330 return false;
331 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400332
thatb63e2f92015-06-27 21:35:11 +0200333 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200334 {
thatb63e2f92015-06-27 21:35:11 +0200335 std::string type = child->name();
336
337 if (type == "background") {
338 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
339 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200340 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400341
thatb63e2f92015-06-27 21:35:11 +0200342 if (type == "object") {
343 // legacy format : <object type="...">
344 xml_attribute<>* attr = child->first_attribute("type");
345 type = attr ? attr->value() : "*unspecified*";
346 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400347
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200348 if (type == "text")
349 {
350 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100351 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200352 mRenders.push_back(element);
353 mActions.push_back(element);
354 }
355 else if (type == "image")
356 {
357 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100358 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200359 mRenders.push_back(element);
360 }
361 else if (type == "fill")
362 {
363 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100364 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200365 mRenders.push_back(element);
366 }
367 else if (type == "action")
368 {
369 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100370 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200371 mActions.push_back(element);
372 }
373 else if (type == "console")
374 {
375 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100376 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200377 mRenders.push_back(element);
378 mActions.push_back(element);
379 }
that1964d192016-01-07 00:41:03 +0100380 else if (type == "terminal")
381 {
382 GUITerminal* element = new GUITerminal(child);
383 mObjects.push_back(element);
384 mRenders.push_back(element);
385 mActions.push_back(element);
386 mInputs.push_back(element);
387 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200388 else if (type == "button")
389 {
390 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100391 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200392 mRenders.push_back(element);
393 mActions.push_back(element);
394 }
395 else if (type == "checkbox")
396 {
397 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100398 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200399 mRenders.push_back(element);
400 mActions.push_back(element);
401 }
402 else if (type == "fileselector")
403 {
404 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100405 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200406 mRenders.push_back(element);
407 mActions.push_back(element);
408 }
409 else if (type == "animation")
410 {
411 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100412 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 mRenders.push_back(element);
414 }
415 else if (type == "progressbar")
416 {
417 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100418 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200419 mRenders.push_back(element);
420 mActions.push_back(element);
421 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400422 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200423 {
424 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100425 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200426 mRenders.push_back(element);
427 mActions.push_back(element);
428 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200429 else if (type == "slidervalue")
430 {
431 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100432 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200433 mRenders.push_back(element);
434 mActions.push_back(element);
435 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400436 else if (type == "listbox")
437 {
438 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100439 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400440 mRenders.push_back(element);
441 mActions.push_back(element);
442 }
443 else if (type == "keyboard")
444 {
445 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100446 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400447 mRenders.push_back(element);
448 mActions.push_back(element);
449 }
450 else if (type == "input")
451 {
452 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100453 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400454 mRenders.push_back(element);
455 mActions.push_back(element);
456 mInputs.push_back(element);
457 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500458 else if (type == "partitionlist")
459 {
460 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100461 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500462 mRenders.push_back(element);
463 mActions.push_back(element);
464 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100465 else if (type == "patternpassword")
466 {
467 GUIPatternPassword* element = new GUIPatternPassword(child);
468 mObjects.push_back(element);
469 mRenders.push_back(element);
470 mActions.push_back(element);
471 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500472 else if (type == "textbox")
473 {
474 GUITextBox* element = new GUITextBox(child);
475 mObjects.push_back(element);
476 mRenders.push_back(element);
477 mActions.push_back(element);
478 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200479 else if (type == "template")
480 {
481 if (!templates || !child->first_attribute("name"))
482 {
483 LOGERR("Invalid template request.\n");
484 }
485 else
486 {
487 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500488 xml_node<>* node;
489 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400490
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200491 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500492 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
493 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400494
Ethan Yonker780cd392014-07-21 15:24:39 -0500495 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200496 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500497 if (!node->first_attribute("name"))
498 continue;
499
500 if (name == node->first_attribute("name")->value())
501 {
502 if (!ProcessNode(node, templates, depth + 1))
503 return false;
504 else {
505 node_found = true;
506 break;
507 }
508 }
509 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200510 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500511 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200512 }
thatb63e2f92015-06-27 21:35:11 +0200513 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200514 }
515 }
516 }
517 else
518 {
thatb63e2f92015-06-27 21:35:11 +0200519 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200520 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200521 }
522 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400523}
524
525int Page::Render(void)
526{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200527 // Render background
528 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
529 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400530
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200531 // Render remaining objects
532 std::vector<RenderObject*>::iterator iter;
533 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
534 {
535 if ((*iter)->Render())
536 LOGERR("A render request has failed.\n");
537 }
538 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400539}
540
541int Page::Update(void)
542{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200543 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400544
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200545 std::vector<RenderObject*>::iterator iter;
546 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
547 {
548 int ret = (*iter)->Update();
549 if (ret < 0)
550 LOGERR("An update request has failed.\n");
551 else if (ret > retCode)
552 retCode = ret;
553 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400554
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200555 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400556}
557
558int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
559{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200560 // By default, return 1 to ignore further touches if nobody is listening
561 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400562
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200563 // Don't try to handle a lack of handlers
564 if (mActions.size() == 0)
565 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400566
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200567 // We record mTouchStart so we can pass all the touch stream to the same handler
568 if (state == TOUCH_START)
569 {
570 std::vector<ActionObject*>::reverse_iterator iter;
571 // We work backwards, from top-most element to bottom-most element
572 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
573 {
574 if ((*iter)->IsInRegion(x, y))
575 {
576 mTouchStart = (*iter);
577 ret = mTouchStart->NotifyTouch(state, x, y);
578 if (ret >= 0)
579 break;
580 mTouchStart = NULL;
581 }
582 }
583 }
584 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
585 {
586 ret = mTouchStart->NotifyTouch(state, x, y);
587 mTouchStart = NULL;
588 }
589 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
590 {
591 ret = mTouchStart->NotifyTouch(state, x, y);
592 }
593 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400594}
595
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100596int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400597{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200598 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400599
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100600 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200601 // We work backwards, from top-most element to bottom-most element
602 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
603 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100604 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100605 if (ret == 0)
606 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100607 if (ret < 0) {
608 LOGERR("An action handler has returned an error\n");
609 ret = 1;
610 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200611 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100612 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400613}
614
that8834a0f2016-01-05 23:29:30 +0100615int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400616{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200617 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400618
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200619 // We work backwards, from top-most element to bottom-most element
620 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
621 {
that8834a0f2016-01-05 23:29:30 +0100622 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200623 if (ret == 0)
624 return 0;
625 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100626 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200627 }
628 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400629}
630
631int Page::SetKeyBoardFocus(int inFocus)
632{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200633 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400634
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200635 // We work backwards, from top-most element to bottom-most element
636 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
637 {
638 int ret = (*iter)->SetInputFocus(inFocus);
639 if (ret == 0)
640 return 0;
641 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100642 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200643 }
644 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400645}
646
647void Page::SetPageFocus(int inFocus)
648{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200649 // Render remaining objects
650 std::vector<RenderObject*>::iterator iter;
651 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
652 (*iter)->SetPageFocus(inFocus);
653
654 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400655}
656
657int Page::NotifyVarChange(std::string varName, std::string value)
658{
Vojtech Bocek07220562014-02-08 02:05:33 +0100659 std::vector<GUIObject*>::iterator iter;
660 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200661 {
662 if ((*iter)->NotifyVarChange(varName, value))
663 LOGERR("An action handler errored on NotifyVarChange.\n");
664 }
665 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400666}
667
that6a894592016-03-13 17:51:28 +0100668
669// transient data for loading themes
670struct LoadingContext
671{
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500672 ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100673 std::set<std::string> filenames; // to detect cyclic includes
674 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
675 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
676 std::vector<char*> xmlbuffers; // text buffers with xml content
677 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
678 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
679
680 LoadingContext()
681 {
682 zip = NULL;
683 }
684
685 ~LoadingContext()
686 {
687 // free all xml buffers
688 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
689 free(*it);
690 }
691
692};
693
694// for FindStyle
695LoadingContext* PageManager::currentLoadingContext = NULL;
696
697
698PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400699{
that74ac6062015-03-04 22:39:34 +0100700 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200701 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400702
that6a894592016-03-13 17:51:28 +0100703 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400704}
705
706PageSet::~PageSet()
707{
Ethan Yonker1c273312015-03-16 12:18:56 -0500708 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100709 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
710 delete *itr;
711
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200712 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400713}
714
that6a894592016-03-13 17:51:28 +0100715int PageSet::Load(LoadingContext& ctx, const std::string& filename)
716{
717 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
718
719 if (!ctx.filenames.insert(filename).second)
720 // ignore already loaded files to prevent crash with cyclic includes
721 return 0;
722
723 // load XML into buffer
724 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
725 if (!xmlbuffer)
726 return -1; // error already displayed by LoadFileToBuffer
727 ctx.xmlbuffers.push_back(xmlbuffer);
728
729 // parse XML
730 xml_document<>* doc = new xml_document<>();
731 doc->parse<0>(xmlbuffer);
732 ctx.xmldocs.push_back(doc);
733
734 xml_node<>* root = doc->first_node("recovery");
735 if (!root)
736 root = doc->first_node("install");
737 if (!root) {
738 LOGERR("Unknown root element in %s\n", filename.c_str());
739 return -1;
740 }
741
742 if (isMain) {
743 int rc = LoadDetails(ctx, root);
744 if (rc != 0)
745 return rc;
746 }
747
748 LOGINFO("Loading resources...\n");
749 xml_node<>* child = root->first_node("resources");
750 if (child)
751 mResources->LoadResources(child, ctx.zip, "theme");
752
753 LOGINFO("Loading variables...\n");
754 child = root->first_node("variables");
755 if (child)
756 LoadVariables(child);
757
758 LOGINFO("Loading mouse cursor...\n");
759 child = root->first_node("mousecursor");
760 if (child)
761 PageManager::LoadCursorData(child);
762
763 LOGINFO("Loading pages...\n");
764 child = root->first_node("templates");
765 if (child)
766 ctx.templates.push_back(child);
767
768 child = root->first_node("styles");
769 if (child)
770 ctx.styles.push_back(child);
771
772 // Load pages
773 child = root->first_node("pages");
774 if (child) {
775 if (LoadPages(ctx, child)) {
776 LOGERR("PageSet::Load returning -1\n");
777 return -1;
778 }
779 }
780
781 // process includes recursively
782 child = root->first_node("include");
783 if (child) {
784 xml_node<>* include = child->first_node("xmlfile");
785 while (include != NULL) {
786 xml_attribute<>* attr = include->first_attribute("name");
787 if (!attr) {
788 LOGERR("Skipping include/xmlfile with no name\n");
789 continue;
790 }
791
792 string filename = ctx.basepath + attr->value();
793 LOGINFO("Including file: %s...\n", filename.c_str());
794 int rc = Load(ctx, filename);
795 if (rc != 0)
796 return rc;
797
798 include = include->next_sibling("xmlfile");
799 }
800 }
801
802 return 0;
803}
804
805void PageSet::MakeEmergencyConsoleIfNeeded()
806{
807 if (mPages.empty()) {
808 mCurrentPage = new Page(NULL, NULL); // fallback console page
809 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
810 mPages.push_back(mCurrentPage);
811 }
812}
813
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500814int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500815{
816 xml_document<> lang;
817 xml_node<>* parent;
818 xml_node<>* child;
819 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600820 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500821
822 if (languageFile) {
823 printf("parsing languageFile\n");
824 lang.parse<0>(languageFile);
825 printf("parsing languageFile done\n");
826 } else {
827 return -1;
828 }
829
830 parent = lang.first_node("language");
831 if (!parent) {
832 LOGERR("Unable to locate language node in language file.\n");
833 lang.clear();
834 return -1;
835 }
836
837 child = parent->first_node("display");
838 if (child) {
839 DataManager::SetValue("tw_language_display", child->value());
840 resource_source = child->value();
841 } else {
842 LOGERR("language file does not have a display value set\n");
843 DataManager::SetValue("tw_language_display", "Not Set");
844 resource_source = languageFile;
845 }
846
847 child = parent->first_node("resources");
848 if (child)
849 mResources->LoadResources(child, package, resource_source);
850 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600851 ret = -1;
852 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500853 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600854 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500855}
856
that6a894592016-03-13 17:51:28 +0100857int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400858{
that6a894592016-03-13 17:51:28 +0100859 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600860 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600861 int theme_ver = 0;
862 xml_node<>* themeversion = child->first_node("themeversion");
863 if (themeversion && themeversion->value()) {
864 theme_ver = atoi(themeversion->value());
865 } else {
866 LOGINFO("No themeversion in theme.\n");
867 }
868 if (theme_ver != TW_THEME_VERSION) {
869 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100870 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600871 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600872 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600873 } else {
874 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
875 }
876 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600877 xml_node<>* resolution = child->first_node("resolution");
878 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600879 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600880 xml_attribute<>* width_attr = resolution->first_attribute("width");
881 xml_attribute<>* height_attr = resolution->first_attribute("height");
882 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
883 if (width_attr && height_attr && !noscale_attr) {
884 int width = atoi(width_attr->value());
885 int height = atoi(height_attr->value());
886 int offx = 0, offy = 0;
887#ifdef TW_ROUND_SCREEN
888 xml_node<>* roundscreen = child->first_node("roundscreen");
889 if (roundscreen) {
890 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
891 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
892 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
893 if (offx_attr) {
894 offx = atoi(offx_attr->value());
895 }
896 if (offy_attr) {
897 offy = atoi(offy_attr->value());
898 }
899 }
900#endif
901 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500902 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
903 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600904#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500905 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
906 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600907 tw_x_offset = offx * scale_off_w;
908 tw_y_offset = offy * scale_off_h;
909#endif
910 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500911 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
912 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600913 set_scale_values(scale_w, scale_h);
914 }
915 }
916 } else {
917 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
918 }
919 } else {
920 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
921 }
922 } else {
923 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
924 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500925
Ethan Yonker780cd392014-07-21 15:24:39 -0500926 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400927}
928
929int PageSet::SetPage(std::string page)
930{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200931 Page* tmp = FindPage(page);
932 if (tmp)
933 {
934 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
935 mCurrentPage = tmp;
936 mCurrentPage->SetPageFocus(1);
937 mCurrentPage->NotifyVarChange("", "");
938 return 0;
939 }
940 else
941 {
942 LOGERR("Unable to locate page (%s)\n", page.c_str());
943 }
944 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400945}
946
947int PageSet::SetOverlay(Page* page)
948{
Ethan Yonker1c273312015-03-16 12:18:56 -0500949 if (page) {
950 if (mOverlays.size() >= 10) {
951 LOGERR("Too many overlays requested, max is 10.\n");
952 return -1;
953 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500954
955 std::vector<Page*>::iterator iter;
956 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
957 if ((*iter)->GetName() == page->GetName()) {
958 mOverlays.erase(iter);
959 // SetOverlay() is (and should stay) the only function which
960 // adds to mOverlays. Then, each page can appear at most once.
961 break;
962 }
963 }
964
Ethan Yonker1c273312015-03-16 12:18:56 -0500965 page->SetPageFocus(1);
966 page->NotifyVarChange("", "");
967
968 if (!mOverlays.empty())
969 mOverlays.back()->SetPageFocus(0);
970
971 mOverlays.push_back(page);
972 } else {
973 if (!mOverlays.empty()) {
974 mOverlays.back()->SetPageFocus(0);
975 mOverlays.pop_back();
976 if (!mOverlays.empty())
977 mOverlays.back()->SetPageFocus(1);
978 else if (mCurrentPage)
979 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
980 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200981 }
982 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400983}
984
that74ac6062015-03-04 22:39:34 +0100985const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400986{
that74ac6062015-03-04 22:39:34 +0100987 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400988}
989
990Page* PageSet::FindPage(std::string name)
991{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200992 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400993
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200994 for (iter = mPages.begin(); iter != mPages.end(); iter++)
995 {
996 if (name == (*iter)->GetName())
997 return (*iter);
998 }
999 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001000}
1001
1002int PageSet::LoadVariables(xml_node<>* vars)
1003{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001004 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001005 xml_attribute<> *name, *value, *persist;
1006 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001007
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001008 child = vars->first_node("variable");
1009 while (child)
1010 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001011 name = child->first_attribute("name");
1012 value = child->first_attribute("value");
1013 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001014 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001015 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001016 if (strcmp(name->value(), "tw_x_offset") == 0) {
1017 tw_x_offset = atoi(value->value());
1018 child = child->next_sibling("variable");
1019 continue;
1020 }
1021 if (strcmp(name->value(), "tw_y_offset") == 0) {
1022 tw_y_offset = atoi(value->value());
1023 child = child->next_sibling("variable");
1024 continue;
1025 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001026 if (strcmp(name->value(), "tw_w_offset") == 0) {
1027 tw_w_offset = atoi(value->value());
1028 child = child->next_sibling("variable");
1029 continue;
1030 }
1031 if (strcmp(name->value(), "tw_h_offset") == 0) {
1032 tw_h_offset = atoi(value->value());
1033 child = child->next_sibling("variable");
1034 continue;
1035 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001036 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001037 string temp = value->value();
1038 string valstr = gui_parse_text(temp);
1039
1040 if (valstr.find("+") != string::npos) {
1041 string val1str = valstr;
1042 val1str = val1str.substr(0, val1str.find('+'));
1043 string val2str = valstr;
1044 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1045 int val1 = atoi(val1str.c_str());
1046 int val2 = atoi(val2str.c_str());
1047 int val = val1 + val2;
1048
1049 DataManager::SetValue(name->value(), val, p);
1050 } else if (valstr.find("-") != string::npos) {
1051 string val1str = valstr;
1052 val1str = val1str.substr(0, val1str.find('-'));
1053 string val2str = valstr;
1054 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1055 int val1 = atoi(val1str.c_str());
1056 int val2 = atoi(val2str.c_str());
1057 int val = val1 - val2;
1058
1059 DataManager::SetValue(name->value(), val, p);
1060 } else {
1061 DataManager::SetValue(name->value(), valstr, p);
1062 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001063 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001064
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001065 child = child->next_sibling("variable");
1066 }
1067 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001068}
1069
that6a894592016-03-13 17:51:28 +01001070int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001071{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001072 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001073
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001074 if (!pages)
1075 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001076
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001077 child = pages->first_node("page");
1078 while (child != NULL)
1079 {
that6a894592016-03-13 17:51:28 +01001080 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001081 if (page->GetName().empty())
1082 {
1083 LOGERR("Unable to process load page\n");
1084 delete page;
1085 }
1086 else
1087 {
1088 mPages.push_back(page);
1089 }
1090 child = child->next_sibling("page");
1091 }
1092 if (mPages.size() > 0)
1093 return 0;
1094 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001095}
1096
1097int PageSet::IsCurrentPage(Page* page)
1098{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001099 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001100}
1101
that10ae24f2015-12-26 20:53:51 +01001102std::string PageSet::GetCurrentPage() const
1103{
1104 return mCurrentPage ? mCurrentPage->GetName() : "";
1105}
1106
Dees_Troy51a0e822012-09-05 15:24:24 -04001107int PageSet::Render(void)
1108{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001109 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001110
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001111 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1112 if (ret < 0)
1113 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001114
1115 std::vector<Page*>::iterator iter;
1116
1117 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1118 ret = ((*iter) ? (*iter)->Render() : -1);
1119 if (ret < 0)
1120 return ret;
1121 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001122 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001123}
1124
1125int PageSet::Update(void)
1126{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001127 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001128
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001129 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1130 if (ret < 0 || ret > 1)
1131 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001132
1133 std::vector<Page*>::iterator iter;
1134
1135 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1136 ret = ((*iter) ? (*iter)->Update() : -1);
1137 if (ret < 0)
1138 return ret;
1139 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001140 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001141}
1142
1143int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1144{
Ethan Yonker1c273312015-03-16 12:18:56 -05001145 if (!mOverlays.empty())
1146 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001147
1148 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001149}
1150
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001151int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001152{
Ethan Yonker1c273312015-03-16 12:18:56 -05001153 if (!mOverlays.empty())
1154 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001155
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001156 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001157}
1158
that8834a0f2016-01-05 23:29:30 +01001159int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001160{
Ethan Yonker1c273312015-03-16 12:18:56 -05001161 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001162 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001163
that8834a0f2016-01-05 23:29:30 +01001164 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001165}
1166
1167int PageSet::SetKeyBoardFocus(int inFocus)
1168{
Ethan Yonker1c273312015-03-16 12:18:56 -05001169 if (!mOverlays.empty())
1170 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001171
1172 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001173}
1174
1175int PageSet::NotifyVarChange(std::string varName, std::string value)
1176{
Ethan Yonker1c273312015-03-16 12:18:56 -05001177 std::vector<Page*>::iterator iter;
1178
1179 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1180 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001181
1182 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001183}
1184
Ethan Yonker74db1572015-10-28 12:44:49 -05001185void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1186{
1187 mResources->AddStringResource(resource_source, resource_name, value);
1188}
1189
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001190char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001191 size_t len;
1192 char* buffer = NULL;
1193
1194 if (!package) {
1195 // We can try to load the XML directly...
1196 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1197 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001198 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001199 // This isn't always an error, sometimes we request files that don't exist.
1200 return NULL;
1201 }
1202
1203 len = (size_t)st.st_size;
1204
1205 buffer = (char*) malloc(len + 1);
1206 if (!buffer) {
1207 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1208 return NULL;
1209 }
1210
1211 int fd = open(filename.c_str(), O_RDONLY);
1212 if (fd == -1) {
1213 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1214 free(buffer);
1215 return NULL;
1216 }
1217
1218 if (read(fd, buffer, len) < 0) {
1219 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1220 free(buffer);
1221 close(fd);
1222 return NULL;
1223 }
1224 close(fd);
1225 } else {
1226 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001227 if (!package->EntryExists(filename)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001228 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1229 return NULL;
1230 }
1231
1232 // Allocate the buffer for the file
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001233 len = package->GetUncompressedSize(filename);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001234 buffer = (char*) malloc(len + 1);
1235 if (!buffer)
1236 return NULL;
1237
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001238 if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001239 LOGERR("Unable to extract '%s'\n", filename.c_str());
1240 free(buffer);
1241 return NULL;
1242 }
1243 }
1244 // NULL-terminate the string
1245 buffer[len] = 0x00;
1246 return buffer;
1247}
1248
Ethan Yonker74db1572015-10-28 12:44:49 -05001249void PageManager::LoadLanguageListDir(string dir) {
1250 if (!TWFunc::Path_Exists(dir)) {
1251 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1252 return;
1253 }
1254
1255 DIR *d = opendir(dir.c_str());
1256 struct dirent *p;
1257
1258 if (d == NULL) {
1259 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1260 return;
1261 }
1262
1263 while ((p = readdir(d))) {
1264 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1265 continue;
1266
1267 string file = p->d_name;
1268 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1269 continue;
1270 string path = dir + p->d_name;
1271 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1272 struct language_struct language_entry;
1273 language_entry.filename = file_no_extn;
1274 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1275 if (xmlFile == NULL) {
1276 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1277 continue;
1278 }
1279 xml_document<> *doc = new xml_document<>();
1280 doc->parse<0>(xmlFile);
1281
1282 xml_node<>* parent = doc->first_node("language");
1283 if (!parent) {
1284 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1285 } else {
1286 xml_node<>* child = parent->first_node("display");
1287 if (child) {
1288 language_entry.displayvalue = child->value();
1289 } else {
1290 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1291 language_entry.displayvalue = language_entry.filename;
1292 }
1293 Language_List.push_back(language_entry);
1294 }
1295 doc->clear();
1296 delete doc;
1297 free(xmlFile);
1298 }
1299 closedir(d);
1300}
1301
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001302void PageManager::LoadLanguageList(ZipWrap* package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001303 Language_List.clear();
1304 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1305 TWFunc::removeDir(TWRES "customlanguages", true);
1306 if (package) {
1307 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001308 package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001309 LoadLanguageListDir(TWRES "customlanguages/");
1310 } else {
1311 LoadLanguageListDir(TWRES "languages/");
1312 }
Xuefercac6ace2016-02-01 02:28:55 +08001313
1314 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001315}
1316
1317void PageManager::LoadLanguage(string filename) {
1318 string actual_filename;
1319 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1320 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1321 else
1322 actual_filename = TWRES "languages/" + filename + ".xml";
1323 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1324 if (xmlFile == NULL)
1325 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1326 else {
1327 mCurrentSet->LoadLanguage(xmlFile, NULL);
1328 free(xmlFile);
1329 }
1330 PartitionManager.Translate_Partition_Display_Names();
1331}
1332
Dees_Troy51a0e822012-09-05 15:24:24 -04001333int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1334{
that6a894592016-03-13 17:51:28 +01001335 std::string mainxmlfilename = package;
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001336 ZipWrap zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001337 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001338 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001339 PageSet* pageSet = NULL;
1340 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001341 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001342
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001343 mReloadTheme = false;
1344 mStartPage = startpage;
1345
that6a894592016-03-13 17:51:28 +01001346 // init the loading context
1347 LoadingContext ctx;
1348
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001349 // Open the XML file
1350 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001351 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001352 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001353 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001354 tw_x_offset = TW_X_OFFSET;
1355 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001356 tw_w_offset = TW_W_OFFSET;
1357 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001358 if (name != "splash") {
1359 LoadLanguageList(NULL);
1360 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1361 }
that6a894592016-03-13 17:51:28 +01001362 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001363 }
1364 else
1365 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001366 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001367 tw_x_offset = 0;
1368 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001369 tw_w_offset = 0;
1370 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001371 if (!TWFunc::Path_Exists(package))
1372 return -1;
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001373#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001374 if (sysMapFile(package.c_str(), &map) != 0) {
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001375#else
1376 if (!map.MapFile(package)) {
1377#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001378 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001379 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001380 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001381 if (!zip.Open(package.c_str(), &map)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001382 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001383#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001384 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001385#endif
Ethan Yonker561c58d2015-10-05 08:48:22 -05001386 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001387 }
that6a894592016-03-13 17:51:28 +01001388 ctx.zip = &zip;
1389 mainxmlfilename = "ui.xml";
1390 LoadLanguageList(ctx.zip);
1391 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001392 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001393 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001394
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001395 // Before loading, mCurrentSet must be the loading package so we can find resources
1396 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001397 mCurrentSet = new PageSet();
1398
1399 if (baseLanguageFile) {
1400 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1401 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001402 }
that6a894592016-03-13 17:51:28 +01001403
1404 if (languageFile) {
1405 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1406 free(languageFile);
1407 }
1408
1409 // Load and parse the XML and all includes
1410 currentLoadingContext = &ctx; // required to find styles
1411 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1412 currentLoadingContext = NULL;
1413
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001414 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001415 mCurrentSet->SetPage(startpage);
1416 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001417 } else {
1418 if (ret != TW_THEME_VER_ERR)
1419 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001420 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001421
that6a894592016-03-13 17:51:28 +01001422 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001423 mCurrentSet = pageSet;
1424
that6a894592016-03-13 17:51:28 +01001425 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001426 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001427#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001428 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001429#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001430 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001431 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001432
1433error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001434 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001435 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001436 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001437#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001438 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001439#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001440 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001441 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001442}
1443
1444PageSet* PageManager::FindPackage(std::string name)
1445{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001446 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001447
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001448 iter = mPageSets.find(name);
1449 if (iter != mPageSets.end())
1450 return (*iter).second;
1451
1452 LOGERR("Unable to locate package %s\n", name.c_str());
1453 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001454}
1455
1456PageSet* PageManager::SelectPackage(std::string name)
1457{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001458 LOGINFO("Switching packages (%s)\n", name.c_str());
1459 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001460
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001461 tmp = FindPackage(name);
1462 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001463 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001464 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001465 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001466 mCurrentSet->NotifyVarChange("", "");
1467 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 else
1469 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001470
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001471 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001472}
1473
1474int PageManager::ReloadPackage(std::string name, std::string package)
1475{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001476 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001477
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001478 mReloadTheme = false;
1479
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001480 iter = mPageSets.find(name);
1481 if (iter == mPageSets.end())
1482 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001483
Matt Mowera8a89d12016-12-30 18:10:37 -06001484 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001485 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1486
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001487 PageSet* set = (*iter).second;
1488 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001489
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001490 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001491 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001492 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001493 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1494 return -1;
1495 }
1496 if (mCurrentSet == set)
1497 SelectPackage(name);
1498 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001499 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001500 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001501}
1502
1503void PageManager::ReleasePackage(std::string name)
1504{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001505 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001506
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001507 iter = mPageSets.find(name);
1508 if (iter == mPageSets.end())
1509 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001510
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001511 PageSet* set = (*iter).second;
1512 mPageSets.erase(iter);
1513 delete set;
that235c6482016-01-24 21:59:00 +01001514 if (set == mCurrentSet)
1515 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001516 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001517}
1518
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001519int PageManager::RunReload() {
1520 int ret_val = 0;
1521 std::string theme_path;
1522
1523 if (!mReloadTheme)
1524 return 0;
1525
1526 mReloadTheme = false;
1527 theme_path = DataManager::GetSettingsStoragePath();
1528 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1529 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1530 ret_val = 1;
1531 }
1532
1533 theme_path += "/TWRP/theme/ui.zip";
1534 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1535 {
1536 // Loading the custom theme failed - try loading the stock theme
1537 LOGINFO("Attempting to reload stock theme...\n");
1538 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1539 {
1540 LOGERR("Failed to load base packages.\n");
1541 ret_val = 1;
1542 }
1543 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001544 if (ret_val == 0) {
1545 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1546 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1547 LoadLanguage(DataManager::GetStrValue("tw_language"));
1548 }
1549 }
1550
1551 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001552 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001553
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001554 return ret_val;
1555}
1556
1557void PageManager::RequestReload() {
1558 mReloadTheme = true;
1559}
1560
Ethan Yonkerafde0982016-01-23 08:55:35 -06001561void PageManager::SetStartPage(const std::string& page_name) {
1562 mStartPage = page_name;
1563}
1564
Dees_Troy51a0e822012-09-05 15:24:24 -04001565int PageManager::ChangePage(std::string name)
1566{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001567 DataManager::SetValue("tw_operation_state", 0);
1568 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1569 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001570}
1571
that10ae24f2015-12-26 20:53:51 +01001572std::string PageManager::GetCurrentPage()
1573{
1574 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1575}
1576
Dees_Troy51a0e822012-09-05 15:24:24 -04001577int PageManager::ChangeOverlay(std::string name)
1578{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001579 if (name.empty())
1580 return mCurrentSet->SetOverlay(NULL);
1581 else
1582 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001583 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001584 return mCurrentSet->SetOverlay(page);
1585 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001586}
1587
that74ac6062015-03-04 22:39:34 +01001588const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001589{
that74ac6062015-03-04 22:39:34 +01001590 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001591}
1592
Dees_Troy51a0e822012-09-05 15:24:24 -04001593int PageManager::IsCurrentPage(Page* page)
1594{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001595 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001596}
1597
1598int PageManager::Render(void)
1599{
Matt Mowera8a89d12016-12-30 18:10:37 -06001600 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001601 return 0;
1602
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001603 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001604 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001605 mMouseCursor->Render();
1606 return res;
1607}
1608
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001609HardwareKeyboard *PageManager::GetHardwareKeyboard()
1610{
Matt Mowera8a89d12016-12-30 18:10:37 -06001611 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001612 mHardwareKeyboard = new HardwareKeyboard();
1613 return mHardwareKeyboard;
1614}
1615
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001616xml_node<>* PageManager::FindStyle(std::string name)
1617{
that6a894592016-03-13 17:51:28 +01001618 if (!currentLoadingContext)
1619 {
1620 LOGERR("FindStyle works only while loading a theme.\n");
1621 return NULL;
1622 }
1623
1624 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001625 xml_node<>* node = (*itr)->first_node("style");
1626
1627 while (node) {
1628 if (!node->first_attribute("name"))
1629 continue;
1630
1631 if (name == node->first_attribute("name")->value())
1632 return node;
1633 node = node->next_sibling("style");
1634 }
1635 }
1636 return NULL;
1637}
1638
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001639MouseCursor *PageManager::GetMouseCursor()
1640{
Matt Mowera8a89d12016-12-30 18:10:37 -06001641 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001642 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1643 return mMouseCursor;
1644}
1645
1646void PageManager::LoadCursorData(xml_node<>* node)
1647{
Matt Mowera8a89d12016-12-30 18:10:37 -06001648 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001649 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1650
1651 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001652}
1653
1654int PageManager::Update(void)
1655{
Matt Mowera8a89d12016-12-30 18:10:37 -06001656 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001657 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001658
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001659 if (RunReload())
1660 return -2;
1661
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001662 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1663
Matt Mowera8a89d12016-12-30 18:10:37 -06001664 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001665 {
1666 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001667 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001668 res = c_res;
1669 }
1670 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001671}
1672
1673int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1674{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001675 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001676}
1677
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001678int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001679{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001680 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001681}
1682
that8834a0f2016-01-05 23:29:30 +01001683int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001684{
that8834a0f2016-01-05 23:29:30 +01001685 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001686}
1687
1688int PageManager::SetKeyBoardFocus(int inFocus)
1689{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001690 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001691}
1692
1693int PageManager::NotifyVarChange(std::string varName, std::string value)
1694{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001695 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001696}
1697
Ethan Yonker74db1572015-10-28 12:44:49 -05001698void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1699{
1700 if (mCurrentSet)
1701 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1702}
1703
Dees_Troy51a0e822012-09-05 15:24:24 -04001704extern "C" void gui_notifyVarChange(const char *name, const char* value)
1705{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001706 if (!gGuiRunning)
1707 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001708
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001709 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001710}