blob: 8b9ce464ecbc0019b4cd93aac14f4b9e648f2439 [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
bigbiff673c7ae2020-12-02 19:44:56 -050042
bigbiffd58ba182020-03-23 10:02:29 -040043#include <ziparchive/zip_archive.h>
bigbiff673c7ae2020-12-02 19:44:56 -050044#include "ZipUtil.h"
Ethan Yonker8373cfe2017-09-08 06:50:54 -050045
Dees_Troy51a0e822012-09-05 15:24:24 -040046extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000047#include "../twcommon.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060048#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040049}
bigbiffd81833a2021-01-17 11:06:57 -050050#include "minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040051
52#include "rapidxml.hpp"
53#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020054#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040055
Captain Throwback33dbec02022-01-29 12:45:35 -050056#include "../variables.h"
that74bff7f2017-01-18 22:32:36 +010057
Ethan Yonker8e5692f2016-01-21 11:21:06 -060058#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060059
Dees_Troy51a0e822012-09-05 15:24:24 -040060extern int gGuiRunning;
Mohd Faraz77bbeb02020-08-12 12:29:42 +000061GUITerminal* term = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040062
63std::map<std::string, PageSet*> PageManager::mPageSets;
64PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010065MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010066HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050067bool PageManager::mReloadTheme = false;
68std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050069std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040070
Ethan Yonker751a85e2014-12-12 16:59:10 -060071int tw_x_offset = 0;
72int tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -050073int tw_w_offset = 0;
74int tw_h_offset = 0;
Ethan Yonker751a85e2014-12-12 16:59:10 -060075
Dees_Troy51a0e822012-09-05 15:24:24 -040076// Helper routine to convert a string to a color declaration
77int ConvertStrToColor(std::string str, COLOR* color)
78{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020079 // Set the default, solid black
80 memset(color, 0, sizeof(COLOR));
81 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040082
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020083 // Translate variables
84 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050085
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020086 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010087 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020088 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
89 else if (str == "red") { color->red = 255; return 0; }
90 else if (str == "green") { color->green = 255; return 0; }
91 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040092
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020093 // At this point, we require an RGB(A) color
94 if (str[0] != '#')
95 return -1;
96
97 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040098
Dees_Troy30b962e2012-10-19 20:48:59 -040099 int result;
100 if (str.size() >= 8) {
101 // We have alpha channel
102 string alpha = str.substr(6, 2);
103 result = strtol(alpha.c_str(), NULL, 16);
104 color->alpha = result & 0x000000FF;
105 str.resize(6);
106 result = strtol(str.c_str(), NULL, 16);
107 color->red = (result >> 16) & 0x000000FF;
108 color->green = (result >> 8) & 0x000000FF;
109 color->blue = result & 0x000000FF;
110 } else {
111 result = strtol(str.c_str(), NULL, 16);
112 color->red = (result >> 16) & 0x000000FF;
113 color->green = (result >> 8) & 0x000000FF;
114 color->blue = result & 0x000000FF;
115 }
116 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400117}
118
119// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600120xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
121{
that8d46c092015-02-26 01:30:04 +0100122 if (!parent)
123 return NULL;
124
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600125 xml_node<>* child = parent->first_node(nodename);
126 if (child)
127 return child;
128
129 if (depth == 10) {
130 LOGERR("Too many style loops detected.\n");
131 return NULL;
132 }
133
134 xml_node<>* style = parent->first_node("style");
135 if (style) {
136 while (style) {
137 if (!style->first_attribute("name")) {
138 LOGERR("No name given for style.\n");
139 continue;
140 } else {
141 std::string name = style->first_attribute("name")->value();
142 xml_node<>* node = PageManager::FindStyle(name);
143
144 if (node) {
145 // We found the style that was named
146 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
147 if (stylenode)
148 return stylenode;
149 }
150 }
151 style = style->next_sibling("style");
152 }
153 } else {
that54e9c832015-11-04 21:46:01 +0100154 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600155 xml_attribute<>* attr = parent->first_attribute("style");
156 // If no style is found anywhere else and the node wasn't found in the object itself
157 // as a special case we will search for a style that uses the same style name as the
158 // object type, so <object type="button"> would search for a style named "button"
159 if (!attr)
160 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100161 // if there's no attribute type, the object type must be the element name
162 std::string stylename = attr ? attr->value() : parent->name();
163 xml_node<>* node = PageManager::FindStyle(stylename);
164 if (node) {
165 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
166 if (stylenode)
167 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600168 }
169 }
170 return NULL;
171}
172
thatf6ed8fc2015-02-14 20:23:16 +0100173std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
174{
175 if (!element)
176 return defaultvalue;
177
178 xml_attribute<>* attr = element->first_attribute(attrname);
179 return attr ? attr->value() : defaultvalue;
180}
181
182int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
183{
184 string value = LoadAttrString(element, attrname);
185 // resolve variables
186 DataManager::GetValue(value, value);
187 return value.empty() ? defaultvalue : atoi(value.c_str());
188}
189
190int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
191{
192 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
193}
194
195int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
196{
197 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
198}
199
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600200COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100201{
202 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600203 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100204 // resolve variables
205 DataManager::GetValue(value, value);
206 COLOR ret = defaultvalue;
207 if (ConvertStrToColor(value, &ret) == 0)
208 return ret;
209 else
210 return defaultvalue;
211}
212
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600213COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
214{
215 bool found_color = false;
216 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
217}
218
thatf6ed8fc2015-02-14 20:23:16 +0100219FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
220{
221 std::string name = LoadAttrString(element, attrname, "");
222 if (name.empty())
223 return NULL;
224 else
that74ac6062015-03-04 22:39:34 +0100225 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100226}
227
228ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
229{
230 std::string name = LoadAttrString(element, attrname, "");
231 if (name.empty())
232 return NULL;
233 else
that74ac6062015-03-04 22:39:34 +0100234 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100235}
236
237AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
238{
239 std::string name = LoadAttrString(element, attrname, "");
240 if (name.empty())
241 return NULL;
242 else
that74ac6062015-03-04 22:39:34 +0100243 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100244}
245
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500246bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400247{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200248 if (!node)
249 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400250
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200251 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100252 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400253
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200254 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100255 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400256
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100258 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400259
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200260 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100261 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400262
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200263 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500264 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400265
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200266 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400267}
268
269int ActionObject::SetActionPos(int x, int y, int w, int h)
270{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200271 if (x < 0 || y < 0)
272 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400273
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500274 mActionX = x;
275 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200276 if (w || h)
277 {
278 mActionW = w;
279 mActionH = h;
280 }
281 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400282}
283
thatb63e2f92015-06-27 21:35:11 +0200284Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400285{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200286 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400287
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200288 // We can memset the whole structure, because the alpha channel is ignored
289 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400290
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200291 // With NULL, we make a console-only display
292 if (!page)
293 {
294 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400295
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200296 GUIConsole* element = new GUIConsole(NULL);
297 mRenders.push_back(element);
298 mActions.push_back(element);
299 return;
300 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400301
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200302 if (page->first_attribute("name"))
303 mName = page->first_attribute("name")->value();
304 else
305 {
306 LOGERR("No page name attribute found!\n");
307 return;
308 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400309
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200310 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400311
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200312 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200313 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400314}
315
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100316Page::~Page()
317{
318 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
319 delete *itr;
320}
321
thatb63e2f92015-06-27 21:35:11 +0200322bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400323{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200324 if (depth == 10)
325 {
326 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
327 return false;
328 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400329
thatb63e2f92015-06-27 21:35:11 +0200330 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200331 {
thatb63e2f92015-06-27 21:35:11 +0200332 std::string type = child->name();
333
334 if (type == "background") {
335 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
336 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200337 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400338
thatb63e2f92015-06-27 21:35:11 +0200339 if (type == "object") {
340 // legacy format : <object type="...">
341 xml_attribute<>* attr = child->first_attribute("type");
342 type = attr ? attr->value() : "*unspecified*";
343 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400344
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 if (type == "text")
346 {
347 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100348 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 mRenders.push_back(element);
350 mActions.push_back(element);
351 }
352 else if (type == "image")
353 {
354 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100355 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200356 mRenders.push_back(element);
357 }
358 else if (type == "fill")
359 {
360 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100361 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200362 mRenders.push_back(element);
363 }
364 else if (type == "action")
365 {
366 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100367 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200368 mActions.push_back(element);
369 }
370 else if (type == "console")
371 {
372 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100373 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200374 mRenders.push_back(element);
375 mActions.push_back(element);
376 }
that1964d192016-01-07 00:41:03 +0100377 else if (type == "terminal")
378 {
379 GUITerminal* element = new GUITerminal(child);
380 mObjects.push_back(element);
381 mRenders.push_back(element);
382 mActions.push_back(element);
383 mInputs.push_back(element);
Mohd Faraz77bbeb02020-08-12 12:29:42 +0000384 term = element;
that1964d192016-01-07 00:41:03 +0100385 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200386 else if (type == "button")
387 {
388 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100389 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200390 mRenders.push_back(element);
391 mActions.push_back(element);
392 }
393 else if (type == "checkbox")
394 {
395 GUICheckbox* element = new GUICheckbox(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 == "fileselector")
401 {
402 GUIFileSelector* element = new GUIFileSelector(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 == "animation")
408 {
409 GUIAnimation* element = new GUIAnimation(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 }
413 else if (type == "progressbar")
414 {
415 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100416 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200417 mRenders.push_back(element);
418 mActions.push_back(element);
419 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400420 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200421 {
422 GUISlider* element = new GUISlider(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 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200427 else if (type == "slidervalue")
428 {
429 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100430 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200431 mRenders.push_back(element);
432 mActions.push_back(element);
433 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400434 else if (type == "listbox")
435 {
436 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100437 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400438 mRenders.push_back(element);
439 mActions.push_back(element);
440 }
441 else if (type == "keyboard")
442 {
443 GUIKeyboard* element = new GUIKeyboard(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 == "input")
449 {
450 GUIInput* element = new GUIInput(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 mInputs.push_back(element);
455 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500456 else if (type == "partitionlist")
457 {
458 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100459 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500460 mRenders.push_back(element);
461 mActions.push_back(element);
462 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100463 else if (type == "patternpassword")
464 {
465 GUIPatternPassword* element = new GUIPatternPassword(child);
466 mObjects.push_back(element);
467 mRenders.push_back(element);
468 mActions.push_back(element);
469 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500470 else if (type == "textbox")
471 {
472 GUITextBox* element = new GUITextBox(child);
473 mObjects.push_back(element);
474 mRenders.push_back(element);
475 mActions.push_back(element);
476 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200477 else if (type == "template")
478 {
479 if (!templates || !child->first_attribute("name"))
480 {
481 LOGERR("Invalid template request.\n");
482 }
483 else
484 {
485 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500486 xml_node<>* node;
487 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400488
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200489 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500490 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
491 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400492
Ethan Yonker780cd392014-07-21 15:24:39 -0500493 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200494 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500495 if (!node->first_attribute("name"))
496 continue;
497
498 if (name == node->first_attribute("name")->value())
499 {
500 if (!ProcessNode(node, templates, depth + 1))
501 return false;
502 else {
503 node_found = true;
504 break;
505 }
506 }
507 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200508 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500509 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200510 }
thatb63e2f92015-06-27 21:35:11 +0200511 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200512 }
513 }
514 }
515 else
516 {
thatb63e2f92015-06-27 21:35:11 +0200517 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200518 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200519 }
520 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400521}
522
523int Page::Render(void)
524{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200525 // Render background
526 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
527 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400528
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200529 // Render remaining objects
530 std::vector<RenderObject*>::iterator iter;
531 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
532 {
533 if ((*iter)->Render())
534 LOGERR("A render request has failed.\n");
535 }
536 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400537}
538
539int Page::Update(void)
540{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200541 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400542
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200543 std::vector<RenderObject*>::iterator iter;
544 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
545 {
546 int ret = (*iter)->Update();
547 if (ret < 0)
548 LOGERR("An update request has failed.\n");
549 else if (ret > retCode)
550 retCode = ret;
551 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400552
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200553 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400554}
555
556int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
557{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200558 // By default, return 1 to ignore further touches if nobody is listening
559 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400560
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200561 // Don't try to handle a lack of handlers
562 if (mActions.size() == 0)
563 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400564
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200565 // We record mTouchStart so we can pass all the touch stream to the same handler
566 if (state == TOUCH_START)
567 {
568 std::vector<ActionObject*>::reverse_iterator iter;
569 // We work backwards, from top-most element to bottom-most element
570 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
571 {
572 if ((*iter)->IsInRegion(x, y))
573 {
574 mTouchStart = (*iter);
575 ret = mTouchStart->NotifyTouch(state, x, y);
576 if (ret >= 0)
577 break;
578 mTouchStart = NULL;
579 }
580 }
581 }
582 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
583 {
584 ret = mTouchStart->NotifyTouch(state, x, y);
585 mTouchStart = NULL;
586 }
587 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
588 {
589 ret = mTouchStart->NotifyTouch(state, x, y);
590 }
591 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400592}
593
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100594int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400595{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400597
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100598 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200599 // We work backwards, from top-most element to bottom-most element
600 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
601 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100602 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100603 if (ret == 0)
604 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100605 if (ret < 0) {
606 LOGERR("An action handler has returned an error\n");
607 ret = 1;
608 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200609 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100610 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400611}
612
that8834a0f2016-01-05 23:29:30 +0100613int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400614{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400616
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200617 // We work backwards, from top-most element to bottom-most element
618 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
619 {
that8834a0f2016-01-05 23:29:30 +0100620 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200621 if (ret == 0)
622 return 0;
623 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100624 LOGERR("A char input handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200625 }
626 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400627}
628
629int Page::SetKeyBoardFocus(int inFocus)
630{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400632
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200633 // We work backwards, from top-most element to bottom-most element
634 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
635 {
636 int ret = (*iter)->SetInputFocus(inFocus);
637 if (ret == 0)
638 return 0;
639 else if (ret < 0)
that6a894592016-03-13 17:51:28 +0100640 LOGERR("An input focus handler has returned an error\n");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200641 }
642 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400643}
644
645void Page::SetPageFocus(int inFocus)
646{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200647 // Render remaining objects
648 std::vector<RenderObject*>::iterator iter;
649 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
650 (*iter)->SetPageFocus(inFocus);
651
652 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400653}
654
655int Page::NotifyVarChange(std::string varName, std::string value)
656{
Vojtech Bocek07220562014-02-08 02:05:33 +0100657 std::vector<GUIObject*>::iterator iter;
658 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200659 {
660 if ((*iter)->NotifyVarChange(varName, value))
661 LOGERR("An action handler errored on NotifyVarChange.\n");
662 }
663 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400664}
665
that6a894592016-03-13 17:51:28 +0100666
667// transient data for loading themes
668struct LoadingContext
669{
bigbiff673c7ae2020-12-02 19:44:56 -0500670 ZipArchiveHandle zip; // zip to load theme from, or NULL for the stock theme
that6a894592016-03-13 17:51:28 +0100671 std::set<std::string> filenames; // to detect cyclic includes
672 std::string basepath; // if zip is NULL, base path to load includes from with trailing slash, otherwise empty
673 std::vector<xml_document<>*> xmldocs; // all loaded xml docs
674 std::vector<char*> xmlbuffers; // text buffers with xml content
675 std::vector<xml_node<>*> styles; // refer to <styles> nodes inside xmldocs
676 std::vector<xml_node<>*> templates; // refer to <templates> nodes inside xmldocs
677
678 LoadingContext()
679 {
680 zip = NULL;
681 }
682
683 ~LoadingContext()
684 {
685 // free all xml buffers
686 for (std::vector<char*>::iterator it = xmlbuffers.begin(); it != xmlbuffers.end(); ++it)
687 free(*it);
688 }
689
690};
691
692// for FindStyle
693LoadingContext* PageManager::currentLoadingContext = NULL;
694
695
696PageSet::PageSet()
Dees_Troy51a0e822012-09-05 15:24:24 -0400697{
that74ac6062015-03-04 22:39:34 +0100698 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200699 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400700
that6a894592016-03-13 17:51:28 +0100701 set_scale_values(1, 1); // Reset any previous scaling values
Dees_Troy51a0e822012-09-05 15:24:24 -0400702}
703
704PageSet::~PageSet()
705{
Ethan Yonker1c273312015-03-16 12:18:56 -0500706 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100707 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
708 delete *itr;
709
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200710 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400711}
712
that6a894592016-03-13 17:51:28 +0100713int PageSet::Load(LoadingContext& ctx, const std::string& filename)
714{
715 bool isMain = ctx.xmlbuffers.empty(); // if we have no files yet, remember that this is the main XML file
716
717 if (!ctx.filenames.insert(filename).second)
718 // ignore already loaded files to prevent crash with cyclic includes
719 return 0;
720
721 // load XML into buffer
722 char* xmlbuffer = PageManager::LoadFileToBuffer(filename, ctx.zip);
723 if (!xmlbuffer)
724 return -1; // error already displayed by LoadFileToBuffer
725 ctx.xmlbuffers.push_back(xmlbuffer);
726
727 // parse XML
728 xml_document<>* doc = new xml_document<>();
729 doc->parse<0>(xmlbuffer);
730 ctx.xmldocs.push_back(doc);
731
732 xml_node<>* root = doc->first_node("recovery");
733 if (!root)
734 root = doc->first_node("install");
735 if (!root) {
736 LOGERR("Unknown root element in %s\n", filename.c_str());
737 return -1;
738 }
739
740 if (isMain) {
741 int rc = LoadDetails(ctx, root);
742 if (rc != 0)
743 return rc;
744 }
745
746 LOGINFO("Loading resources...\n");
747 xml_node<>* child = root->first_node("resources");
748 if (child)
749 mResources->LoadResources(child, ctx.zip, "theme");
750
751 LOGINFO("Loading variables...\n");
752 child = root->first_node("variables");
753 if (child)
754 LoadVariables(child);
755
756 LOGINFO("Loading mouse cursor...\n");
757 child = root->first_node("mousecursor");
758 if (child)
759 PageManager::LoadCursorData(child);
760
761 LOGINFO("Loading pages...\n");
762 child = root->first_node("templates");
763 if (child)
764 ctx.templates.push_back(child);
765
766 child = root->first_node("styles");
767 if (child)
768 ctx.styles.push_back(child);
769
770 // Load pages
771 child = root->first_node("pages");
772 if (child) {
773 if (LoadPages(ctx, child)) {
774 LOGERR("PageSet::Load returning -1\n");
775 return -1;
776 }
777 }
778
779 // process includes recursively
780 child = root->first_node("include");
781 if (child) {
782 xml_node<>* include = child->first_node("xmlfile");
783 while (include != NULL) {
784 xml_attribute<>* attr = include->first_attribute("name");
785 if (!attr) {
786 LOGERR("Skipping include/xmlfile with no name\n");
787 continue;
788 }
789
790 string filename = ctx.basepath + attr->value();
791 LOGINFO("Including file: %s...\n", filename.c_str());
792 int rc = Load(ctx, filename);
793 if (rc != 0)
794 return rc;
795
796 include = include->next_sibling("xmlfile");
797 }
798 }
799
800 return 0;
801}
802
803void PageSet::MakeEmergencyConsoleIfNeeded()
804{
805 if (mPages.empty()) {
806 mCurrentPage = new Page(NULL, NULL); // fallback console page
807 // TODO: since removal of non-TTF fonts, the emergency console doesn't work without a font, which might be missing too
808 mPages.push_back(mCurrentPage);
809 }
810}
811
bigbiff673c7ae2020-12-02 19:44:56 -0500812int PageSet::LoadLanguage(char* languageFile, ZipArchiveHandle package)
Ethan Yonker74db1572015-10-28 12:44:49 -0500813{
814 xml_document<> lang;
815 xml_node<>* parent;
816 xml_node<>* child;
817 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600818 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500819
820 if (languageFile) {
821 printf("parsing languageFile\n");
822 lang.parse<0>(languageFile);
823 printf("parsing languageFile done\n");
824 } else {
825 return -1;
826 }
827
828 parent = lang.first_node("language");
829 if (!parent) {
830 LOGERR("Unable to locate language node in language file.\n");
831 lang.clear();
832 return -1;
833 }
834
835 child = parent->first_node("display");
836 if (child) {
837 DataManager::SetValue("tw_language_display", child->value());
838 resource_source = child->value();
839 } else {
840 LOGERR("language file does not have a display value set\n");
841 DataManager::SetValue("tw_language_display", "Not Set");
842 resource_source = languageFile;
843 }
844
845 child = parent->first_node("resources");
846 if (child)
847 mResources->LoadResources(child, package, resource_source);
848 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600849 ret = -1;
850 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500851 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600852 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500853}
854
that6a894592016-03-13 17:51:28 +0100855int PageSet::LoadDetails(LoadingContext& ctx, xml_node<>* root)
Dees_Troy51a0e822012-09-05 15:24:24 -0400856{
that6a894592016-03-13 17:51:28 +0100857 xml_node<>* child = root->first_node("details");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600858 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600859 int theme_ver = 0;
860 xml_node<>* themeversion = child->first_node("themeversion");
861 if (themeversion && themeversion->value()) {
862 theme_ver = atoi(themeversion->value());
863 } else {
864 LOGINFO("No themeversion in theme.\n");
865 }
866 if (theme_ver != TW_THEME_VERSION) {
867 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
that6a894592016-03-13 17:51:28 +0100868 if (ctx.zip) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600869 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600870 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600871 } else {
872 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
873 }
874 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600875 xml_node<>* resolution = child->first_node("resolution");
876 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600877 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600878 xml_attribute<>* width_attr = resolution->first_attribute("width");
879 xml_attribute<>* height_attr = resolution->first_attribute("height");
880 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
881 if (width_attr && height_attr && !noscale_attr) {
882 int width = atoi(width_attr->value());
883 int height = atoi(height_attr->value());
884 int offx = 0, offy = 0;
885#ifdef TW_ROUND_SCREEN
886 xml_node<>* roundscreen = child->first_node("roundscreen");
887 if (roundscreen) {
888 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
889 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
890 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
891 if (offx_attr) {
892 offx = atoi(offx_attr->value());
893 }
894 if (offy_attr) {
895 offy = atoi(offy_attr->value());
896 }
897 }
898#endif
899 if (width != 0 && height != 0) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500900 float scale_w = (((float)gr_fb_width() + (float)tw_w_offset) - ((float)offx * 2.0)) / (float)width;
901 float scale_h = (((float)gr_fb_height() + (float)tw_h_offset) - ((float)offy * 2.0)) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600902#ifdef TW_ROUND_SCREEN
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500903 float scale_off_w = ((float)gr_fb_width() + (float)tw_w_offset) / (float)width;
904 float scale_off_h = ((float)gr_fb_height() + (float)tw_h_offset) / (float)height;
Ethan Yonker63e414f2015-02-06 15:44:39 -0600905 tw_x_offset = offx * scale_off_w;
906 tw_y_offset = offy * scale_off_h;
907#endif
908 if (scale_w != 1 || scale_h != 1) {
James Christopher Adduonodcd1e442016-11-06 13:17:34 -0500909 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i w: %i h: %i\n",
910 scale_w, scale_h, tw_x_offset, tw_y_offset, tw_w_offset, tw_h_offset);
Ethan Yonker63e414f2015-02-06 15:44:39 -0600911 set_scale_values(scale_w, scale_h);
912 }
913 }
914 } else {
915 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
916 }
917 } else {
918 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
919 }
920 } else {
921 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
922 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500923
Ethan Yonker780cd392014-07-21 15:24:39 -0500924 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400925}
926
927int PageSet::SetPage(std::string page)
928{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200929 Page* tmp = FindPage(page);
930 if (tmp)
931 {
932 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
933 mCurrentPage = tmp;
934 mCurrentPage->SetPageFocus(1);
935 mCurrentPage->NotifyVarChange("", "");
936 return 0;
937 }
938 else
939 {
940 LOGERR("Unable to locate page (%s)\n", page.c_str());
941 }
942 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400943}
944
945int PageSet::SetOverlay(Page* page)
946{
Ethan Yonker1c273312015-03-16 12:18:56 -0500947 if (page) {
948 if (mOverlays.size() >= 10) {
949 LOGERR("Too many overlays requested, max is 10.\n");
950 return -1;
951 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500952
953 std::vector<Page*>::iterator iter;
954 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
955 if ((*iter)->GetName() == page->GetName()) {
956 mOverlays.erase(iter);
957 // SetOverlay() is (and should stay) the only function which
958 // adds to mOverlays. Then, each page can appear at most once.
959 break;
960 }
961 }
962
Ethan Yonker1c273312015-03-16 12:18:56 -0500963 page->SetPageFocus(1);
964 page->NotifyVarChange("", "");
965
966 if (!mOverlays.empty())
967 mOverlays.back()->SetPageFocus(0);
968
969 mOverlays.push_back(page);
970 } else {
971 if (!mOverlays.empty()) {
972 mOverlays.back()->SetPageFocus(0);
973 mOverlays.pop_back();
974 if (!mOverlays.empty())
975 mOverlays.back()->SetPageFocus(1);
976 else if (mCurrentPage)
977 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
978 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200979 }
980 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400981}
982
that74ac6062015-03-04 22:39:34 +0100983const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -0400984{
that74ac6062015-03-04 22:39:34 +0100985 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400986}
987
988Page* PageSet::FindPage(std::string name)
989{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200990 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400991
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200992 for (iter = mPages.begin(); iter != mPages.end(); iter++)
993 {
994 if (name == (*iter)->GetName())
995 return (*iter);
996 }
997 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400998}
999
1000int PageSet::LoadVariables(xml_node<>* vars)
1001{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001002 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001003 xml_attribute<> *name, *value, *persist;
1004 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001005
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001006 child = vars->first_node("variable");
1007 while (child)
1008 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001009 name = child->first_attribute("name");
1010 value = child->first_attribute("value");
1011 persist = child->first_attribute("persist");
Matt Mowera8a89d12016-12-30 18:10:37 -06001012 if (name && value)
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001013 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001014 if (strcmp(name->value(), "tw_x_offset") == 0) {
1015 tw_x_offset = atoi(value->value());
1016 child = child->next_sibling("variable");
1017 continue;
1018 }
1019 if (strcmp(name->value(), "tw_y_offset") == 0) {
1020 tw_y_offset = atoi(value->value());
1021 child = child->next_sibling("variable");
1022 continue;
1023 }
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001024 if (strcmp(name->value(), "tw_w_offset") == 0) {
1025 tw_w_offset = atoi(value->value());
1026 child = child->next_sibling("variable");
1027 continue;
1028 }
1029 if (strcmp(name->value(), "tw_h_offset") == 0) {
1030 tw_h_offset = atoi(value->value());
1031 child = child->next_sibling("variable");
1032 continue;
1033 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001034 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001035 string temp = value->value();
1036 string valstr = gui_parse_text(temp);
1037
1038 if (valstr.find("+") != string::npos) {
1039 string val1str = valstr;
1040 val1str = val1str.substr(0, val1str.find('+'));
1041 string val2str = valstr;
1042 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1043 int val1 = atoi(val1str.c_str());
1044 int val2 = atoi(val2str.c_str());
1045 int val = val1 + val2;
1046
1047 DataManager::SetValue(name->value(), val, p);
1048 } else if (valstr.find("-") != string::npos) {
1049 string val1str = valstr;
1050 val1str = val1str.substr(0, val1str.find('-'));
1051 string val2str = valstr;
1052 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1053 int val1 = atoi(val1str.c_str());
1054 int val2 = atoi(val2str.c_str());
1055 int val = val1 - val2;
1056
1057 DataManager::SetValue(name->value(), val, p);
1058 } else {
1059 DataManager::SetValue(name->value(), valstr, p);
1060 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001061 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001062
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001063 child = child->next_sibling("variable");
1064 }
1065 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001066}
1067
that6a894592016-03-13 17:51:28 +01001068int PageSet::LoadPages(LoadingContext& ctx, xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001069{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001070 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001071
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001072 if (!pages)
1073 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001074
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001075 child = pages->first_node("page");
1076 while (child != NULL)
1077 {
that6a894592016-03-13 17:51:28 +01001078 Page* page = new Page(child, &ctx.templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001079 if (page->GetName().empty())
1080 {
1081 LOGERR("Unable to process load page\n");
1082 delete page;
1083 }
1084 else
1085 {
1086 mPages.push_back(page);
1087 }
1088 child = child->next_sibling("page");
1089 }
1090 if (mPages.size() > 0)
1091 return 0;
1092 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001093}
1094
1095int PageSet::IsCurrentPage(Page* page)
1096{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001097 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001098}
1099
that10ae24f2015-12-26 20:53:51 +01001100std::string PageSet::GetCurrentPage() const
1101{
1102 return mCurrentPage ? mCurrentPage->GetName() : "";
1103}
1104
Dees_Troy51a0e822012-09-05 15:24:24 -04001105int PageSet::Render(void)
1106{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001107 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001108
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001109 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1110 if (ret < 0)
1111 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001112
1113 std::vector<Page*>::iterator iter;
1114
1115 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1116 ret = ((*iter) ? (*iter)->Render() : -1);
1117 if (ret < 0)
1118 return ret;
1119 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001120 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001121}
1122
1123int PageSet::Update(void)
1124{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001125 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001126
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001127 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1128 if (ret < 0 || ret > 1)
1129 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001130
1131 std::vector<Page*>::iterator iter;
1132
1133 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1134 ret = ((*iter) ? (*iter)->Update() : -1);
1135 if (ret < 0)
1136 return ret;
1137 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001138 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001139}
1140
1141int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1142{
Ethan Yonker1c273312015-03-16 12:18:56 -05001143 if (!mOverlays.empty())
1144 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001145
1146 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001147}
1148
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001149int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001150{
Ethan Yonker1c273312015-03-16 12:18:56 -05001151 if (!mOverlays.empty())
1152 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001153
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001154 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001155}
1156
that8834a0f2016-01-05 23:29:30 +01001157int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001158{
Ethan Yonker1c273312015-03-16 12:18:56 -05001159 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001160 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001161
that8834a0f2016-01-05 23:29:30 +01001162 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001163}
1164
1165int PageSet::SetKeyBoardFocus(int inFocus)
1166{
Ethan Yonker1c273312015-03-16 12:18:56 -05001167 if (!mOverlays.empty())
1168 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001169
1170 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001171}
1172
1173int PageSet::NotifyVarChange(std::string varName, std::string value)
1174{
Ethan Yonker1c273312015-03-16 12:18:56 -05001175 std::vector<Page*>::iterator iter;
1176
1177 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1178 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001179
1180 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001181}
1182
Ethan Yonker74db1572015-10-28 12:44:49 -05001183void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1184{
1185 mResources->AddStringResource(resource_source, resource_name, value);
1186}
1187
bigbiff673c7ae2020-12-02 19:44:56 -05001188char* PageManager::LoadFileToBuffer(std::string filename, ZipArchiveHandle package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001189 size_t len;
1190 char* buffer = NULL;
1191
Mohd Faraz16c32042021-04-17 15:14:25 +02001192 if (!package) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001193 // We can try to load the XML directly...
1194 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1195 struct stat st;
Matt Mowera8a89d12016-12-30 18:10:37 -06001196 if (stat(filename.c_str(),&st) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001197 // This isn't always an error, sometimes we request files that don't exist.
1198 return NULL;
1199 }
1200
1201 len = (size_t)st.st_size;
1202
1203 buffer = (char*) malloc(len + 1);
1204 if (!buffer) {
1205 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1206 return NULL;
1207 }
1208
1209 int fd = open(filename.c_str(), O_RDONLY);
1210 if (fd == -1) {
1211 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1212 free(buffer);
1213 return NULL;
1214 }
1215
1216 if (read(fd, buffer, len) < 0) {
1217 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1218 free(buffer);
1219 close(fd);
1220 return NULL;
1221 }
1222 close(fd);
1223 } else {
1224 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
bigbiff673c7ae2020-12-02 19:44:56 -05001225 ZipEntry binary_entry;
bigbiff83298f52021-10-13 19:24:42 -04001226 if (FindEntry(package, filename, &binary_entry) != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001227 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1228 return NULL;
1229 }
1230
1231 // Allocate the buffer for the file
bigbiff673c7ae2020-12-02 19:44:56 -05001232 len = binary_entry.uncompressed_length;
Ethan Yonker561c58d2015-10-05 08:48:22 -05001233 buffer = (char*) malloc(len + 1);
1234 if (!buffer)
1235 return NULL;
1236
bigbiff673c7ae2020-12-02 19:44:56 -05001237 int32_t err =
1238 ExtractToMemory(package, &binary_entry, reinterpret_cast<uint8_t*>(buffer), len);
1239 if (err != 0) {
Ethan Yonker561c58d2015-10-05 08:48:22 -05001240 LOGERR("Unable to extract '%s'\n", filename.c_str());
1241 free(buffer);
1242 return NULL;
1243 }
1244 }
1245 // NULL-terminate the string
1246 buffer[len] = 0x00;
1247 return buffer;
1248}
1249
Ethan Yonker74db1572015-10-28 12:44:49 -05001250void PageManager::LoadLanguageListDir(string dir) {
1251 if (!TWFunc::Path_Exists(dir)) {
1252 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1253 return;
1254 }
1255
1256 DIR *d = opendir(dir.c_str());
1257 struct dirent *p;
1258
1259 if (d == NULL) {
1260 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1261 return;
1262 }
1263
1264 while ((p = readdir(d))) {
1265 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1266 continue;
1267
1268 string file = p->d_name;
1269 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1270 continue;
1271 string path = dir + p->d_name;
1272 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1273 struct language_struct language_entry;
1274 language_entry.filename = file_no_extn;
1275 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1276 if (xmlFile == NULL) {
1277 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1278 continue;
1279 }
1280 xml_document<> *doc = new xml_document<>();
1281 doc->parse<0>(xmlFile);
1282
1283 xml_node<>* parent = doc->first_node("language");
1284 if (!parent) {
1285 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1286 } else {
1287 xml_node<>* child = parent->first_node("display");
1288 if (child) {
1289 language_entry.displayvalue = child->value();
1290 } else {
1291 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1292 language_entry.displayvalue = language_entry.filename;
1293 }
1294 Language_List.push_back(language_entry);
1295 }
1296 doc->clear();
1297 delete doc;
1298 free(xmlFile);
1299 }
1300 closedir(d);
1301}
1302
bigbiff673c7ae2020-12-02 19:44:56 -05001303void PageManager::LoadLanguageList(ZipArchiveHandle package) {
Ethan Yonker74db1572015-10-28 12:44:49 -05001304 Language_List.clear();
1305 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1306 TWFunc::removeDir(TWRES "customlanguages", true);
1307 if (package) {
1308 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
bigbiff83298f52021-10-13 19:24:42 -04001309 ExtractPackageRecursive(package, "/", TWRES "customlanguages", nullptr, nullptr);
bigbiff673c7ae2020-12-02 19:44:56 -05001310
1311 // package->ExtractRecursive("languages", TWRES "customlanguages/");
Ethan Yonker74db1572015-10-28 12:44:49 -05001312 LoadLanguageListDir(TWRES "customlanguages/");
1313 } else {
1314 LoadLanguageListDir(TWRES "languages/");
1315 }
Xuefercac6ace2016-02-01 02:28:55 +08001316
1317 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001318}
1319
1320void PageManager::LoadLanguage(string filename) {
1321 string actual_filename;
1322 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1323 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1324 else
1325 actual_filename = TWRES "languages/" + filename + ".xml";
1326 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1327 if (xmlFile == NULL)
1328 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1329 else {
1330 mCurrentSet->LoadLanguage(xmlFile, NULL);
1331 free(xmlFile);
1332 }
1333 PartitionManager.Translate_Partition_Display_Names();
1334}
1335
Dees_Troy51a0e822012-09-05 15:24:24 -04001336int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1337{
that6a894592016-03-13 17:51:28 +01001338 std::string mainxmlfilename = package;
Ethan Yonker74db1572015-10-28 12:44:49 -05001339 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001340 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001341 PageSet* pageSet = NULL;
1342 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001343
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001344 mReloadTheme = false;
1345 mStartPage = startpage;
1346
that6a894592016-03-13 17:51:28 +01001347 // init the loading context
1348 LoadingContext ctx;
1349
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001350 // Open the XML file
1351 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001352 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001353 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001354 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001355 tw_x_offset = TW_X_OFFSET;
1356 tw_y_offset = TW_Y_OFFSET;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001357 tw_w_offset = TW_W_OFFSET;
1358 tw_h_offset = TW_H_OFFSET;
Ethan Yonker4f74d142016-03-31 08:10:37 -05001359 if (name != "splash") {
1360 LoadLanguageList(NULL);
1361 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
1362 }
that6a894592016-03-13 17:51:28 +01001363 ctx.basepath = TWRES;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001364 }
1365 else
1366 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001367 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001368 tw_x_offset = 0;
1369 tw_y_offset = 0;
James Christopher Adduonodcd1e442016-11-06 13:17:34 -05001370 tw_w_offset = 0;
1371 tw_h_offset = 0;
bigbiff83298f52021-10-13 19:24:42 -04001372 if (!TWFunc::Path_Exists(package)) {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001373 return -1;
bigbiff83298f52021-10-13 19:24:42 -04001374 }
bigbiff673c7ae2020-12-02 19:44:56 -05001375
1376 ZipArchiveHandle Zip;
1377 int err = OpenArchive(package.c_str(), &Zip);
1378
1379 if (err != 0)
1380 return -1;
bigbiff83298f52021-10-13 19:24:42 -04001381
bigbiff673c7ae2020-12-02 19:44:56 -05001382 ctx.zip = Zip;
that6a894592016-03-13 17:51:28 +01001383 mainxmlfilename = "ui.xml";
1384 LoadLanguageList(ctx.zip);
1385 languageFile = LoadFileToBuffer("languages/en.xml", ctx.zip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001386 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001387 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001388
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001389 // Before loading, mCurrentSet must be the loading package so we can find resources
1390 pageSet = mCurrentSet;
that6a894592016-03-13 17:51:28 +01001391 mCurrentSet = new PageSet();
1392
1393 if (baseLanguageFile) {
1394 mCurrentSet->LoadLanguage(baseLanguageFile, NULL);
1395 free(baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001396 }
that6a894592016-03-13 17:51:28 +01001397
1398 if (languageFile) {
1399 mCurrentSet->LoadLanguage(languageFile, ctx.zip);
1400 free(languageFile);
1401 }
1402
1403 // Load and parse the XML and all includes
1404 currentLoadingContext = &ctx; // required to find styles
1405 ret = mCurrentSet->Load(ctx, mainxmlfilename);
1406 currentLoadingContext = NULL;
1407
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001408 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001409 mCurrentSet->SetPage(startpage);
1410 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001411 } else {
1412 if (ret != TW_THEME_VER_ERR)
1413 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001414 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001415
that6a894592016-03-13 17:51:28 +01001416 // reset to previous pageset
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001417 mCurrentSet = pageSet;
1418
that6a894592016-03-13 17:51:28 +01001419 if (ctx.zip) {
bigbiff673c7ae2020-12-02 19:44:56 -05001420 CloseArchive(ctx.zip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001421 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001422 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001423}
1424
1425PageSet* PageManager::FindPackage(std::string name)
1426{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001427 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001428
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001429 iter = mPageSets.find(name);
1430 if (iter != mPageSets.end())
1431 return (*iter).second;
1432
1433 LOGERR("Unable to locate package %s\n", name.c_str());
1434 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001435}
1436
1437PageSet* PageManager::SelectPackage(std::string name)
1438{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001439 LOGINFO("Switching packages (%s)\n", name.c_str());
1440 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001441
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001442 tmp = FindPackage(name);
1443 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001444 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001445 mCurrentSet = tmp;
that6a894592016-03-13 17:51:28 +01001446 mCurrentSet->MakeEmergencyConsoleIfNeeded();
Vojtech Bocek07220562014-02-08 02:05:33 +01001447 mCurrentSet->NotifyVarChange("", "");
1448 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001449 else
1450 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001451
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001452 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001453}
1454
1455int PageManager::ReloadPackage(std::string name, std::string package)
1456{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001457 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001458
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001459 mReloadTheme = false;
1460
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001461 iter = mPageSets.find(name);
1462 if (iter == mPageSets.end())
1463 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001464
Matt Mowera8a89d12016-12-30 18:10:37 -06001465 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001466 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1467
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 PageSet* set = (*iter).second;
1469 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001470
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001471 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001472 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001473 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001474 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1475 return -1;
1476 }
1477 if (mCurrentSet == set)
1478 SelectPackage(name);
1479 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001480 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001481 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001482}
1483
1484void PageManager::ReleasePackage(std::string name)
1485{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001486 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001487
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001488 iter = mPageSets.find(name);
1489 if (iter == mPageSets.end())
1490 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001491
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001492 PageSet* set = (*iter).second;
1493 mPageSets.erase(iter);
1494 delete set;
that235c6482016-01-24 21:59:00 +01001495 if (set == mCurrentSet)
1496 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001497 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001498}
1499
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001500int PageManager::RunReload() {
1501 int ret_val = 0;
1502 std::string theme_path;
1503
1504 if (!mReloadTheme)
1505 return 0;
1506
1507 mReloadTheme = false;
1508 theme_path = DataManager::GetSettingsStoragePath();
1509 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1510 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1511 ret_val = 1;
1512 }
1513
1514 theme_path += "/TWRP/theme/ui.zip";
1515 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1516 {
1517 // Loading the custom theme failed - try loading the stock theme
1518 LOGINFO("Attempting to reload stock theme...\n");
1519 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1520 {
1521 LOGERR("Failed to load base packages.\n");
1522 ret_val = 1;
1523 }
1524 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001525 if (ret_val == 0) {
1526 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1527 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1528 LoadLanguage(DataManager::GetStrValue("tw_language"));
1529 }
1530 }
1531
1532 // This makes the console re-translate
thata9dd9f02017-02-23 23:08:56 +01001533 GUIConsole::Clear_For_Retranslation();
Ethan Yonker74db1572015-10-28 12:44:49 -05001534
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001535 return ret_val;
1536}
1537
1538void PageManager::RequestReload() {
1539 mReloadTheme = true;
1540}
1541
Ethan Yonkerafde0982016-01-23 08:55:35 -06001542void PageManager::SetStartPage(const std::string& page_name) {
1543 mStartPage = page_name;
1544}
1545
Dees_Troy51a0e822012-09-05 15:24:24 -04001546int PageManager::ChangePage(std::string name)
1547{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001548 DataManager::SetValue("tw_operation_state", 0);
1549 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1550 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001551}
1552
that10ae24f2015-12-26 20:53:51 +01001553std::string PageManager::GetCurrentPage()
1554{
1555 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1556}
1557
Dees_Troy51a0e822012-09-05 15:24:24 -04001558int PageManager::ChangeOverlay(std::string name)
1559{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001560 if (name.empty())
1561 return mCurrentSet->SetOverlay(NULL);
1562 else
1563 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001564 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001565 return mCurrentSet->SetOverlay(page);
1566 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001567}
1568
that74ac6062015-03-04 22:39:34 +01001569const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001570{
that74ac6062015-03-04 22:39:34 +01001571 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001572}
1573
Dees_Troy51a0e822012-09-05 15:24:24 -04001574int PageManager::IsCurrentPage(Page* page)
1575{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001576 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001577}
1578
1579int PageManager::Render(void)
1580{
Matt Mowera8a89d12016-12-30 18:10:37 -06001581 if (blankTimer.isScreenOff())
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001582 return 0;
1583
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001584 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
Matt Mowera8a89d12016-12-30 18:10:37 -06001585 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001586 mMouseCursor->Render();
1587 return res;
1588}
1589
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001590HardwareKeyboard *PageManager::GetHardwareKeyboard()
1591{
Matt Mowera8a89d12016-12-30 18:10:37 -06001592 if (!mHardwareKeyboard)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001593 mHardwareKeyboard = new HardwareKeyboard();
1594 return mHardwareKeyboard;
1595}
1596
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001597xml_node<>* PageManager::FindStyle(std::string name)
1598{
that6a894592016-03-13 17:51:28 +01001599 if (!currentLoadingContext)
1600 {
1601 LOGERR("FindStyle works only while loading a theme.\n");
1602 return NULL;
1603 }
1604
1605 for (std::vector<xml_node<>*>::iterator itr = currentLoadingContext->styles.begin(); itr != currentLoadingContext->styles.end(); itr++) {
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001606 xml_node<>* node = (*itr)->first_node("style");
1607
1608 while (node) {
1609 if (!node->first_attribute("name"))
1610 continue;
1611
1612 if (name == node->first_attribute("name")->value())
1613 return node;
1614 node = node->next_sibling("style");
1615 }
1616 }
1617 return NULL;
1618}
1619
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001620MouseCursor *PageManager::GetMouseCursor()
1621{
Matt Mowera8a89d12016-12-30 18:10:37 -06001622 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001623 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1624 return mMouseCursor;
1625}
1626
1627void PageManager::LoadCursorData(xml_node<>* node)
1628{
Matt Mowera8a89d12016-12-30 18:10:37 -06001629 if (!mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001630 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1631
1632 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001633}
1634
1635int PageManager::Update(void)
1636{
Matt Mowera8a89d12016-12-30 18:10:37 -06001637 if (blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001638 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001639
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001640 if (RunReload())
1641 return -2;
1642
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001643 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1644
Matt Mowera8a89d12016-12-30 18:10:37 -06001645 if (mMouseCursor)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001646 {
1647 int c_res = mMouseCursor->Update();
Matt Mowera8a89d12016-12-30 18:10:37 -06001648 if (c_res > res)
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001649 res = c_res;
1650 }
1651 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001652}
1653
1654int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1655{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001656 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001657}
1658
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001659int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001660{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001661 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001662}
1663
that8834a0f2016-01-05 23:29:30 +01001664int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001665{
that8834a0f2016-01-05 23:29:30 +01001666 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001667}
1668
1669int PageManager::SetKeyBoardFocus(int inFocus)
1670{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001671 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001672}
1673
1674int PageManager::NotifyVarChange(std::string varName, std::string value)
1675{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001676 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001677}
1678
Ethan Yonker74db1572015-10-28 12:44:49 -05001679void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1680{
1681 if (mCurrentSet)
1682 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1683}
1684
Dees_Troy51a0e822012-09-05 15:24:24 -04001685extern "C" void gui_notifyVarChange(const char *name, const char* value)
1686{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001687 if (!gGuiRunning)
1688 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001689
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001690 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001691}