blob: c45566232b57314fb9b5a615352caebd4865cff5 [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 Yonkera2dc2f22014-11-08 08:13:40 -060035#include "../twrp-functions.hpp"
Ethan Yonker74db1572015-10-28 12:44:49 -050036#include "../partitions.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040037
38#include <string>
39
40extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000041#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040042#include "../minuitwrp/minui.h"
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060043#include "../minzip/SysUtil.h"
44#include "../minzip/Zip.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060045#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040046}
47
48#include "rapidxml.hpp"
49#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020050#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040051
Ethan Yonker1308d532016-01-14 22:21:49 -060052#define TW_THEME_VERSION 1
Ethan Yonker8e5692f2016-01-21 11:21:06 -060053#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060054
Dees_Troy51a0e822012-09-05 15:24:24 -040055extern int gGuiRunning;
56
Ethan Yonker74db1572015-10-28 12:44:49 -050057// From ../twrp.cpp
58extern bool datamedia;
59
60// From console.cpp
61extern size_t last_message_count;
62extern std::vector<std::string> gConsole;
63extern std::vector<std::string> gConsoleColor;
64
Dees_Troy51a0e822012-09-05 15:24:24 -040065std::map<std::string, PageSet*> PageManager::mPageSets;
66PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010067MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010068HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050069bool PageManager::mReloadTheme = false;
70std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050071std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040072
Ethan Yonker751a85e2014-12-12 16:59:10 -060073int tw_x_offset = 0;
74int tw_y_offset = 0;
75
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);
384 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200385 else if (type == "button")
386 {
387 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100388 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200389 mRenders.push_back(element);
390 mActions.push_back(element);
391 }
392 else if (type == "checkbox")
393 {
394 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100395 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200396 mRenders.push_back(element);
397 mActions.push_back(element);
398 }
399 else if (type == "fileselector")
400 {
401 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100402 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200403 mRenders.push_back(element);
404 mActions.push_back(element);
405 }
406 else if (type == "animation")
407 {
408 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100409 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200410 mRenders.push_back(element);
411 }
412 else if (type == "progressbar")
413 {
414 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100415 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200416 mRenders.push_back(element);
417 mActions.push_back(element);
418 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400419 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200420 {
421 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100422 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200423 mRenders.push_back(element);
424 mActions.push_back(element);
425 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200426 else if (type == "slidervalue")
427 {
428 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100429 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200430 mRenders.push_back(element);
431 mActions.push_back(element);
432 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400433 else if (type == "listbox")
434 {
435 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100436 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400437 mRenders.push_back(element);
438 mActions.push_back(element);
439 }
440 else if (type == "keyboard")
441 {
442 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100443 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400444 mRenders.push_back(element);
445 mActions.push_back(element);
446 }
447 else if (type == "input")
448 {
449 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100450 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400451 mRenders.push_back(element);
452 mActions.push_back(element);
453 mInputs.push_back(element);
454 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500455 else if (type == "partitionlist")
456 {
457 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100458 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500459 mRenders.push_back(element);
460 mActions.push_back(element);
461 }
Vojtech Bocek7e11ac52015-03-05 23:21:49 +0100462 else if (type == "patternpassword")
463 {
464 GUIPatternPassword* element = new GUIPatternPassword(child);
465 mObjects.push_back(element);
466 mRenders.push_back(element);
467 mActions.push_back(element);
468 }
Ethan Yonker44925ad2015-07-22 12:33:59 -0500469 else if (type == "textbox")
470 {
471 GUITextBox* element = new GUITextBox(child);
472 mObjects.push_back(element);
473 mRenders.push_back(element);
474 mActions.push_back(element);
475 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200476 else if (type == "template")
477 {
478 if (!templates || !child->first_attribute("name"))
479 {
480 LOGERR("Invalid template request.\n");
481 }
482 else
483 {
484 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500485 xml_node<>* node;
486 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400487
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200488 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500489 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
490 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400491
Ethan Yonker780cd392014-07-21 15:24:39 -0500492 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200493 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500494 if (!node->first_attribute("name"))
495 continue;
496
497 if (name == node->first_attribute("name")->value())
498 {
499 if (!ProcessNode(node, templates, depth + 1))
500 return false;
501 else {
502 node_found = true;
503 break;
504 }
505 }
506 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200507 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500508 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200509 }
thatb63e2f92015-06-27 21:35:11 +0200510 // [check] why is there no if (node_found) here too?
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200511 }
512 }
513 }
514 else
515 {
thatb63e2f92015-06-27 21:35:11 +0200516 LOGERR("Unknown object type: %s.\n", type.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200518 }
519 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400520}
521
522int Page::Render(void)
523{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200524 // Render background
525 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
526 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400527
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200528 // Render remaining objects
529 std::vector<RenderObject*>::iterator iter;
530 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
531 {
532 if ((*iter)->Render())
533 LOGERR("A render request has failed.\n");
534 }
535 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400536}
537
538int Page::Update(void)
539{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200540 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400541
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200542 std::vector<RenderObject*>::iterator iter;
543 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
544 {
545 int ret = (*iter)->Update();
546 if (ret < 0)
547 LOGERR("An update request has failed.\n");
548 else if (ret > retCode)
549 retCode = ret;
550 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400551
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200552 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400553}
554
555int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
556{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200557 // By default, return 1 to ignore further touches if nobody is listening
558 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400559
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200560 // Don't try to handle a lack of handlers
561 if (mActions.size() == 0)
562 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400563
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200564 // We record mTouchStart so we can pass all the touch stream to the same handler
565 if (state == TOUCH_START)
566 {
567 std::vector<ActionObject*>::reverse_iterator iter;
568 // We work backwards, from top-most element to bottom-most element
569 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
570 {
571 if ((*iter)->IsInRegion(x, y))
572 {
573 mTouchStart = (*iter);
574 ret = mTouchStart->NotifyTouch(state, x, y);
575 if (ret >= 0)
576 break;
577 mTouchStart = NULL;
578 }
579 }
580 }
581 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
582 {
583 ret = mTouchStart->NotifyTouch(state, x, y);
584 mTouchStart = NULL;
585 }
586 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
587 {
588 ret = mTouchStart->NotifyTouch(state, x, y);
589 }
590 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400591}
592
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100593int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400594{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200595 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400596
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100597 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200598 // We work backwards, from top-most element to bottom-most element
599 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
600 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100601 ret = (*iter)->NotifyKey(key, down);
that8834a0f2016-01-05 23:29:30 +0100602 if (ret == 0)
603 return 0;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100604 if (ret < 0) {
605 LOGERR("An action handler has returned an error\n");
606 ret = 1;
607 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100609 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400610}
611
that8834a0f2016-01-05 23:29:30 +0100612int Page::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -0400613{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200614 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400615
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200616 // We work backwards, from top-most element to bottom-most element
617 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
618 {
that8834a0f2016-01-05 23:29:30 +0100619 int ret = (*iter)->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200620 if (ret == 0)
621 return 0;
622 else if (ret < 0)
that8834a0f2016-01-05 23:29:30 +0100623 LOGERR("A char input handler has returned an error");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200624 }
625 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400626}
627
628int Page::SetKeyBoardFocus(int inFocus)
629{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200630 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400631
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200632 // We work backwards, from top-most element to bottom-most element
633 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
634 {
635 int ret = (*iter)->SetInputFocus(inFocus);
636 if (ret == 0)
637 return 0;
638 else if (ret < 0)
639 LOGERR("An input focus handler has returned an error");
640 }
641 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400642}
643
644void Page::SetPageFocus(int inFocus)
645{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200646 // Render remaining objects
647 std::vector<RenderObject*>::iterator iter;
648 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
649 (*iter)->SetPageFocus(inFocus);
650
651 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400652}
653
654int Page::NotifyVarChange(std::string varName, std::string value)
655{
Vojtech Bocek07220562014-02-08 02:05:33 +0100656 std::vector<GUIObject*>::iterator iter;
657 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200658 {
659 if ((*iter)->NotifyVarChange(varName, value))
660 LOGERR("An action handler errored on NotifyVarChange.\n");
661 }
662 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400663}
664
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500665PageSet::PageSet(const char* xmlFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400666{
that74ac6062015-03-04 22:39:34 +0100667 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200668 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400669
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500670 if (!xmlFile)
thatb63e2f92015-06-27 21:35:11 +0200671 mCurrentPage = new Page(NULL, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400672}
673
674PageSet::~PageSet()
675{
Ethan Yonker1c273312015-03-16 12:18:56 -0500676 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100677 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
678 delete *itr;
679
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200680 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400681}
682
Ethan Yonker74db1572015-10-28 12:44:49 -0500683int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
684{
685 xml_document<> lang;
686 xml_node<>* parent;
687 xml_node<>* child;
688 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600689 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500690
691 if (languageFile) {
692 printf("parsing languageFile\n");
693 lang.parse<0>(languageFile);
694 printf("parsing languageFile done\n");
695 } else {
696 return -1;
697 }
698
699 parent = lang.first_node("language");
700 if (!parent) {
701 LOGERR("Unable to locate language node in language file.\n");
702 lang.clear();
703 return -1;
704 }
705
706 child = parent->first_node("display");
707 if (child) {
708 DataManager::SetValue("tw_language_display", child->value());
709 resource_source = child->value();
710 } else {
711 LOGERR("language file does not have a display value set\n");
712 DataManager::SetValue("tw_language_display", "Not Set");
713 resource_source = languageFile;
714 }
715
716 child = parent->first_node("resources");
717 if (child)
718 mResources->LoadResources(child, package, resource_source);
719 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600720 ret = -1;
721 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500722 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600723 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500724}
725
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600726int PageSet::Load(ZipArchive* package, char* xmlFile, char* languageFile, char* baseLanguageFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400727{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500728 xml_document<> mDoc;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200729 xml_node<>* parent;
730 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500731 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600732 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500733
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500734 mDoc.parse<0>(xmlFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200735 parent = mDoc.first_node("recovery");
736 if (!parent)
737 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400738
Ethan Yonker63e414f2015-02-06 15:44:39 -0600739 set_scale_values(1, 1); // Reset any previous scaling values
740
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600741 if (baseLanguageFile)
742 LoadLanguage(baseLanguageFile, NULL);
743
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200744 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600745 child = parent->first_node("details");
746 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600747 int theme_ver = 0;
748 xml_node<>* themeversion = child->first_node("themeversion");
749 if (themeversion && themeversion->value()) {
750 theme_ver = atoi(themeversion->value());
751 } else {
752 LOGINFO("No themeversion in theme.\n");
753 }
754 if (theme_ver != TW_THEME_VERSION) {
755 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
756 if (package) {
757 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
758 mDoc.clear();
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600759 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600760 } else {
761 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
762 }
763 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600764 xml_node<>* resolution = child->first_node("resolution");
765 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600766 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600767 xml_attribute<>* width_attr = resolution->first_attribute("width");
768 xml_attribute<>* height_attr = resolution->first_attribute("height");
769 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
770 if (width_attr && height_attr && !noscale_attr) {
771 int width = atoi(width_attr->value());
772 int height = atoi(height_attr->value());
773 int offx = 0, offy = 0;
774#ifdef TW_ROUND_SCREEN
775 xml_node<>* roundscreen = child->first_node("roundscreen");
776 if (roundscreen) {
777 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
778 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
779 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
780 if (offx_attr) {
781 offx = atoi(offx_attr->value());
782 }
783 if (offy_attr) {
784 offy = atoi(offy_attr->value());
785 }
786 }
787#endif
788 if (width != 0 && height != 0) {
789 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
790 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
791#ifdef TW_ROUND_SCREEN
792 float scale_off_w = (float)gr_fb_width() / (float)width;
793 float scale_off_h = (float)gr_fb_height() / (float)height;
794 tw_x_offset = offx * scale_off_w;
795 tw_y_offset = offy * scale_off_h;
796#endif
797 if (scale_w != 1 || scale_h != 1) {
798 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
799 set_scale_values(scale_w, scale_h);
800 }
801 }
802 } else {
803 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
804 }
805 } else {
806 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
807 }
808 } else {
809 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
810 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500811
812 if (languageFile)
813 LoadLanguage(languageFile, package);
814
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200815 LOGINFO("Loading resources...\n");
816 child = parent->first_node("resources");
817 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500818 mResources->LoadResources(child, package, "theme");
Dees_Troy51a0e822012-09-05 15:24:24 -0400819
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200820 LOGINFO("Loading variables...\n");
821 child = parent->first_node("variables");
822 if (child)
823 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400824
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100825 LOGINFO("Loading mouse cursor...\n");
826 child = parent->first_node("mousecursor");
827 if(child)
828 PageManager::LoadCursorData(child);
829
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200830 LOGINFO("Loading pages...\n");
831 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500832 xmltemplate = parent->first_node("templates");
833 if (xmltemplate)
834 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400835
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600836 // Load styles if present
837 xmlstyle = parent->first_node("styles");
838 if (xmlstyle)
839 styles.push_back(xmlstyle);
840
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200841 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500842 if (child) {
843 if (LoadPages(child)) {
844 LOGERR("PageSet::Load returning -1\n");
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500845 mDoc.clear();
Ethan Yonker780cd392014-07-21 15:24:39 -0500846 return -1;
847 }
848 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100849
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500850 int ret = CheckInclude(package, &mDoc);
851 mDoc.clear();
852 templates.clear();
853 return ret;
Ethan Yonker780cd392014-07-21 15:24:39 -0500854}
Dees_Troy51a0e822012-09-05 15:24:24 -0400855
Ethan Yonker780cd392014-07-21 15:24:39 -0500856int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
857{
858 xml_node<>* par;
859 xml_node<>* par2;
860 xml_node<>* chld;
861 xml_node<>* parent;
862 xml_node<>* child;
863 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600864 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500865 long len;
866 char* xmlFile = NULL;
867 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100868 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500869
870 par = parentDoc->first_node("recovery");
871 if (!par) {
872 par = parentDoc->first_node("install");
873 }
874 if (!par) {
875 return 0;
876 }
877
878 par2 = par->first_node("include");
879 if (!par2)
880 return 0;
881 chld = par2->first_node("xmlfile");
882 while (chld != NULL) {
883 xml_attribute<>* attr = chld->first_attribute("name");
884 if (!attr)
885 break;
886
Ethan Yonker780cd392014-07-21 15:24:39 -0500887 if (!package) {
888 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000889 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500890 filename += attr->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500891 } else {
892 filename += attr->value();
Ethan Yonker561c58d2015-10-05 08:48:22 -0500893 }
894 xmlFile = PageManager::LoadFileToBuffer(filename, package);
895 if (xmlFile == NULL) {
896 LOGERR("PageSet::CheckInclude unable to load '%s'\n", filename.c_str());
897 return -1;
Ethan Yonker780cd392014-07-21 15:24:39 -0500898 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500899
Vojtech Boceke979abd2015-01-12 18:29:12 +0100900 doc = new xml_document<>();
901 doc->parse<0>(xmlFile);
902
903 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500904 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100905 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500906
907 // Now, let's parse the XML
908 LOGINFO("Loading included resources...\n");
909 child = parent->first_node("resources");
910 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500911 mResources->LoadResources(child, package, "theme");
Ethan Yonker780cd392014-07-21 15:24:39 -0500912
913 LOGINFO("Loading included variables...\n");
914 child = parent->first_node("variables");
915 if (child)
916 LoadVariables(child);
917
918 LOGINFO("Loading mouse cursor...\n");
919 child = parent->first_node("mousecursor");
920 if(child)
921 PageManager::LoadCursorData(child);
922
923 LOGINFO("Loading included pages...\n");
924 // This may be NULL if no templates are present
925 xmltemplate = parent->first_node("templates");
926 if (xmltemplate)
927 templates.push_back(xmltemplate);
928
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600929 // Load styles if present
930 xmlstyle = parent->first_node("styles");
931 if (xmlstyle)
932 styles.push_back(xmlstyle);
933
Ethan Yonker780cd392014-07-21 15:24:39 -0500934 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100935 if (child && LoadPages(child))
936 {
937 templates.pop_back();
938 doc->clear();
939 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500940 free(xmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100941 return -1;
942 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500943
Ethan Yonker561c58d2015-10-05 08:48:22 -0500944 if (CheckInclude(package, doc)) {
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500945 doc->clear();
946 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500947 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500948 return -1;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500949 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500950 doc->clear();
951 delete doc;
952 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500953
954 chld = chld->next_sibling("xmlfile");
955 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500956
Ethan Yonker780cd392014-07-21 15:24:39 -0500957 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400958}
959
960int PageSet::SetPage(std::string page)
961{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200962 Page* tmp = FindPage(page);
963 if (tmp)
964 {
965 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
966 mCurrentPage = tmp;
967 mCurrentPage->SetPageFocus(1);
968 mCurrentPage->NotifyVarChange("", "");
969 return 0;
970 }
971 else
972 {
973 LOGERR("Unable to locate page (%s)\n", page.c_str());
974 }
975 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400976}
977
978int PageSet::SetOverlay(Page* page)
979{
Ethan Yonker1c273312015-03-16 12:18:56 -0500980 if (page) {
981 if (mOverlays.size() >= 10) {
982 LOGERR("Too many overlays requested, max is 10.\n");
983 return -1;
984 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500985
986 std::vector<Page*>::iterator iter;
987 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
988 if ((*iter)->GetName() == page->GetName()) {
989 mOverlays.erase(iter);
990 // SetOverlay() is (and should stay) the only function which
991 // adds to mOverlays. Then, each page can appear at most once.
992 break;
993 }
994 }
995
Ethan Yonker1c273312015-03-16 12:18:56 -0500996 page->SetPageFocus(1);
997 page->NotifyVarChange("", "");
998
999 if (!mOverlays.empty())
1000 mOverlays.back()->SetPageFocus(0);
1001
1002 mOverlays.push_back(page);
1003 } else {
1004 if (!mOverlays.empty()) {
1005 mOverlays.back()->SetPageFocus(0);
1006 mOverlays.pop_back();
1007 if (!mOverlays.empty())
1008 mOverlays.back()->SetPageFocus(1);
1009 else if (mCurrentPage)
1010 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
1011 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001012 }
1013 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001014}
1015
that74ac6062015-03-04 22:39:34 +01001016const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001017{
that74ac6062015-03-04 22:39:34 +01001018 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -04001019}
1020
1021Page* PageSet::FindPage(std::string name)
1022{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001023 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001024
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001025 for (iter = mPages.begin(); iter != mPages.end(); iter++)
1026 {
1027 if (name == (*iter)->GetName())
1028 return (*iter);
1029 }
1030 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001031}
1032
1033int PageSet::LoadVariables(xml_node<>* vars)
1034{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001035 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001036 xml_attribute<> *name, *value, *persist;
1037 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001038
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001039 child = vars->first_node("variable");
1040 while (child)
1041 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001042 name = child->first_attribute("name");
1043 value = child->first_attribute("value");
1044 persist = child->first_attribute("persist");
1045 if(name && value)
1046 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001047 if (strcmp(name->value(), "tw_x_offset") == 0) {
1048 tw_x_offset = atoi(value->value());
1049 child = child->next_sibling("variable");
1050 continue;
1051 }
1052 if (strcmp(name->value(), "tw_y_offset") == 0) {
1053 tw_y_offset = atoi(value->value());
1054 child = child->next_sibling("variable");
1055 continue;
1056 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001057 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001058 string temp = value->value();
1059 string valstr = gui_parse_text(temp);
1060
1061 if (valstr.find("+") != string::npos) {
1062 string val1str = valstr;
1063 val1str = val1str.substr(0, val1str.find('+'));
1064 string val2str = valstr;
1065 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1066 int val1 = atoi(val1str.c_str());
1067 int val2 = atoi(val2str.c_str());
1068 int val = val1 + val2;
1069
1070 DataManager::SetValue(name->value(), val, p);
1071 } else if (valstr.find("-") != string::npos) {
1072 string val1str = valstr;
1073 val1str = val1str.substr(0, val1str.find('-'));
1074 string val2str = valstr;
1075 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1076 int val1 = atoi(val1str.c_str());
1077 int val2 = atoi(val2str.c_str());
1078 int val = val1 - val2;
1079
1080 DataManager::SetValue(name->value(), val, p);
1081 } else {
1082 DataManager::SetValue(name->value(), valstr, p);
1083 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001084 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001085
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001086 child = child->next_sibling("variable");
1087 }
1088 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001089}
1090
Ethan Yonker780cd392014-07-21 15:24:39 -05001091int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001092{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001093 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001094
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001095 if (!pages)
1096 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001097
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001098 child = pages->first_node("page");
1099 while (child != NULL)
1100 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001101 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001102 if (page->GetName().empty())
1103 {
1104 LOGERR("Unable to process load page\n");
1105 delete page;
1106 }
1107 else
1108 {
1109 mPages.push_back(page);
1110 }
1111 child = child->next_sibling("page");
1112 }
1113 if (mPages.size() > 0)
1114 return 0;
1115 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001116}
1117
1118int PageSet::IsCurrentPage(Page* page)
1119{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001120 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001121}
1122
that10ae24f2015-12-26 20:53:51 +01001123std::string PageSet::GetCurrentPage() const
1124{
1125 return mCurrentPage ? mCurrentPage->GetName() : "";
1126}
1127
Dees_Troy51a0e822012-09-05 15:24:24 -04001128int PageSet::Render(void)
1129{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001130 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001131
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001132 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1133 if (ret < 0)
1134 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001135
1136 std::vector<Page*>::iterator iter;
1137
1138 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1139 ret = ((*iter) ? (*iter)->Render() : -1);
1140 if (ret < 0)
1141 return ret;
1142 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001143 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001144}
1145
1146int PageSet::Update(void)
1147{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001148 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001149
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001150 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1151 if (ret < 0 || ret > 1)
1152 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001153
1154 std::vector<Page*>::iterator iter;
1155
1156 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1157 ret = ((*iter) ? (*iter)->Update() : -1);
1158 if (ret < 0)
1159 return ret;
1160 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001161 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001162}
1163
1164int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1165{
Ethan Yonker1c273312015-03-16 12:18:56 -05001166 if (!mOverlays.empty())
1167 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001168
1169 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001170}
1171
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001172int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001173{
Ethan Yonker1c273312015-03-16 12:18:56 -05001174 if (!mOverlays.empty())
1175 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001176
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001177 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001178}
1179
that8834a0f2016-01-05 23:29:30 +01001180int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001181{
Ethan Yonker1c273312015-03-16 12:18:56 -05001182 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001183 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001184
that8834a0f2016-01-05 23:29:30 +01001185 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001186}
1187
1188int PageSet::SetKeyBoardFocus(int inFocus)
1189{
Ethan Yonker1c273312015-03-16 12:18:56 -05001190 if (!mOverlays.empty())
1191 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001192
1193 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001194}
1195
1196int PageSet::NotifyVarChange(std::string varName, std::string value)
1197{
Ethan Yonker1c273312015-03-16 12:18:56 -05001198 std::vector<Page*>::iterator iter;
1199
1200 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1201 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001202
1203 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001204}
1205
Ethan Yonker74db1572015-10-28 12:44:49 -05001206void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1207{
1208 mResources->AddStringResource(resource_source, resource_name, value);
1209}
1210
Ethan Yonker561c58d2015-10-05 08:48:22 -05001211char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
1212 size_t len;
1213 char* buffer = NULL;
1214
1215 if (!package) {
1216 // We can try to load the XML directly...
1217 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1218 struct stat st;
1219 if(stat(filename.c_str(),&st) != 0) {
1220 // This isn't always an error, sometimes we request files that don't exist.
1221 return NULL;
1222 }
1223
1224 len = (size_t)st.st_size;
1225
1226 buffer = (char*) malloc(len + 1);
1227 if (!buffer) {
1228 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1229 return NULL;
1230 }
1231
1232 int fd = open(filename.c_str(), O_RDONLY);
1233 if (fd == -1) {
1234 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1235 free(buffer);
1236 return NULL;
1237 }
1238
1239 if (read(fd, buffer, len) < 0) {
1240 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1241 free(buffer);
1242 close(fd);
1243 return NULL;
1244 }
1245 close(fd);
1246 } else {
1247 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
1248 const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
1249 if (zipentry == NULL) {
1250 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1251 return NULL;
1252 }
1253
1254 // Allocate the buffer for the file
1255 len = mzGetZipEntryUncompLen(zipentry);
1256 buffer = (char*) malloc(len + 1);
1257 if (!buffer)
1258 return NULL;
1259
1260 if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
1261 LOGERR("Unable to extract '%s'\n", filename.c_str());
1262 free(buffer);
1263 return NULL;
1264 }
1265 }
1266 // NULL-terminate the string
1267 buffer[len] = 0x00;
1268 return buffer;
1269}
1270
Ethan Yonker74db1572015-10-28 12:44:49 -05001271void PageManager::LoadLanguageListDir(string dir) {
1272 if (!TWFunc::Path_Exists(dir)) {
1273 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1274 return;
1275 }
1276
1277 DIR *d = opendir(dir.c_str());
1278 struct dirent *p;
1279
1280 if (d == NULL) {
1281 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1282 return;
1283 }
1284
1285 while ((p = readdir(d))) {
1286 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1287 continue;
1288
1289 string file = p->d_name;
1290 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1291 continue;
1292 string path = dir + p->d_name;
1293 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1294 struct language_struct language_entry;
1295 language_entry.filename = file_no_extn;
1296 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1297 if (xmlFile == NULL) {
1298 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1299 continue;
1300 }
1301 xml_document<> *doc = new xml_document<>();
1302 doc->parse<0>(xmlFile);
1303
1304 xml_node<>* parent = doc->first_node("language");
1305 if (!parent) {
1306 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1307 } else {
1308 xml_node<>* child = parent->first_node("display");
1309 if (child) {
1310 language_entry.displayvalue = child->value();
1311 } else {
1312 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1313 language_entry.displayvalue = language_entry.filename;
1314 }
1315 Language_List.push_back(language_entry);
1316 }
1317 doc->clear();
1318 delete doc;
1319 free(xmlFile);
1320 }
1321 closedir(d);
1322}
1323
1324void PageManager::LoadLanguageList(ZipArchive* package) {
1325 Language_List.clear();
1326 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1327 TWFunc::removeDir(TWRES "customlanguages", true);
1328 if (package) {
1329 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
1330 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
1331 mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
1332 LoadLanguageListDir(TWRES "customlanguages/");
1333 } else {
1334 LoadLanguageListDir(TWRES "languages/");
1335 }
1336}
1337
1338void PageManager::LoadLanguage(string filename) {
1339 string actual_filename;
1340 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1341 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1342 else
1343 actual_filename = TWRES "languages/" + filename + ".xml";
1344 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1345 if (xmlFile == NULL)
1346 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1347 else {
1348 mCurrentSet->LoadLanguage(xmlFile, NULL);
1349 free(xmlFile);
1350 }
1351 PartitionManager.Translate_Partition_Display_Names();
1352}
1353
Dees_Troy51a0e822012-09-05 15:24:24 -04001354int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1355{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001356 int fd;
1357 ZipArchive zip, *pZip = NULL;
1358 long len;
1359 char* xmlFile = NULL;
Ethan Yonker74db1572015-10-28 12:44:49 -05001360 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001361 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001362 PageSet* pageSet = NULL;
1363 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001364 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001365
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001366 mReloadTheme = false;
1367 mStartPage = startpage;
1368
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001369 // Open the XML file
1370 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001371 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001372 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001373 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001374 tw_x_offset = TW_X_OFFSET;
1375 tw_y_offset = TW_Y_OFFSET;
Ethan Yonker74db1572015-10-28 12:44:49 -05001376 LoadLanguageList(NULL);
1377 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001378 }
1379 else
1380 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001381 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001382 tw_x_offset = 0;
1383 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001384 if (!TWFunc::Path_Exists(package))
1385 return -1;
1386 if (sysMapFile(package.c_str(), &map) != 0) {
1387 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001388 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001389 }
1390 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1391 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1392 sysReleaseMap(&map);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001393 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001394 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001395 pZip = &zip;
Ethan Yonker561c58d2015-10-05 08:48:22 -05001396 package = "ui.xml";
Ethan Yonker74db1572015-10-28 12:44:49 -05001397 LoadLanguageList(pZip);
1398 languageFile = LoadFileToBuffer("languages/en.xml", pZip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001399 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001400 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001401
Ethan Yonker561c58d2015-10-05 08:48:22 -05001402 xmlFile = LoadFileToBuffer(package, pZip);
1403 if (xmlFile == NULL) {
1404 goto error;
1405 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001406
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001407 // Before loading, mCurrentSet must be the loading package so we can find resources
1408 pageSet = mCurrentSet;
1409 mCurrentSet = new PageSet(xmlFile);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001410 ret = mCurrentSet->Load(pZip, xmlFile, languageFile, baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001411 if (languageFile) {
1412 free(languageFile);
1413 languageFile = NULL;
1414 }
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001415 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001416 mCurrentSet->SetPage(startpage);
1417 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001418 } else {
1419 if (ret != TW_THEME_VER_ERR)
1420 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001421 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001422
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001423 mCurrentSet = pageSet;
1424
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001425 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001426 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001427 sysReleaseMap(&map);
1428 }
Ethan Yonker561c58d2015-10-05 08:48:22 -05001429 free(xmlFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001430 if (languageFile)
1431 free(languageFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001432 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001433
1434error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001435 // Sometimes we get here without a real error
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001436 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001437 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001438 sysReleaseMap(&map);
1439 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001440 if (xmlFile)
1441 free(xmlFile);
1442 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001443}
1444
1445PageSet* PageManager::FindPackage(std::string name)
1446{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001447 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001448
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001449 iter = mPageSets.find(name);
1450 if (iter != mPageSets.end())
1451 return (*iter).second;
1452
1453 LOGERR("Unable to locate package %s\n", name.c_str());
1454 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001455}
1456
1457PageSet* PageManager::SelectPackage(std::string name)
1458{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001459 LOGINFO("Switching packages (%s)\n", name.c_str());
1460 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001461
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001462 tmp = FindPackage(name);
1463 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001464 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001465 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001466 mCurrentSet->NotifyVarChange("", "");
1467 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 else
1469 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001470
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001471 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001472}
1473
1474int PageManager::ReloadPackage(std::string name, std::string package)
1475{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001476 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001477
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001478 mReloadTheme = false;
1479
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001480 iter = mPageSets.find(name);
1481 if (iter == mPageSets.end())
1482 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001483
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001484 if(mMouseCursor)
1485 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1486
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001487 PageSet* set = (*iter).second;
1488 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001489
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001490 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001491 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001492 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001493 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1494 return -1;
1495 }
1496 if (mCurrentSet == set)
1497 SelectPackage(name);
1498 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001499 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001500 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001501}
1502
1503void PageManager::ReleasePackage(std::string name)
1504{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001505 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001506
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001507 iter = mPageSets.find(name);
1508 if (iter == mPageSets.end())
1509 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001510
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001511 PageSet* set = (*iter).second;
1512 mPageSets.erase(iter);
1513 delete set;
that235c6482016-01-24 21:59:00 +01001514 if (set == mCurrentSet)
1515 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001516 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001517}
1518
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001519int PageManager::RunReload() {
1520 int ret_val = 0;
1521 std::string theme_path;
1522
1523 if (!mReloadTheme)
1524 return 0;
1525
1526 mReloadTheme = false;
1527 theme_path = DataManager::GetSettingsStoragePath();
1528 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1529 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1530 ret_val = 1;
1531 }
1532
1533 theme_path += "/TWRP/theme/ui.zip";
1534 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1535 {
1536 // Loading the custom theme failed - try loading the stock theme
1537 LOGINFO("Attempting to reload stock theme...\n");
1538 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1539 {
1540 LOGERR("Failed to load base packages.\n");
1541 ret_val = 1;
1542 }
1543 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001544 if (ret_val == 0) {
1545 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1546 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1547 LoadLanguage(DataManager::GetStrValue("tw_language"));
1548 }
1549 }
1550
1551 // This makes the console re-translate
1552 last_message_count = 0;
1553 gConsole.clear();
1554 gConsoleColor.clear();
1555
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001556 return ret_val;
1557}
1558
1559void PageManager::RequestReload() {
1560 mReloadTheme = true;
1561}
1562
Ethan Yonkerafde0982016-01-23 08:55:35 -06001563void PageManager::SetStartPage(const std::string& page_name) {
1564 mStartPage = page_name;
1565}
1566
Dees_Troy51a0e822012-09-05 15:24:24 -04001567int PageManager::ChangePage(std::string name)
1568{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001569 DataManager::SetValue("tw_operation_state", 0);
1570 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1571 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001572}
1573
that10ae24f2015-12-26 20:53:51 +01001574std::string PageManager::GetCurrentPage()
1575{
1576 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1577}
1578
Dees_Troy51a0e822012-09-05 15:24:24 -04001579int PageManager::ChangeOverlay(std::string name)
1580{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001581 if (name.empty())
1582 return mCurrentSet->SetOverlay(NULL);
1583 else
1584 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001585 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001586 return mCurrentSet->SetOverlay(page);
1587 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001588}
1589
that74ac6062015-03-04 22:39:34 +01001590const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001591{
that74ac6062015-03-04 22:39:34 +01001592 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001593}
1594
Dees_Troy51a0e822012-09-05 15:24:24 -04001595int PageManager::IsCurrentPage(Page* page)
1596{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001597 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001598}
1599
1600int PageManager::Render(void)
1601{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001602 if(blankTimer.isScreenOff())
1603 return 0;
1604
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001605 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1606 if(mMouseCursor)
1607 mMouseCursor->Render();
1608 return res;
1609}
1610
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001611HardwareKeyboard *PageManager::GetHardwareKeyboard()
1612{
1613 if(!mHardwareKeyboard)
1614 mHardwareKeyboard = new HardwareKeyboard();
1615 return mHardwareKeyboard;
1616}
1617
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001618xml_node<>* PageManager::FindStyle(std::string name)
1619{
1620 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1621 xml_node<>* node = (*itr)->first_node("style");
1622
1623 while (node) {
1624 if (!node->first_attribute("name"))
1625 continue;
1626
1627 if (name == node->first_attribute("name")->value())
1628 return node;
1629 node = node->next_sibling("style");
1630 }
1631 }
1632 return NULL;
1633}
1634
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001635MouseCursor *PageManager::GetMouseCursor()
1636{
1637 if(!mMouseCursor)
1638 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1639 return mMouseCursor;
1640}
1641
1642void PageManager::LoadCursorData(xml_node<>* node)
1643{
1644 if(!mMouseCursor)
1645 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1646
1647 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001648}
1649
1650int PageManager::Update(void)
1651{
thatfb759d42015-01-11 12:16:53 +01001652 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001653 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001654
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001655 if (RunReload())
1656 return -2;
1657
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001658 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1659
1660 if(mMouseCursor)
1661 {
1662 int c_res = mMouseCursor->Update();
1663 if(c_res > res)
1664 res = c_res;
1665 }
1666 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001667}
1668
1669int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1670{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001671 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001672}
1673
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001674int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001675{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001676 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001677}
1678
that8834a0f2016-01-05 23:29:30 +01001679int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001680{
that8834a0f2016-01-05 23:29:30 +01001681 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001682}
1683
1684int PageManager::SetKeyBoardFocus(int inFocus)
1685{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001686 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001687}
1688
1689int PageManager::NotifyVarChange(std::string varName, std::string value)
1690{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001691 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001692}
1693
Ethan Yonker74db1572015-10-28 12:44:49 -05001694void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1695{
1696 if (mCurrentSet)
1697 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1698}
1699
Dees_Troy51a0e822012-09-05 15:24:24 -04001700extern "C" void gui_notifyVarChange(const char *name, const char* value)
1701{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001702 if (!gGuiRunning)
1703 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001704
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001705 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001706}