blob: a3047bbe98f8dc467355bfe44e4463009c9f82f5 [file] [log] [blame]
Dees_Troya13d74f2013-03-24 08:54:55 -05001/*
2 Copyright 2013 bigbiff/Dees_Troy TeamWin
3 This file is part of TWRP/TeamWin Recovery Project.
4
5 TWRP is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 TWRP is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TWRP. If not, see <http://www.gnu.org/licenses/>.
17*/
Dees Troy3be70a82013-10-22 14:25:12 +000018
Dees_Troya13d74f2013-03-24 08:54:55 -050019// pages.cpp - Source to manage GUI base objects
Dees_Troy51a0e822012-09-05 15:24:24 -040020
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <fcntl.h>
26#include <sys/reboot.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29#include <sys/mman.h>
30#include <sys/types.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
34#include <stdlib.h>
Ethan Yonker3fdcda42016-11-30 12:29:37 -060035#include <dirent.h>
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060036#include "../twrp-functions.hpp"
Ethan Yonker74db1572015-10-28 12:44:49 -050037#include "../partitions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040038
39#include <string>
Xuefercac6ace2016-02-01 02:28:55 +080040#include <algorithm>
Dees_Troy51a0e822012-09-05 15:24:24 -040041
Ethan Yonker8373cfe2017-09-08 06:50:54 -050042#ifdef USE_MINZIP
43#include "../minzip/SysUtil.h"
44#else
bigbiffd58ba182020-03-23 10:02:29 -040045#ifdef USE_OTAUTIL_ZIPARCHIVE
Ethan Yonker58f21322018-08-24 11:17:36 -050046#include <otautil/SysUtil.h>
bigbiffd58ba182020-03-23 10:02:29 -040047#else
48#include <ziparchive/zip_archive.h>
49#endif
Ethan Yonker8373cfe2017-09-08 06:50:54 -050050#endif
51
Dees_Troy51a0e822012-09-05 15:24:24 -040052extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000053#include "../twcommon.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060054#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040055}
bigbiffd58ba182020-03-23 10:02:29 -040056#include "zipwrap.hpp"
Ethan Yonkerfbb43532015-12-28 21:54:50 +010057#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040058
59#include "rapidxml.hpp"
60#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020061#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040062
that74bff7f2017-01-18 22:32:36 +010063// version 2 requires theme to handle power button as action togglebacklight
Captain Throwback3b339542020-10-22 09:33:29 -040064// version 4 adds fastbootd support
65#define TW_THEME_VERSION 4
that74bff7f2017-01-18 22:32:36 +010066
Ethan Yonker8e5692f2016-01-21 11:21:06 -060067#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060068
Dees_Troy51a0e822012-09-05 15:24:24 -040069extern int gGuiRunning;
70
71std::map<std::string, PageSet*> PageManager::mPageSets;
72PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010073MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010074HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050075bool PageManager::mReloadTheme = false;
76std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050077std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040078
Ethan Yonker751a85e2014-12-12 16:59:10 -060079int tw_x_offset = 0;
80int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050081int tw_w_offset = 0;
82int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060083
Dees_Troy51a0e822012-09-05 15:24:24 -040084// Helper routine to convert a string to a color declaration
85int ConvertStrToColor(std::string str, COLOR* color)
86{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 // Set the default, solid black
88 memset(color, 0, sizeof(COLOR));
89 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040090
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020091 // Translate variables
92 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050093
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020094 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010095 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020096 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
97 else if (str == "red") { color->red = 255; return 0; }
98 else if (str == "green") { color->green = 255; return 0; }
99 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -0400100
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200101 // At this point, we require an RGB(A) color
102 if (str[0] != '#')
103 return -1;
104
105 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400106
Dees_Troy30b962e2012-10-19 20:48:59 -0400107 int result;
108 if (str.size() >= 8) {
109 // We have alpha channel
110 string alpha = str.substr(6, 2);
111 result = strtol(alpha.c_str(), NULL, 16);
112 color->alpha = result & 0x000000FF;
113 str.resize(6);
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 } else {
119 result = strtol(str.c_str(), NULL, 16);
120 color->red = (result >> 16) & 0x000000FF;
121 color->green = (result >> 8) & 0x000000FF;
122 color->blue = result & 0x000000FF;
123 }
124 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400125}
126
127// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600128xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
129{
that8d46c092015-02-26 01:30:04 +0100130 if (!parent)
131 return NULL;
132
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600133 xml_node<>* child = parent->first_node(nodename);
134 if (child)
135 return child;
136
137 if (depth == 10) {
138 LOGERR("Too many style loops detected.\n");
139 return NULL;
140 }
141
142 xml_node<>* style = parent->first_node("style");
143 if (style) {
144 while (style) {
145 if (!style->first_attribute("name")) {
146 LOGERR("No name given for style.\n");
147 continue;
148 } else {
149 std::string name = style->first_attribute("name")->value();
150 xml_node<>* node = PageManager::FindStyle(name);
151
152 if (node) {
153 // We found the style that was named
154 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
155 if (stylenode)
156 return stylenode;
157 }
158 }
159 style = style->next_sibling("style");
160 }
161 } else {
that54e9c832015-11-04 21:46:01 +0100162 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600163 xml_attribute<>* attr = parent->first_attribute("style");
164 // If no style is found anywhere else and the node wasn't found in the object itself
165 // as a special case we will search for a style that uses the same style name as the
166 // object type, so <object type="button"> would search for a style named "button"
167 if (!attr)
168 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100169 // if there's no attribute type, the object type must be the element name
170 std::string stylename = attr ? attr->value() : parent->name();
171 xml_node<>* node = PageManager::FindStyle(stylename);
172 if (node) {
173 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
174 if (stylenode)
175 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600176 }
177 }
178 return NULL;
179}
180
thatf6ed8fc2015-02-14 20:23:16 +0100181std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
182{
183 if (!element)
184 return defaultvalue;
185
186 xml_attribute<>* attr = element->first_attribute(attrname);
187 return attr ? attr->value() : defaultvalue;
188}
189
190int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
191{
192 string value = LoadAttrString(element, attrname);
193 // resolve variables
194 DataManager::GetValue(value, value);
195 return value.empty() ? defaultvalue : atoi(value.c_str());
196}
197
198int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
199{
200 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
201}
202
203int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
204{
205 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
206}
207
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600208COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100209{
210 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600211 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100212 // resolve variables
213 DataManager::GetValue(value, value);
214 COLOR ret = defaultvalue;
215 if (ConvertStrToColor(value, &ret) == 0)
216 return ret;
217 else
218 return defaultvalue;
219}
220
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600221COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
222{
223 bool found_color = false;
224 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
225}
226
thatf6ed8fc2015-02-14 20:23:16 +0100227FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
228{
229 std::string name = LoadAttrString(element, attrname, "");
230 if (name.empty())
231 return NULL;
232 else
that74ac6062015-03-04 22:39:34 +0100233 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100234}
235
236ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
237{
238 std::string name = LoadAttrString(element, attrname, "");
239 if (name.empty())
240 return NULL;
241 else
that74ac6062015-03-04 22:39:34 +0100242 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100243}
244
245AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
246{
247 std::string name = LoadAttrString(element, attrname, "");
248 if (name.empty())
249 return NULL;
250 else
that74ac6062015-03-04 22:39:34 +0100251 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100252}
253
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500254bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400255{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200256 if (!node)
257 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400258
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200259 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100260 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400261
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200262 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100263 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400264
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200265 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100266 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400267
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200268 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100269 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400270
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200271 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500272 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400273
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200274 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400275}
276
277int ActionObject::SetActionPos(int x, int y, int w, int h)
278{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200279 if (x < 0 || y < 0)
280 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400281
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500282 mActionX = x;
283 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200284 if (w || h)
285 {
286 mActionW = w;
287 mActionH = h;
288 }
289 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400290}
291
thatb63e2f92015-06-27 21:35:11 +0200292Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400293{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200294 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400295
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200296 // We can memset the whole structure, because the alpha channel is ignored
297 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400298
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200299 // With NULL, we make a console-only display
300 if (!page)
301 {
302 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400303
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200304 GUIConsole* element = new GUIConsole(NULL);
305 mRenders.push_back(element);
306 mActions.push_back(element);
307 return;
308 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400309
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200310 if (page->first_attribute("name"))
311 mName = page->first_attribute("name")->value();
312 else
313 {
314 LOGERR("No page name attribute found!\n");
315 return;
316 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400317
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200318 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400319
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200320 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200321 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400322}
323
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100324Page::~Page()
325{
326 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
327 delete *itr;
328}
329
thatb63e2f92015-06-27 21:35:11 +0200330bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400331{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200332 if (depth == 10)
333 {
334 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
335 return false;
336 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400337
thatb63e2f92015-06-27 21:35:11 +0200338 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200339 {
thatb63e2f92015-06-27 21:35:11 +0200340 std::string type = child->name();
341
342 if (type == "background") {
343 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
344 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400346
thatb63e2f92015-06-27 21:35:11 +0200347 if (type == "object") {
348 // legacy format : <object type="...">
349 xml_attribute<>* attr = child->first_attribute("type");
350 type = attr ? attr->value() : "*unspecified*";
351 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400352
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200353 if (type == "text")
354 {
355 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100356 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200357 mRenders.push_back(element);
358 mActions.push_back(element);
359 }
360 else if (type == "image")
361 {
362 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100363 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200364 mRenders.push_back(element);
365 }
366 else if (type == "fill")
367 {
368 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100369 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200370 mRenders.push_back(element);
371 }
372 else if (type == "action")
373 {
374 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100375 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200376 mActions.push_back(element);
377 }
378 else if (type == "console")
379 {
380 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100381 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200382 mRenders.push_back(element);
383 mActions.push_back(element);
384 }
that1964d192016-01-07 00:41:03 +0100385 else if (type == "terminal")
386 {
387 GUITerminal* element = new GUITerminal(child);
388 mObjects.push_back(element);
389 mRenders.push_back(element);
390 mActions.push_back(element);
391 mInputs.push_back(element);
392 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200393 else if (type == "button")
394 {
395 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100396 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200397 mRenders.push_back(element);
398 mActions.push_back(element);
399 }
400 else if (type == "checkbox")
401 {
402 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100403 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200404 mRenders.push_back(element);
405 mActions.push_back(element);
406 }
407 else if (type == "fileselector")
408 {
409 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100410 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200411 mRenders.push_back(element);
412 mActions.push_back(element);
413 }
414 else if (type == "animation")
415 {
416 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100417 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200418 mRenders.push_back(element);
419 }
420 else if (type == "progressbar")
421 {
422 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100423 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200424 mRenders.push_back(element);
425 mActions.push_back(element);
426 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400427 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200428 {
429 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100430 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200431 mRenders.push_back(element);
432 mActions.push_back(element);
433 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200434 else if (type == "slidervalue")
435 {
436 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100437 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200438 mRenders.push_back(element);
439 mActions.push_back(element);
440 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400441 else if (type == "listbox")
442 {
443 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100444 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400445 mRenders.push_back(element);
446 mActions.push_back(element);
447 }
448 else if (type == "keyboard")
449 {
450 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100451 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400452 mRenders.push_back(element);
453 mActions.push_back(element);
454 }
455 else if (type == "input")
456 {
457 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100458 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400459 mRenders.push_back(element);
460 mActions.push_back(element);
461 mInputs.push_back(element);
462 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500463 else if (type == "partitionlist")
464 {
465 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100466 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500467 mRenders.push_back(element);
468 mActions.push_back(element);
469 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100470 else if (type == "patternpassword")
471 {
472 GUIPatternPassword* element = new GUIPatternPassword(child);
473 mObjects.push_back(element);
474 mRenders.push_back(element);
475 mActions.push_back(element);
476 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500477 else if (type == "textbox")
478 {
479 GUITextBox* element = new GUITextBox(child);
480 mObjects.push_back(element);
481 mRenders.push_back(element);
482 mActions.push_back(element);
483 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200484 else if (type == "template")
485 {
486 if (!templates || !child->first_attribute("name"))
487 {
488 LOGERR("Invalid template request.\n");
489 }
490 else
491 {
492 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500493 xml_node<>* node;
494 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400495
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200496 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500497 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
498 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400499
Ethan Yonker780cd392014-07-21 15:24:39 -0500500 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200501 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500502 if (!node->first_attribute("name"))
503 continue;
504
505 if (name == node->first_attribute("name")->value())
506 {
507 if (!ProcessNode(node, templates, depth + 1))
508 return false;
509 else {
510 node_found = true;
511 break;
512 }
513 }
514 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500516 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 }
thatb63e2f92015-06-27 21:35:11 +0200518 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200519 }
520 }
521 }
522 else
523 {
thatb63e2f92015-06-27 21:35:11 +0200524 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200525 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200526 }
527 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400528}
529
530int Page::Render(void)
531{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200532 // Render background
533 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
534 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400535
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200536 // Render remaining objects
537 std::vector<RenderObject*>::iterator iter;
538 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
539 {
540 if ((*iter)->Render())
541 LOGERR("A render request has failed.\n");
542 }
543 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400544}
545
546int Page::Update(void)
547{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200548 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400549
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 std::vector<RenderObject*>::iterator iter;
551 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
552 {
553 int ret = (*iter)->Update();
554 if (ret < 0)
555 LOGERR("An update request has failed.\n");
556 else if (ret > retCode)
557 retCode = ret;
558 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400559
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200560 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400561}
562
563int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
564{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200565 // By default, return 1 to ignore further touches if nobody is listening
566 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400567
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200568 // Don't try to handle a lack of handlers
569 if (mActions.size() == 0)
570 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400571
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200572 // We record mTouchStart so we can pass all the touch stream to the same handler
573 if (state == TOUCH_START)
574 {
575 std::vector<ActionObject*>::reverse_iterator iter;
576 // We work backwards, from top-most element to bottom-most element
577 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
578 {
579 if ((*iter)->IsInRegion(x, y))
580 {
581 mTouchStart = (*iter);
582 ret = mTouchStart->NotifyTouch(state, x, y);
583 if (ret >= 0)
584 break;
585 mTouchStart = NULL;
586 }
587 }
588 }
589 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
590 {
591 ret = mTouchStart->NotifyTouch(state, x, y);
592 mTouchStart = NULL;
593 }
594 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
595 {
596 ret = mTouchStart->NotifyTouch(state, x, y);
597 }
598 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400599}
600
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100601int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400602{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200603 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400604
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100605 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200606 // We work backwards, from top-most element to bottom-most element
607 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
608 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100609 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100610 if (ret == 0)
611 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100612 if (ret < 0) {
613 LOGERR("An action handler has returned an error\n");
614 ret = 1;
615 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200616 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100617 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400618}
619
that8834a0f2016-01-05 23:29:30 +0100620int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400621{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200622 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400623
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200624 // We work backwards, from top-most element to bottom-most element
625 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
626 {
that8834a0f2016-01-05 23:29:30 +0100627 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200628 if (ret == 0)
629 return 0;
630 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100631 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200632 }
633 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400634}
635
636int Page::SetKeyBoardFocus(int inFocus)
637{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200638 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400639
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200640 // We work backwards, from top-most element to bottom-most element
641 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
642 {
643 int ret = (*iter)->SetInputFocus(inFocus);
644 if (ret == 0)
645 return 0;
646 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100647 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200648 }
649 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400650}
651
652void Page::SetPageFocus(int inFocus)
653{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200654 // Render remaining objects
655 std::vector<RenderObject*>::iterator iter;
656 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
657 (*iter)->SetPageFocus(inFocus);
658
659 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400660}
661
662int Page::NotifyVarChange(std::string varName, std::string value)
663{
Vojtech Bocek07220562014-02-08 02:05:33 +0100664 std::vector<GUIObject*>::iterator iter;
665 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200666 {
667 if ((*iter)->NotifyVarChange(varName, value))
668 LOGERR("An action handler errored on NotifyVarChange.\n");
669 }
670 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400671}
672
that6a894592016-03-13 17:51:28 +0100673
674// transient data for loading themes
675struct LoadingContext
676{
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500677 ZipWrap* zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100678 std::set<std::string> filenames; // to detect cyclic includes
679 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
680 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
681 std::vector<char*> xmlbuffers; // text buffers with xml content
682 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
683 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
684
685 LoadingContext()
686 {
687 zip = NULL;
688 }
689
690 ~LoadingContext()
691 {
692 // free all xml buffers
693 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
694 free(*it);
695 }
696
697};
698
699// for FindStyle
700LoadingContext* PageManager::currentLoadingContext = NULL;
701
702
703PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400704{
that74ac6062015-03-04 22:39:34 +0100705 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200706 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400707
that6a894592016-03-13 17:51:28 +0100708 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400709}
710
711PageSet::~PageSet()
712{
Ethan Yonker1c273312015-03-16 12:18:56 -0500713 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100714 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
715 delete *itr;
716
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200717 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400718}
719
that6a894592016-03-13 17:51:28 +0100720int PageSet::Load(LoadingContext& ctx, const std::string& filename)
721{
722 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
723
724 if (!ctx.filenames.insert(filename).second)
725 // ignore already loaded files to prevent crash with cyclic includes
726 return 0;
727
728 // load XML into buffer
729 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
730 if (!xmlbuffer)
731 return -1; // error already displayed by LoadFileToBuffer
732 ctx.xmlbuffers.push_back(xmlbuffer);
733
734 // parse XML
735 xml_document<>* doc = new xml_document<>();
736 doc->parse<0>(xmlbuffer);
737 ctx.xmldocs.push_back(doc);
738
739 xml_node<>* root = doc->first_node("recovery");
740 if (!root)
741 root = doc->first_node("install");
742 if (!root) {
743 LOGERR("Unknown root element in %s\n", filename.c_str());
744 return -1;
745 }
746
747 if (isMain) {
748 int rc = LoadDetails(ctx, root);
749 if (rc != 0)
750 return rc;
751 }
752
753 LOGINFO("Loading resources...\n");
754 xml_node<>* child = root->first_node("resources");
755 if (child)
756 mResources->LoadResources(child, ctx.zip, "theme");
757
758 LOGINFO("Loading variables...\n");
759 child = root->first_node("variables");
760 if (child)
761 LoadVariables(child);
762
763 LOGINFO("Loading mouse cursor...\n");
764 child = root->first_node("mousecursor");
765 if (child)
766 PageManager::LoadCursorData(child);
767
768 LOGINFO("Loading pages...\n");
769 child = root->first_node("templates");
770 if (child)
771 ctx.templates.push_back(child);
772
773 child = root->first_node("styles");
774 if (child)
775 ctx.styles.push_back(child);
776
777 // Load pages
778 child = root->first_node("pages");
779 if (child) {
780 if (LoadPages(ctx, child)) {
781 LOGERR("PageSet::Load returning -1\n");
782 return -1;
783 }
784 }
785
786 // process includes recursively
787 child = root->first_node("include");
788 if (child) {
789 xml_node<>* include = child->first_node("xmlfile");
790 while (include != NULL) {
791 xml_attribute<>* attr = include->first_attribute("name");
792 if (!attr) {
793 LOGERR("Skipping include/xmlfile with no name\n");
794 continue;
795 }
796
797 string filename = ctx.basepath + attr->value();
798 LOGINFO("Including file: %s...\n", filename.c_str());
799 int rc = Load(ctx, filename);
800 if (rc != 0)
801 return rc;
802
803 include = include->next_sibling("xmlfile");
804 }
805 }
806
807 return 0;
808}
809
810void PageSet::MakeEmergencyConsoleIfNeeded()
811{
812 if (mPages.empty()) {
813 mCurrentPage = new Page(NULL, NULL); // fallback console page
814 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
815 mPages.push_back(mCurrentPage);
816 }
817}
818
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500819int PageSet::LoadLanguage(char* languageFile, ZipWrap* package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500820{
821 xml_document<> lang;
822 xml_node<>* parent;
823 xml_node<>* child;
824 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600825 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500826
827 if (languageFile) {
828 printf("parsing languageFile\n");
829 lang.parse<0>(languageFile);
830 printf("parsing languageFile done\n");
831 } else {
832 return -1;
833 }
834
835 parent = lang.first_node("language");
836 if (!parent) {
837 LOGERR("Unable to locate language node in language file.\n");
838 lang.clear();
839 return -1;
840 }
841
842 child = parent->first_node("display");
843 if (child) {
844 DataManager::SetValue("tw_language_display", child->value());
845 resource_source = child->value();
846 } else {
847 LOGERR("language file does not have a display value set\n");
848 DataManager::SetValue("tw_language_display", "Not Set");
849 resource_source = languageFile;
850 }
851
852 child = parent->first_node("resources");
853 if (child)
854 mResources->LoadResources(child, package, resource_source);
855 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600856 ret = -1;
857 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500858 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600859 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500860}
861
that6a894592016-03-13 17:51:28 +0100862int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400863{
that6a894592016-03-13 17:51:28 +0100864 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600865 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600866 int theme_ver = 0;
867 xml_node<>* themeversion = child->first_node("themeversion");
868 if (themeversion && themeversion->value()) {
869 theme_ver = atoi(themeversion->value());
870 } else {
871 LOGINFO("No themeversion in theme.\n");
872 }
873 if (theme_ver != TW_THEME_VERSION) {
874 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100875 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600876 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600877 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600878 } else {
879 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
880 }
881 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600882 xml_node<>* resolution = child->first_node("resolution");
883 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600884 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600885 xml_attribute<>* width_attr = resolution->first_attribute("width");
886 xml_attribute<>* height_attr = resolution->first_attribute("height");
887 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
888 if (width_attr && height_attr && !noscale_attr) {
889 int width = atoi(width_attr->value());
890 int height = atoi(height_attr->value());
891 int offx = 0, offy = 0;
892#ifdef TW_ROUND_SCREEN
893 xml_node<>* roundscreen = child->first_node("roundscreen");
894 if (roundscreen) {
895 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
896 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
897 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
898 if (offx_attr) {
899 offx = atoi(offx_attr->value());
900 }
901 if (offy_attr) {
902 offy = atoi(offy_attr->value());
903 }
904 }
905#endif
906 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500907 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
908 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600909#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500910 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
911 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600912 tw_x_offset = offx * scale_off_w;
913 tw_y_offset = offy * scale_off_h;
914#endif
915 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500916 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
917 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600918 set_scale_values(scale_w, scale_h);
919 }
920 }
921 } else {
922 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
923 }
924 } else {
925 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
926 }
927 } else {
928 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
929 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500930
Ethan Yonker780cd392014-07-21 15:24:39 -0500931 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400932}
933
934int PageSet::SetPage(std::string page)
935{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200936 Page* tmp = FindPage(page);
937 if (tmp)
938 {
939 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
940 mCurrentPage = tmp;
941 mCurrentPage->SetPageFocus(1);
942 mCurrentPage->NotifyVarChange("", "");
943 return 0;
944 }
945 else
946 {
947 LOGERR("Unable to locate page (%s)\n", page.c_str());
948 }
949 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400950}
951
952int PageSet::SetOverlay(Page* page)
953{
Ethan Yonker1c273312015-03-16 12:18:56 -0500954 if (page) {
955 if (mOverlays.size() >= 10) {
956 LOGERR("Too many overlays requested, max is 10.\n");
957 return -1;
958 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500959
960 std::vector<Page*>::iterator iter;
961 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
962 if ((*iter)->GetName() == page->GetName()) {
963 mOverlays.erase(iter);
964 // SetOverlay() is (and should stay) the only function which
965 // adds to mOverlays. Then, each page can appear at most once.
966 break;
967 }
968 }
969
Ethan Yonker1c273312015-03-16 12:18:56 -0500970 page->SetPageFocus(1);
971 page->NotifyVarChange("", "");
972
973 if (!mOverlays.empty())
974 mOverlays.back()->SetPageFocus(0);
975
976 mOverlays.push_back(page);
977 } else {
978 if (!mOverlays.empty()) {
979 mOverlays.back()->SetPageFocus(0);
980 mOverlays.pop_back();
981 if (!mOverlays.empty())
982 mOverlays.back()->SetPageFocus(1);
983 else if (mCurrentPage)
984 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
985 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200986 }
987 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400988}
989
that74ac6062015-03-04 22:39:34 +0100990const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400991{
that74ac6062015-03-04 22:39:34 +0100992 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400993}
994
995Page* PageSet::FindPage(std::string name)
996{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200997 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400998
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200999 for (iter = mPages.begin(); iter != mPages.end(); iter++)
1000 {
1001 if (name == (*iter)->GetName())
1002 return (*iter);
1003 }
1004 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001005}
1006
1007int PageSet::LoadVariables(xml_node<>* vars)
1008{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001009 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001010 xml_attribute<> *name, *value, *persist;
1011 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001012
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001013 child = vars->first_node("variable");
1014 while (child)
1015 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001016 name = child->first_attribute("name");
1017 value = child->first_attribute("value");
1018 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001019 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001020 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001021 if (strcmp(name->value(), "tw_x_offset") == 0) {
1022 tw_x_offset = atoi(value->value());
1023 child = child->next_sibling("variable");
1024 continue;
1025 }
1026 if (strcmp(name->value(), "tw_y_offset") == 0) {
1027 tw_y_offset = atoi(value->value());
1028 child = child->next_sibling("variable");
1029 continue;
1030 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001031 if (strcmp(name->value(), "tw_w_offset") == 0) {
1032 tw_w_offset = atoi(value->value());
1033 child = child->next_sibling("variable");
1034 continue;
1035 }
1036 if (strcmp(name->value(), "tw_h_offset") == 0) {
1037 tw_h_offset = atoi(value->value());
1038 child = child->next_sibling("variable");
1039 continue;
1040 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001041 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001042 string temp = value->value();
1043 string valstr = gui_parse_text(temp);
1044
1045 if (valstr.find("+") != string::npos) {
1046 string val1str = valstr;
1047 val1str = val1str.substr(0, val1str.find('+'));
1048 string val2str = valstr;
1049 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1050 int val1 = atoi(val1str.c_str());
1051 int val2 = atoi(val2str.c_str());
1052 int val = val1 + val2;
1053
1054 DataManager::SetValue(name->value(), val, p);
1055 } else if (valstr.find("-") != string::npos) {
1056 string val1str = valstr;
1057 val1str = val1str.substr(0, val1str.find('-'));
1058 string val2str = valstr;
1059 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1060 int val1 = atoi(val1str.c_str());
1061 int val2 = atoi(val2str.c_str());
1062 int val = val1 - val2;
1063
1064 DataManager::SetValue(name->value(), val, p);
1065 } else {
1066 DataManager::SetValue(name->value(), valstr, p);
1067 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001068 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001069
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001070 child = child->next_sibling("variable");
1071 }
1072 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001073}
1074
that6a894592016-03-13 17:51:28 +01001075int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001076{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001077 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001078
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001079 if (!pages)
1080 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001081
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001082 child = pages->first_node("page");
1083 while (child != NULL)
1084 {
that6a894592016-03-13 17:51:28 +01001085 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001086 if (page->GetName().empty())
1087 {
1088 LOGERR("Unable to process load page\n");
1089 delete page;
1090 }
1091 else
1092 {
1093 mPages.push_back(page);
1094 }
1095 child = child->next_sibling("page");
1096 }
1097 if (mPages.size() > 0)
1098 return 0;
1099 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001100}
1101
1102int PageSet::IsCurrentPage(Page* page)
1103{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001104 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001105}
1106
that10ae24f2015-12-26 20:53:51 +01001107std::string PageSet::GetCurrentPage() const
1108{
1109 return mCurrentPage ? mCurrentPage->GetName() : "";
1110}
1111
Dees_Troy51a0e822012-09-05 15:24:24 -04001112int PageSet::Render(void)
1113{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001114 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001115
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001116 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1117 if (ret < 0)
1118 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001119
1120 std::vector<Page*>::iterator iter;
1121
1122 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1123 ret = ((*iter) ? (*iter)->Render() : -1);
1124 if (ret < 0)
1125 return ret;
1126 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001127 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001128}
1129
1130int PageSet::Update(void)
1131{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001132 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001133
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001134 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1135 if (ret < 0 || ret > 1)
1136 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001137
1138 std::vector<Page*>::iterator iter;
1139
1140 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1141 ret = ((*iter) ? (*iter)->Update() : -1);
1142 if (ret < 0)
1143 return ret;
1144 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001145 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001146}
1147
1148int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1149{
Ethan Yonker1c273312015-03-16 12:18:56 -05001150 if (!mOverlays.empty())
1151 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001152
1153 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001154}
1155
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001156int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001157{
Ethan Yonker1c273312015-03-16 12:18:56 -05001158 if (!mOverlays.empty())
1159 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001160
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001161 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001162}
1163
that8834a0f2016-01-05 23:29:30 +01001164int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001165{
Ethan Yonker1c273312015-03-16 12:18:56 -05001166 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001167 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001168
that8834a0f2016-01-05 23:29:30 +01001169 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001170}
1171
1172int PageSet::SetKeyBoardFocus(int inFocus)
1173{
Ethan Yonker1c273312015-03-16 12:18:56 -05001174 if (!mOverlays.empty())
1175 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001176
1177 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001178}
1179
1180int PageSet::NotifyVarChange(std::string varName, std::string value)
1181{
Ethan Yonker1c273312015-03-16 12:18:56 -05001182 std::vector<Page*>::iterator iter;
1183
1184 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1185 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001186
1187 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001188}
1189
Ethan Yonker74db1572015-10-28 12:44:49 -05001190void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1191{
1192 mResources->AddStringResource(resource_source, resource_name, value);
1193}
1194
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001195char* PageManager::LoadFileToBuffer(std::string filename, ZipWrap* package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001196 size_t len;
1197 char* buffer = NULL;
1198
1199 if (!package) {
1200 // We can try to load the XML directly...
1201 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1202 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001203 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001204 // This isn't always an error, sometimes we request files that don't exist.
1205 return NULL;
1206 }
1207
1208 len = (size_t)st.st_size;
1209
1210 buffer = (char*) malloc(len + 1);
1211 if (!buffer) {
1212 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1213 return NULL;
1214 }
1215
1216 int fd = open(filename.c_str(), O_RDONLY);
1217 if (fd == -1) {
1218 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1219 free(buffer);
1220 return NULL;
1221 }
1222
1223 if (read(fd, buffer, len) < 0) {
1224 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1225 free(buffer);
1226 close(fd);
1227 return NULL;
1228 }
1229 close(fd);
1230 } else {
1231 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001232 if (!package->EntryExists(filename)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001233 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1234 return NULL;
1235 }
1236
1237 // Allocate the buffer for the file
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001238 len = package->GetUncompressedSize(filename);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001239 buffer = (char*) malloc(len + 1);
1240 if (!buffer)
1241 return NULL;
1242
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001243 if (!package->ExtractToBuffer(filename, (unsigned char*) buffer)) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001244 LOGERR("Unable to extract '%s'\n", filename.c_str());
1245 free(buffer);
1246 return NULL;
1247 }
1248 }
1249 // NULL-terminate the string
1250 buffer[len] = 0x00;
1251 return buffer;
1252}
1253
Ethan Yonker74db1572015-10-28 12:44:49 -05001254void PageManager::LoadLanguageListDir(string dir) {
1255 if (!TWFunc::Path_Exists(dir)) {
1256 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1257 return;
1258 }
1259
1260 DIR *d = opendir(dir.c_str());
1261 struct dirent *p;
1262
1263 if (d == NULL) {
1264 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1265 return;
1266 }
1267
1268 while ((p = readdir(d))) {
1269 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1270 continue;
1271
1272 string file = p->d_name;
1273 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1274 continue;
1275 string path = dir + p->d_name;
1276 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1277 struct language_struct language_entry;
1278 language_entry.filename = file_no_extn;
1279 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1280 if (xmlFile == NULL) {
1281 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1282 continue;
1283 }
1284 xml_document<> *doc = new xml_document<>();
1285 doc->parse<0>(xmlFile);
1286
1287 xml_node<>* parent = doc->first_node("language");
1288 if (!parent) {
1289 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1290 } else {
1291 xml_node<>* child = parent->first_node("display");
1292 if (child) {
1293 language_entry.displayvalue = child->value();
1294 } else {
1295 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1296 language_entry.displayvalue = language_entry.filename;
1297 }
1298 Language_List.push_back(language_entry);
1299 }
1300 doc->clear();
1301 delete doc;
1302 free(xmlFile);
1303 }
1304 closedir(d);
1305}
1306
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001307void PageManager::LoadLanguageList(ZipWrap* package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001308 Language_List.clear();
1309 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1310 TWFunc::removeDir(TWRES "customlanguages", true);
1311 if (package) {
1312 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001313 package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001314 LoadLanguageListDir(TWRES "customlanguages/");
1315 } else {
1316 LoadLanguageListDir(TWRES "languages/");
1317 }
Xuefercac6ace2016-02-01 02:28:55 +08001318
1319 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001320}
1321
1322void PageManager::LoadLanguage(string filename) {
1323 string actual_filename;
1324 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1325 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1326 else
1327 actual_filename = TWRES "languages/" + filename + ".xml";
1328 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1329 if (xmlFile == NULL)
1330 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1331 else {
1332 mCurrentSet->LoadLanguage(xmlFile, NULL);
1333 free(xmlFile);
1334 }
1335 PartitionManager.Translate_Partition_Display_Names();
1336}
1337
Dees_Troy51a0e822012-09-05 15:24:24 -04001338int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1339{
that6a894592016-03-13 17:51:28 +01001340 std::string mainxmlfilename = package;
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001341 ZipWrap zip;
Ethan Yonker74db1572015-10-28 12:44:49 -05001342 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001343 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001344 PageSet* pageSet = NULL;
1345 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001346 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001347
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001348 mReloadTheme = false;
1349 mStartPage = startpage;
1350
that6a894592016-03-13 17:51:28 +01001351 // init the loading context
1352 LoadingContext ctx;
1353
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001354 // Open the XML file
1355 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001356 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001357 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001358 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001359 tw_x_offset = TW_X_OFFSET;
1360 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001361 tw_w_offset = TW_W_OFFSET;
1362 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001363 if (name != "splash") {
1364 LoadLanguageList(NULL);
1365 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1366 }
that6a894592016-03-13 17:51:28 +01001367 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001368 }
1369 else
1370 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001371 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001372 tw_x_offset = 0;
1373 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001374 tw_w_offset = 0;
1375 tw_h_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001376 if (!TWFunc::Path_Exists(package))
1377 return -1;
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001378#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001379 if (sysMapFile(package.c_str(), &map) != 0) {
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001380#else
1381 if (!map.MapFile(package)) {
1382#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001383 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001384 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001385 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001386 if (!zip.Open(package.c_str(), &map)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001387 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001388#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001389 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001390#endif
Ethan Yonker561c58d2015-10-05 08:48:22 -05001391 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001392 }
that6a894592016-03-13 17:51:28 +01001393 ctx.zip = &zip;
1394 mainxmlfilename = "ui.xml";
1395 LoadLanguageList(ctx.zip);
1396 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001397 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001398 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001399
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001400 // Before loading, mCurrentSet must be the loading package so we can find resources
1401 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001402 mCurrentSet = new PageSet();
1403
1404 if (baseLanguageFile) {
1405 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1406 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001407 }
that6a894592016-03-13 17:51:28 +01001408
1409 if (languageFile) {
1410 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1411 free(languageFile);
1412 }
1413
1414 // Load and parse the XML and all includes
1415 currentLoadingContext = &ctx; // required to find styles
1416 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1417 currentLoadingContext = NULL;
1418
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001419 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001420 mCurrentSet->SetPage(startpage);
1421 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001422 } else {
1423 if (ret != TW_THEME_VER_ERR)
1424 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001425 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001426
that6a894592016-03-13 17:51:28 +01001427 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001428 mCurrentSet = pageSet;
1429
that6a894592016-03-13 17:51:28 +01001430 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001431 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001432#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001433 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001434#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001435 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001436 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001437
1438error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001439 // Sometimes we get here without a real error
that6a894592016-03-13 17:51:28 +01001440 if (ctx.zip) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -05001441 ctx.zip->Close();
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001442#ifdef USE_MINZIP
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001443 sysReleaseMap(&map);
Ethan Yonkerecbd3e82017-12-14 14:43:59 -06001444#endif
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001445 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001446 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001447}
1448
1449PageSet* PageManager::FindPackage(std::string name)
1450{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001451 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001452
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001453 iter = mPageSets.find(name);
1454 if (iter != mPageSets.end())
1455 return (*iter).second;
1456
1457 LOGERR("Unable to locate package %s\n", name.c_str());
1458 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001459}
1460
1461PageSet* PageManager::SelectPackage(std::string name)
1462{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001463 LOGINFO("Switching packages (%s)\n", name.c_str());
1464 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001465
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001466 tmp = FindPackage(name);
1467 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001468 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001469 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001470 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001471 mCurrentSet->NotifyVarChange("", "");
1472 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001473 else
1474 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001475
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001476 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001477}
1478
1479int PageManager::ReloadPackage(std::string name, std::string package)
1480{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001481 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001482
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001483 mReloadTheme = false;
1484
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001485 iter = mPageSets.find(name);
1486 if (iter == mPageSets.end())
1487 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001488
Matt Mowera8a89d12016-12-30 18:10:37 -06001489 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001490 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1491
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001492 PageSet* set = (*iter).second;
1493 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001494
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001495 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001496 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001497 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001498 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1499 return -1;
1500 }
1501 if (mCurrentSet == set)
1502 SelectPackage(name);
1503 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001504 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001505 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001506}
1507
1508void PageManager::ReleasePackage(std::string name)
1509{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001510 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001511
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001512 iter = mPageSets.find(name);
1513 if (iter == mPageSets.end())
1514 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001515
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001516 PageSet* set = (*iter).second;
1517 mPageSets.erase(iter);
1518 delete set;
that235c6482016-01-24 21:59:00 +01001519 if (set == mCurrentSet)
1520 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001521 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001522}
1523
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001524int PageManager::RunReload() {
1525 int ret_val = 0;
1526 std::string theme_path;
1527
1528 if (!mReloadTheme)
1529 return 0;
1530
1531 mReloadTheme = false;
1532 theme_path = DataManager::GetSettingsStoragePath();
1533 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1534 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1535 ret_val = 1;
1536 }
1537
1538 theme_path += "/TWRP/theme/ui.zip";
1539 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1540 {
1541 // Loading the custom theme failed - try loading the stock theme
1542 LOGINFO("Attempting to reload stock theme...\n");
1543 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1544 {
1545 LOGERR("Failed to load base packages.\n");
1546 ret_val = 1;
1547 }
1548 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001549 if (ret_val == 0) {
1550 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1551 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1552 LoadLanguage(DataManager::GetStrValue("tw_language"));
1553 }
1554 }
1555
1556 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001557 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001558
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001559 return ret_val;
1560}
1561
1562void PageManager::RequestReload() {
1563 mReloadTheme = true;
1564}
1565
Ethan Yonkerafde0982016-01-23 08:55:35 -06001566void PageManager::SetStartPage(const std::string& page_name) {
1567 mStartPage = page_name;
1568}
1569
Dees_Troy51a0e822012-09-05 15:24:24 -04001570int PageManager::ChangePage(std::string name)
1571{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001572 DataManager::SetValue("tw_operation_state", 0);
1573 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1574 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001575}
1576
that10ae24f2015-12-26 20:53:51 +01001577std::string PageManager::GetCurrentPage()
1578{
1579 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1580}
1581
Dees_Troy51a0e822012-09-05 15:24:24 -04001582int PageManager::ChangeOverlay(std::string name)
1583{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001584 if (name.empty())
1585 return mCurrentSet->SetOverlay(NULL);
1586 else
1587 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001588 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001589 return mCurrentSet->SetOverlay(page);
1590 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001591}
1592
that74ac6062015-03-04 22:39:34 +01001593const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001594{
that74ac6062015-03-04 22:39:34 +01001595 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001596}
1597
Dees_Troy51a0e822012-09-05 15:24:24 -04001598int PageManager::IsCurrentPage(Page* page)
1599{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001600 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001601}
1602
1603int PageManager::Render(void)
1604{
Matt Mowera8a89d12016-12-30 18:10:37 -06001605 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001606 return 0;
1607
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001608 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001609 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001610 mMouseCursor->Render();
1611 return res;
1612}
1613
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001614HardwareKeyboard *PageManager::GetHardwareKeyboard()
1615{
Matt Mowera8a89d12016-12-30 18:10:37 -06001616 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001617 mHardwareKeyboard = new HardwareKeyboard();
1618 return mHardwareKeyboard;
1619}
1620
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001621xml_node<>* PageManager::FindStyle(std::string name)
1622{
that6a894592016-03-13 17:51:28 +01001623 if (!currentLoadingContext)
1624 {
1625 LOGERR("FindStyle works only while loading a theme.\n");
1626 return NULL;
1627 }
1628
1629 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001630 xml_node<>* node = (*itr)->first_node("style");
1631
1632 while (node) {
1633 if (!node->first_attribute("name"))
1634 continue;
1635
1636 if (name == node->first_attribute("name")->value())
1637 return node;
1638 node = node->next_sibling("style");
1639 }
1640 }
1641 return NULL;
1642}
1643
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001644MouseCursor *PageManager::GetMouseCursor()
1645{
Matt Mowera8a89d12016-12-30 18:10:37 -06001646 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001647 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1648 return mMouseCursor;
1649}
1650
1651void PageManager::LoadCursorData(xml_node<>* node)
1652{
Matt Mowera8a89d12016-12-30 18:10:37 -06001653 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001654 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1655
1656 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001657}
1658
1659int PageManager::Update(void)
1660{
Matt Mowera8a89d12016-12-30 18:10:37 -06001661 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001662 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001663
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001664 if (RunReload())
1665 return -2;
1666
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001667 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1668
Matt Mowera8a89d12016-12-30 18:10:37 -06001669 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001670 {
1671 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001672 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001673 res = c_res;
1674 }
1675 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001676}
1677
1678int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1679{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001680 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001681}
1682
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001683int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001684{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001685 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001686}
1687
that8834a0f2016-01-05 23:29:30 +01001688int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001689{
that8834a0f2016-01-05 23:29:30 +01001690 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001691}
1692
1693int PageManager::SetKeyBoardFocus(int inFocus)
1694{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001695 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001696}
1697
1698int PageManager::NotifyVarChange(std::string varName, std::string value)
1699{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001700 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001701}
1702
Ethan Yonker74db1572015-10-28 12:44:49 -05001703void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1704{
1705 if (mCurrentSet)
1706 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1707}
1708
Dees_Troy51a0e822012-09-05 15:24:24 -04001709extern "C" void gui_notifyVarChange(const char *name, const char* value)
1710{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001711 if (!gGuiRunning)
1712 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001713
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001714 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001715}