blob: cfe306773be97ffff5e5c561777e87247162a159 [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>
Xuefercac6ace2016-02-01 02:28:55 +080039#include <algorithm>
Dees_Troy51a0e822012-09-05 15:24:24 -040040
41extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000042#include "../twcommon.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}
Ethan Yonkerfbb43532015-12-28 21:54:50 +010047#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040048
49#include "rapidxml.hpp"
50#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020051#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040052
Ethan Yonker1308d532016-01-14 22:21:49 -060053#define TW_THEME_VERSION 1
Ethan Yonker8e5692f2016-01-21 11:21:06 -060054#define TW_THEME_VER_ERR -2
Ethan Yonker1308d532016-01-14 22:21:49 -060055
Dees_Troy51a0e822012-09-05 15:24:24 -040056extern int gGuiRunning;
57
Ethan Yonker74db1572015-10-28 12:44:49 -050058// From ../twrp.cpp
59extern bool datamedia;
60
61// From console.cpp
62extern size_t last_message_count;
63extern std::vector<std::string> gConsole;
64extern std::vector<std::string> gConsoleColor;
65
Dees_Troy51a0e822012-09-05 15:24:24 -040066std::map<std::string, PageSet*> PageManager::mPageSets;
67PageSet* PageManager::mCurrentSet;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010068MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010069HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -050070bool PageManager::mReloadTheme = false;
71std::string PageManager::mStartPage = "main";
Ethan Yonker74db1572015-10-28 12:44:49 -050072std::vector<language_struct> Language_List;
Dees_Troy51a0e822012-09-05 15:24:24 -040073
Ethan Yonker751a85e2014-12-12 16:59:10 -060074int tw_x_offset = 0;
75int tw_y_offset = 0;
76
Dees_Troy51a0e822012-09-05 15:24:24 -040077// Helper routine to convert a string to a color declaration
78int ConvertStrToColor(std::string str, COLOR* color)
79{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020080 // Set the default, solid black
81 memset(color, 0, sizeof(COLOR));
82 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040083
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020084 // Translate variables
85 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050086
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020087 // Look for some defaults
thatf6ed8fc2015-02-14 20:23:16 +010088 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020089 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
90 else if (str == "red") { color->red = 255; return 0; }
91 else if (str == "green") { color->green = 255; return 0; }
92 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040093
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020094 // At this point, we require an RGB(A) color
95 if (str[0] != '#')
96 return -1;
97
98 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040099
Dees_Troy30b962e2012-10-19 20:48:59 -0400100 int result;
101 if (str.size() >= 8) {
102 // We have alpha channel
103 string alpha = str.substr(6, 2);
104 result = strtol(alpha.c_str(), NULL, 16);
105 color->alpha = result & 0x000000FF;
106 str.resize(6);
107 result = strtol(str.c_str(), NULL, 16);
108 color->red = (result >> 16) & 0x000000FF;
109 color->green = (result >> 8) & 0x000000FF;
110 color->blue = result & 0x000000FF;
111 } else {
112 result = strtol(str.c_str(), NULL, 16);
113 color->red = (result >> 16) & 0x000000FF;
114 color->green = (result >> 8) & 0x000000FF;
115 color->blue = result & 0x000000FF;
116 }
117 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400118}
119
120// Helper APIs
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600121xml_node<>* FindNode(xml_node<>* parent, const char* nodename, int depth /* = 0 */)
122{
that8d46c092015-02-26 01:30:04 +0100123 if (!parent)
124 return NULL;
125
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600126 xml_node<>* child = parent->first_node(nodename);
127 if (child)
128 return child;
129
130 if (depth == 10) {
131 LOGERR("Too many style loops detected.\n");
132 return NULL;
133 }
134
135 xml_node<>* style = parent->first_node("style");
136 if (style) {
137 while (style) {
138 if (!style->first_attribute("name")) {
139 LOGERR("No name given for style.\n");
140 continue;
141 } else {
142 std::string name = style->first_attribute("name")->value();
143 xml_node<>* node = PageManager::FindStyle(name);
144
145 if (node) {
146 // We found the style that was named
147 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
148 if (stylenode)
149 return stylenode;
150 }
151 }
152 style = style->next_sibling("style");
153 }
154 } else {
that54e9c832015-11-04 21:46:01 +0100155 // Search for stylename in the parent node <object type="foo" style="foo2">
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600156 xml_attribute<>* attr = parent->first_attribute("style");
157 // If no style is found anywhere else and the node wasn't found in the object itself
158 // as a special case we will search for a style that uses the same style name as the
159 // object type, so <object type="button"> would search for a style named "button"
160 if (!attr)
161 attr = parent->first_attribute("type");
that54e9c832015-11-04 21:46:01 +0100162 // if there's no attribute type, the object type must be the element name
163 std::string stylename = attr ? attr->value() : parent->name();
164 xml_node<>* node = PageManager::FindStyle(stylename);
165 if (node) {
166 xml_node<>* stylenode = FindNode(node, nodename, depth + 1);
167 if (stylenode)
168 return stylenode;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600169 }
170 }
171 return NULL;
172}
173
thatf6ed8fc2015-02-14 20:23:16 +0100174std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
175{
176 if (!element)
177 return defaultvalue;
178
179 xml_attribute<>* attr = element->first_attribute(attrname);
180 return attr ? attr->value() : defaultvalue;
181}
182
183int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
184{
185 string value = LoadAttrString(element, attrname);
186 // resolve variables
187 DataManager::GetValue(value, value);
188 return value.empty() ? defaultvalue : atoi(value.c_str());
189}
190
191int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
192{
193 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
194}
195
196int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
197{
198 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
199}
200
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600201COLOR LoadAttrColor(xml_node<>* element, const char* attrname, bool* found_color, COLOR defaultvalue)
thatf6ed8fc2015-02-14 20:23:16 +0100202{
203 string value = LoadAttrString(element, attrname);
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600204 *found_color = !value.empty();
thatf6ed8fc2015-02-14 20:23:16 +0100205 // resolve variables
206 DataManager::GetValue(value, value);
207 COLOR ret = defaultvalue;
208 if (ConvertStrToColor(value, &ret) == 0)
209 return ret;
210 else
211 return defaultvalue;
212}
213
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600214COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
215{
216 bool found_color = false;
217 return LoadAttrColor(element, attrname, &found_color, defaultvalue);
218}
219
thatf6ed8fc2015-02-14 20:23:16 +0100220FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
221{
222 std::string name = LoadAttrString(element, attrname, "");
223 if (name.empty())
224 return NULL;
225 else
that74ac6062015-03-04 22:39:34 +0100226 return PageManager::GetResources()->FindFont(name);
thatf6ed8fc2015-02-14 20:23:16 +0100227}
228
229ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
230{
231 std::string name = LoadAttrString(element, attrname, "");
232 if (name.empty())
233 return NULL;
234 else
that74ac6062015-03-04 22:39:34 +0100235 return PageManager::GetResources()->FindImage(name);
thatf6ed8fc2015-02-14 20:23:16 +0100236}
237
238AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
239{
240 std::string name = LoadAttrString(element, attrname, "");
241 if (name.empty())
242 return NULL;
243 else
that74ac6062015-03-04 22:39:34 +0100244 return PageManager::GetResources()->FindAnimation(name);
thatf6ed8fc2015-02-14 20:23:16 +0100245}
246
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500247bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400248{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200249 if (!node)
250 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400251
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200252 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100253 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400254
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100256 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400257
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200258 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100259 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200261 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100262 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400263
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200264 if (placement && node->first_attribute("placement"))
Ethan Yonkerb7a54a32015-10-05 10:16:27 -0500265 *placement = (Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400266
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200267 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400268}
269
270int ActionObject::SetActionPos(int x, int y, int w, int h)
271{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200272 if (x < 0 || y < 0)
273 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400274
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500275 mActionX = x;
276 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200277 if (w || h)
278 {
279 mActionW = w;
280 mActionH = h;
281 }
282 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400283}
284
thatb63e2f92015-06-27 21:35:11 +0200285Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates)
Dees_Troy51a0e822012-09-05 15:24:24 -0400286{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200287 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400288
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200289 // We can memset the whole structure, because the alpha channel is ignored
290 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400291
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200292 // With NULL, we make a console-only display
293 if (!page)
294 {
295 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400296
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200297 GUIConsole* element = new GUIConsole(NULL);
298 mRenders.push_back(element);
299 mActions.push_back(element);
300 return;
301 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400302
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200303 if (page->first_attribute("name"))
304 mName = page->first_attribute("name")->value();
305 else
306 {
307 LOGERR("No page name attribute found!\n");
308 return;
309 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400310
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200311 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400312
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200313 // This is a recursive routine for template handling
thatb63e2f92015-06-27 21:35:11 +0200314 ProcessNode(page, templates, 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400315}
316
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100317Page::~Page()
318{
319 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
320 delete *itr;
321}
322
thatb63e2f92015-06-27 21:35:11 +0200323bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates, int depth)
Dees_Troy51a0e822012-09-05 15:24:24 -0400324{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200325 if (depth == 10)
326 {
327 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
328 return false;
329 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400330
thatb63e2f92015-06-27 21:35:11 +0200331 for (xml_node<>* child = page->first_node(); child; child = child->next_sibling())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200332 {
thatb63e2f92015-06-27 21:35:11 +0200333 std::string type = child->name();
334
335 if (type == "background") {
336 mBackground = LoadAttrColor(child, "color", COLOR(0,0,0,0));
337 continue;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200338 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400339
thatb63e2f92015-06-27 21:35:11 +0200340 if (type == "object") {
341 // legacy format : <object type="...">
342 xml_attribute<>* attr = child->first_attribute("type");
343 type = attr ? attr->value() : "*unspecified*";
344 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400345
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200346 if (type == "text")
347 {
348 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100349 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200350 mRenders.push_back(element);
351 mActions.push_back(element);
352 }
353 else if (type == "image")
354 {
355 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100356 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200357 mRenders.push_back(element);
358 }
359 else if (type == "fill")
360 {
361 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100362 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200363 mRenders.push_back(element);
364 }
365 else if (type == "action")
366 {
367 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100368 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200369 mActions.push_back(element);
370 }
371 else if (type == "console")
372 {
373 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100374 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200375 mRenders.push_back(element);
376 mActions.push_back(element);
377 }
that1964d192016-01-07 00:41:03 +0100378 else if (type == "terminal")
379 {
380 GUITerminal* element = new GUITerminal(child);
381 mObjects.push_back(element);
382 mRenders.push_back(element);
383 mActions.push_back(element);
384 mInputs.push_back(element);
385 }
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)
that8834a0f2016-01-05 23:29:30 +0100624 LOGERR("A char input handler has returned an error");
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)
640 LOGERR("An input focus handler has returned an error");
641 }
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
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500666PageSet::PageSet(const char* xmlFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400667{
that74ac6062015-03-04 22:39:34 +0100668 mResources = new ResourceManager;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200669 mCurrentPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500671 if (!xmlFile)
thatb63e2f92015-06-27 21:35:11 +0200672 mCurrentPage = new Page(NULL, NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400673}
674
675PageSet::~PageSet()
676{
Ethan Yonker1c273312015-03-16 12:18:56 -0500677 mOverlays.clear();
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100678 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
679 delete *itr;
680
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200681 delete mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -0400682}
683
Ethan Yonker74db1572015-10-28 12:44:49 -0500684int PageSet::LoadLanguage(char* languageFile, ZipArchive* package)
685{
686 xml_document<> lang;
687 xml_node<>* parent;
688 xml_node<>* child;
689 std::string resource_source;
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600690 int ret = 0;
Ethan Yonker74db1572015-10-28 12:44:49 -0500691
692 if (languageFile) {
693 printf("parsing languageFile\n");
694 lang.parse<0>(languageFile);
695 printf("parsing languageFile done\n");
696 } else {
697 return -1;
698 }
699
700 parent = lang.first_node("language");
701 if (!parent) {
702 LOGERR("Unable to locate language node in language file.\n");
703 lang.clear();
704 return -1;
705 }
706
707 child = parent->first_node("display");
708 if (child) {
709 DataManager::SetValue("tw_language_display", child->value());
710 resource_source = child->value();
711 } else {
712 LOGERR("language file does not have a display value set\n");
713 DataManager::SetValue("tw_language_display", "Not Set");
714 resource_source = languageFile;
715 }
716
717 child = parent->first_node("resources");
718 if (child)
719 mResources->LoadResources(child, package, resource_source);
720 else
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600721 ret = -1;
722 DataManager::SetValue("tw_backup_name", gui_lookup("auto_generate", "(Auto Generate)"));
Ethan Yonker74db1572015-10-28 12:44:49 -0500723 lang.clear();
Ethan Yonker4adc33e2016-01-22 16:07:11 -0600724 return ret;
Ethan Yonker74db1572015-10-28 12:44:49 -0500725}
726
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600727int PageSet::Load(ZipArchive* package, char* xmlFile, char* languageFile, char* baseLanguageFile)
Dees_Troy51a0e822012-09-05 15:24:24 -0400728{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500729 xml_document<> mDoc;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200730 xml_node<>* parent;
731 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500732 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600733 xml_node<>* xmlstyle;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500734
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500735 mDoc.parse<0>(xmlFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200736 parent = mDoc.first_node("recovery");
737 if (!parent)
738 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400739
Ethan Yonker63e414f2015-02-06 15:44:39 -0600740 set_scale_values(1, 1); // Reset any previous scaling values
741
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600742 if (baseLanguageFile)
743 LoadLanguage(baseLanguageFile, NULL);
744
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200745 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600746 child = parent->first_node("details");
747 if (child) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600748 int theme_ver = 0;
749 xml_node<>* themeversion = child->first_node("themeversion");
750 if (themeversion && themeversion->value()) {
751 theme_ver = atoi(themeversion->value());
752 } else {
753 LOGINFO("No themeversion in theme.\n");
754 }
755 if (theme_ver != TW_THEME_VERSION) {
756 LOGINFO("theme version from xml: %i, expected %i\n", theme_ver, TW_THEME_VERSION);
757 if (package) {
758 gui_err("theme_ver_err=Custom theme version does not match TWRP version. Using stock theme.");
759 mDoc.clear();
Ethan Yonker8e5692f2016-01-21 11:21:06 -0600760 return TW_THEME_VER_ERR;
Ethan Yonker1308d532016-01-14 22:21:49 -0600761 } else {
762 gui_print_color("warning", "Stock theme version does not match TWRP version.\n");
763 }
764 }
Ethan Yonker63e414f2015-02-06 15:44:39 -0600765 xml_node<>* resolution = child->first_node("resolution");
766 if (resolution) {
Ethan Yonker1308d532016-01-14 22:21:49 -0600767 LOGINFO("Checking resolution...\n");
Ethan Yonker63e414f2015-02-06 15:44:39 -0600768 xml_attribute<>* width_attr = resolution->first_attribute("width");
769 xml_attribute<>* height_attr = resolution->first_attribute("height");
770 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
771 if (width_attr && height_attr && !noscale_attr) {
772 int width = atoi(width_attr->value());
773 int height = atoi(height_attr->value());
774 int offx = 0, offy = 0;
775#ifdef TW_ROUND_SCREEN
776 xml_node<>* roundscreen = child->first_node("roundscreen");
777 if (roundscreen) {
778 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
779 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
780 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
781 if (offx_attr) {
782 offx = atoi(offx_attr->value());
783 }
784 if (offy_attr) {
785 offy = atoi(offy_attr->value());
786 }
787 }
788#endif
789 if (width != 0 && height != 0) {
790 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
791 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
792#ifdef TW_ROUND_SCREEN
793 float scale_off_w = (float)gr_fb_width() / (float)width;
794 float scale_off_h = (float)gr_fb_height() / (float)height;
795 tw_x_offset = offx * scale_off_w;
796 tw_y_offset = offy * scale_off_h;
797#endif
798 if (scale_w != 1 || scale_h != 1) {
799 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
800 set_scale_values(scale_w, scale_h);
801 }
802 }
803 } else {
804 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
805 }
806 } else {
807 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
808 }
809 } else {
810 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
811 }
Ethan Yonker74db1572015-10-28 12:44:49 -0500812
813 if (languageFile)
814 LoadLanguage(languageFile, package);
815
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200816 LOGINFO("Loading resources...\n");
817 child = parent->first_node("resources");
818 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500819 mResources->LoadResources(child, package, "theme");
Dees_Troy51a0e822012-09-05 15:24:24 -0400820
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200821 LOGINFO("Loading variables...\n");
822 child = parent->first_node("variables");
823 if (child)
824 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400825
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100826 LOGINFO("Loading mouse cursor...\n");
827 child = parent->first_node("mousecursor");
828 if(child)
829 PageManager::LoadCursorData(child);
830
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200831 LOGINFO("Loading pages...\n");
832 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500833 xmltemplate = parent->first_node("templates");
834 if (xmltemplate)
835 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400836
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600837 // Load styles if present
838 xmlstyle = parent->first_node("styles");
839 if (xmlstyle)
840 styles.push_back(xmlstyle);
841
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200842 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500843 if (child) {
844 if (LoadPages(child)) {
845 LOGERR("PageSet::Load returning -1\n");
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500846 mDoc.clear();
Ethan Yonker780cd392014-07-21 15:24:39 -0500847 return -1;
848 }
849 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100850
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500851 int ret = CheckInclude(package, &mDoc);
852 mDoc.clear();
853 templates.clear();
854 return ret;
Ethan Yonker780cd392014-07-21 15:24:39 -0500855}
Dees_Troy51a0e822012-09-05 15:24:24 -0400856
Ethan Yonker780cd392014-07-21 15:24:39 -0500857int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
858{
859 xml_node<>* par;
860 xml_node<>* par2;
861 xml_node<>* chld;
862 xml_node<>* parent;
863 xml_node<>* child;
864 xml_node<>* xmltemplate;
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600865 xml_node<>* xmlstyle;
Ethan Yonker780cd392014-07-21 15:24:39 -0500866 long len;
867 char* xmlFile = NULL;
868 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100869 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500870
871 par = parentDoc->first_node("recovery");
872 if (!par) {
873 par = parentDoc->first_node("install");
874 }
875 if (!par) {
876 return 0;
877 }
878
879 par2 = par->first_node("include");
880 if (!par2)
881 return 0;
882 chld = par2->first_node("xmlfile");
883 while (chld != NULL) {
884 xml_attribute<>* attr = chld->first_attribute("name");
885 if (!attr)
886 break;
887
Ethan Yonker780cd392014-07-21 15:24:39 -0500888 if (!package) {
889 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000890 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500891 filename += attr->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500892 } else {
893 filename += attr->value();
Ethan Yonker561c58d2015-10-05 08:48:22 -0500894 }
895 xmlFile = PageManager::LoadFileToBuffer(filename, package);
896 if (xmlFile == NULL) {
897 LOGERR("PageSet::CheckInclude unable to load '%s'\n", filename.c_str());
898 return -1;
Ethan Yonker780cd392014-07-21 15:24:39 -0500899 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500900
Vojtech Boceke979abd2015-01-12 18:29:12 +0100901 doc = new xml_document<>();
902 doc->parse<0>(xmlFile);
903
904 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500905 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100906 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500907
908 // Now, let's parse the XML
909 LOGINFO("Loading included resources...\n");
910 child = parent->first_node("resources");
911 if (child)
Ethan Yonker74db1572015-10-28 12:44:49 -0500912 mResources->LoadResources(child, package, "theme");
Ethan Yonker780cd392014-07-21 15:24:39 -0500913
914 LOGINFO("Loading included variables...\n");
915 child = parent->first_node("variables");
916 if (child)
917 LoadVariables(child);
918
919 LOGINFO("Loading mouse cursor...\n");
920 child = parent->first_node("mousecursor");
921 if(child)
922 PageManager::LoadCursorData(child);
923
924 LOGINFO("Loading included pages...\n");
925 // This may be NULL if no templates are present
926 xmltemplate = parent->first_node("templates");
927 if (xmltemplate)
928 templates.push_back(xmltemplate);
929
Ethan Yonker21ff02a2015-02-18 14:35:00 -0600930 // Load styles if present
931 xmlstyle = parent->first_node("styles");
932 if (xmlstyle)
933 styles.push_back(xmlstyle);
934
Ethan Yonker780cd392014-07-21 15:24:39 -0500935 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100936 if (child && LoadPages(child))
937 {
938 templates.pop_back();
939 doc->clear();
940 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500941 free(xmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100942 return -1;
943 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500944
Ethan Yonker561c58d2015-10-05 08:48:22 -0500945 if (CheckInclude(package, doc)) {
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500946 doc->clear();
947 delete doc;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500948 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500949 return -1;
Ethan Yonker561c58d2015-10-05 08:48:22 -0500950 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500951 doc->clear();
952 delete doc;
953 free(xmlFile);
Ethan Yonker780cd392014-07-21 15:24:39 -0500954
955 chld = chld->next_sibling("xmlfile");
956 }
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -0500957
Ethan Yonker780cd392014-07-21 15:24:39 -0500958 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400959}
960
961int PageSet::SetPage(std::string page)
962{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200963 Page* tmp = FindPage(page);
964 if (tmp)
965 {
966 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
967 mCurrentPage = tmp;
968 mCurrentPage->SetPageFocus(1);
969 mCurrentPage->NotifyVarChange("", "");
970 return 0;
971 }
972 else
973 {
974 LOGERR("Unable to locate page (%s)\n", page.c_str());
975 }
976 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400977}
978
979int PageSet::SetOverlay(Page* page)
980{
Ethan Yonker1c273312015-03-16 12:18:56 -0500981 if (page) {
982 if (mOverlays.size() >= 10) {
983 LOGERR("Too many overlays requested, max is 10.\n");
984 return -1;
985 }
Matt Mowerd411f8d2015-04-09 16:04:12 -0500986
987 std::vector<Page*>::iterator iter;
988 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
989 if ((*iter)->GetName() == page->GetName()) {
990 mOverlays.erase(iter);
991 // SetOverlay() is (and should stay) the only function which
992 // adds to mOverlays. Then, each page can appear at most once.
993 break;
994 }
995 }
996
Ethan Yonker1c273312015-03-16 12:18:56 -0500997 page->SetPageFocus(1);
998 page->NotifyVarChange("", "");
999
1000 if (!mOverlays.empty())
1001 mOverlays.back()->SetPageFocus(0);
1002
1003 mOverlays.push_back(page);
1004 } else {
1005 if (!mOverlays.empty()) {
1006 mOverlays.back()->SetPageFocus(0);
1007 mOverlays.pop_back();
1008 if (!mOverlays.empty())
1009 mOverlays.back()->SetPageFocus(1);
1010 else if (mCurrentPage)
1011 mCurrentPage->SetPageFocus(1); // Just in case somehow the regular page lost focus, we'll set it again
1012 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001013 }
1014 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001015}
1016
that74ac6062015-03-04 22:39:34 +01001017const ResourceManager* PageSet::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001018{
that74ac6062015-03-04 22:39:34 +01001019 return mResources;
Dees_Troy51a0e822012-09-05 15:24:24 -04001020}
1021
1022Page* PageSet::FindPage(std::string name)
1023{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001024 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001025
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001026 for (iter = mPages.begin(); iter != mPages.end(); iter++)
1027 {
1028 if (name == (*iter)->GetName())
1029 return (*iter);
1030 }
1031 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001032}
1033
1034int PageSet::LoadVariables(xml_node<>* vars)
1035{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001036 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001037 xml_attribute<> *name, *value, *persist;
1038 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -04001039
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001040 child = vars->first_node("variable");
1041 while (child)
1042 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001043 name = child->first_attribute("name");
1044 value = child->first_attribute("value");
1045 persist = child->first_attribute("persist");
1046 if(name && value)
1047 {
Ethan Yonker751a85e2014-12-12 16:59:10 -06001048 if (strcmp(name->value(), "tw_x_offset") == 0) {
1049 tw_x_offset = atoi(value->value());
1050 child = child->next_sibling("variable");
1051 continue;
1052 }
1053 if (strcmp(name->value(), "tw_y_offset") == 0) {
1054 tw_y_offset = atoi(value->value());
1055 child = child->next_sibling("variable");
1056 continue;
1057 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001058 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -05001059 string temp = value->value();
1060 string valstr = gui_parse_text(temp);
1061
1062 if (valstr.find("+") != string::npos) {
1063 string val1str = valstr;
1064 val1str = val1str.substr(0, val1str.find('+'));
1065 string val2str = valstr;
1066 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
1067 int val1 = atoi(val1str.c_str());
1068 int val2 = atoi(val2str.c_str());
1069 int val = val1 + val2;
1070
1071 DataManager::SetValue(name->value(), val, p);
1072 } else if (valstr.find("-") != string::npos) {
1073 string val1str = valstr;
1074 val1str = val1str.substr(0, val1str.find('-'));
1075 string val2str = valstr;
1076 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
1077 int val1 = atoi(val1str.c_str());
1078 int val2 = atoi(val2str.c_str());
1079 int val = val1 - val2;
1080
1081 DataManager::SetValue(name->value(), val, p);
1082 } else {
1083 DataManager::SetValue(name->value(), valstr, p);
1084 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +01001085 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001086
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001087 child = child->next_sibling("variable");
1088 }
1089 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001090}
1091
Ethan Yonker780cd392014-07-21 15:24:39 -05001092int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -04001093{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001094 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -04001095
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001096 if (!pages)
1097 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001098
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001099 child = pages->first_node("page");
1100 while (child != NULL)
1101 {
Ethan Yonker780cd392014-07-21 15:24:39 -05001102 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001103 if (page->GetName().empty())
1104 {
1105 LOGERR("Unable to process load page\n");
1106 delete page;
1107 }
1108 else
1109 {
1110 mPages.push_back(page);
1111 }
1112 child = child->next_sibling("page");
1113 }
1114 if (mPages.size() > 0)
1115 return 0;
1116 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001117}
1118
1119int PageSet::IsCurrentPage(Page* page)
1120{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001121 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001122}
1123
that10ae24f2015-12-26 20:53:51 +01001124std::string PageSet::GetCurrentPage() const
1125{
1126 return mCurrentPage ? mCurrentPage->GetName() : "";
1127}
1128
Dees_Troy51a0e822012-09-05 15:24:24 -04001129int PageSet::Render(void)
1130{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001131 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001132
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001133 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
1134 if (ret < 0)
1135 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001136
1137 std::vector<Page*>::iterator iter;
1138
1139 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1140 ret = ((*iter) ? (*iter)->Render() : -1);
1141 if (ret < 0)
1142 return ret;
1143 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001144 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001145}
1146
1147int PageSet::Update(void)
1148{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001149 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001150
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001151 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
1152 if (ret < 0 || ret > 1)
1153 return ret;
Ethan Yonker1c273312015-03-16 12:18:56 -05001154
1155 std::vector<Page*>::iterator iter;
1156
1157 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++) {
1158 ret = ((*iter) ? (*iter)->Update() : -1);
1159 if (ret < 0)
1160 return ret;
1161 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001162 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001163}
1164
1165int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1166{
Ethan Yonker1c273312015-03-16 12:18:56 -05001167 if (!mOverlays.empty())
1168 return mOverlays.back()->NotifyTouch(state, x, y);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001169
1170 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001171}
1172
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001173int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001174{
Ethan Yonker1c273312015-03-16 12:18:56 -05001175 if (!mOverlays.empty())
1176 return mOverlays.back()->NotifyKey(key, down);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001177
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001178 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001179}
1180
that8834a0f2016-01-05 23:29:30 +01001181int PageSet::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001182{
Ethan Yonker1c273312015-03-16 12:18:56 -05001183 if (!mOverlays.empty())
that8834a0f2016-01-05 23:29:30 +01001184 return mOverlays.back()->NotifyCharInput(ch);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001185
that8834a0f2016-01-05 23:29:30 +01001186 return (mCurrentPage ? mCurrentPage->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001187}
1188
1189int PageSet::SetKeyBoardFocus(int inFocus)
1190{
Ethan Yonker1c273312015-03-16 12:18:56 -05001191 if (!mOverlays.empty())
1192 return mOverlays.back()->SetKeyBoardFocus(inFocus);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001193
1194 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001195}
1196
1197int PageSet::NotifyVarChange(std::string varName, std::string value)
1198{
Ethan Yonker1c273312015-03-16 12:18:56 -05001199 std::vector<Page*>::iterator iter;
1200
1201 for (iter = mOverlays.begin(); iter != mOverlays.end(); iter++)
1202 (*iter)->NotifyVarChange(varName, value);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001203
1204 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001205}
1206
Ethan Yonker74db1572015-10-28 12:44:49 -05001207void PageSet::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1208{
1209 mResources->AddStringResource(resource_source, resource_name, value);
1210}
1211
Ethan Yonker561c58d2015-10-05 08:48:22 -05001212char* PageManager::LoadFileToBuffer(std::string filename, ZipArchive* package) {
1213 size_t len;
1214 char* buffer = NULL;
1215
1216 if (!package) {
1217 // We can try to load the XML directly...
1218 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' directly\n", filename.c_str());
1219 struct stat st;
1220 if(stat(filename.c_str(),&st) != 0) {
1221 // This isn't always an error, sometimes we request files that don't exist.
1222 return NULL;
1223 }
1224
1225 len = (size_t)st.st_size;
1226
1227 buffer = (char*) malloc(len + 1);
1228 if (!buffer) {
1229 LOGERR("PageManager::LoadFileToBuffer failed to malloc\n");
1230 return NULL;
1231 }
1232
1233 int fd = open(filename.c_str(), O_RDONLY);
1234 if (fd == -1) {
1235 LOGERR("PageManager::LoadFileToBuffer failed to open '%s' - (%s)\n", filename.c_str(), strerror(errno));
1236 free(buffer);
1237 return NULL;
1238 }
1239
1240 if (read(fd, buffer, len) < 0) {
1241 LOGERR("PageManager::LoadFileToBuffer failed to read '%s' - (%s)\n", filename.c_str(), strerror(errno));
1242 free(buffer);
1243 close(fd);
1244 return NULL;
1245 }
1246 close(fd);
1247 } else {
1248 LOGINFO("PageManager::LoadFileToBuffer loading filename: '%s' from zip\n", filename.c_str());
1249 const ZipEntry* zipentry = mzFindZipEntry(package, filename.c_str());
1250 if (zipentry == NULL) {
1251 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
1252 return NULL;
1253 }
1254
1255 // Allocate the buffer for the file
1256 len = mzGetZipEntryUncompLen(zipentry);
1257 buffer = (char*) malloc(len + 1);
1258 if (!buffer)
1259 return NULL;
1260
1261 if (!mzExtractZipEntryToBuffer(package, zipentry, (unsigned char*) buffer)) {
1262 LOGERR("Unable to extract '%s'\n", filename.c_str());
1263 free(buffer);
1264 return NULL;
1265 }
1266 }
1267 // NULL-terminate the string
1268 buffer[len] = 0x00;
1269 return buffer;
1270}
1271
Ethan Yonker74db1572015-10-28 12:44:49 -05001272void PageManager::LoadLanguageListDir(string dir) {
1273 if (!TWFunc::Path_Exists(dir)) {
1274 LOGERR("LoadLanguageListDir '%s' path not found\n", dir.c_str());
1275 return;
1276 }
1277
1278 DIR *d = opendir(dir.c_str());
1279 struct dirent *p;
1280
1281 if (d == NULL) {
1282 LOGERR("LoadLanguageListDir error opening dir: '%s', %s\n", dir.c_str(), strerror(errno));
1283 return;
1284 }
1285
1286 while ((p = readdir(d))) {
1287 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..") || strlen(p->d_name) < 5)
1288 continue;
1289
1290 string file = p->d_name;
1291 if (file.substr(strlen(p->d_name) - 4) != ".xml")
1292 continue;
1293 string path = dir + p->d_name;
1294 string file_no_extn = file.substr(0, strlen(p->d_name) - 4);
1295 struct language_struct language_entry;
1296 language_entry.filename = file_no_extn;
1297 char* xmlFile = PageManager::LoadFileToBuffer(dir + p->d_name, NULL);
1298 if (xmlFile == NULL) {
1299 LOGERR("LoadLanguageListDir unable to load '%s'\n", language_entry.filename.c_str());
1300 continue;
1301 }
1302 xml_document<> *doc = new xml_document<>();
1303 doc->parse<0>(xmlFile);
1304
1305 xml_node<>* parent = doc->first_node("language");
1306 if (!parent) {
1307 LOGERR("Invalid language XML file '%s'\n", language_entry.filename.c_str());
1308 } else {
1309 xml_node<>* child = parent->first_node("display");
1310 if (child) {
1311 language_entry.displayvalue = child->value();
1312 } else {
1313 LOGERR("No display value for '%s'\n", language_entry.filename.c_str());
1314 language_entry.displayvalue = language_entry.filename;
1315 }
1316 Language_List.push_back(language_entry);
1317 }
1318 doc->clear();
1319 delete doc;
1320 free(xmlFile);
1321 }
1322 closedir(d);
1323}
1324
1325void PageManager::LoadLanguageList(ZipArchive* package) {
1326 Language_List.clear();
1327 if (TWFunc::Path_Exists(TWRES "customlanguages"))
1328 TWFunc::removeDir(TWRES "customlanguages", true);
1329 if (package) {
1330 TWFunc::Recursive_Mkdir(TWRES "customlanguages");
1331 struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default
1332 mzExtractRecursive(package, "languages", TWRES "customlanguages/", &timestamp, NULL, NULL, NULL);
1333 LoadLanguageListDir(TWRES "customlanguages/");
1334 } else {
1335 LoadLanguageListDir(TWRES "languages/");
1336 }
Xuefercac6ace2016-02-01 02:28:55 +08001337
1338 std::sort(Language_List.begin(), Language_List.end());
Ethan Yonker74db1572015-10-28 12:44:49 -05001339}
1340
1341void PageManager::LoadLanguage(string filename) {
1342 string actual_filename;
1343 if (TWFunc::Path_Exists(TWRES "customlanguages/" + filename + ".xml"))
1344 actual_filename = TWRES "customlanguages/" + filename + ".xml";
1345 else
1346 actual_filename = TWRES "languages/" + filename + ".xml";
1347 char* xmlFile = PageManager::LoadFileToBuffer(actual_filename, NULL);
1348 if (xmlFile == NULL)
1349 LOGERR("Unable to load '%s'\n", actual_filename.c_str());
1350 else {
1351 mCurrentSet->LoadLanguage(xmlFile, NULL);
1352 free(xmlFile);
1353 }
1354 PartitionManager.Translate_Partition_Display_Names();
1355}
1356
Dees_Troy51a0e822012-09-05 15:24:24 -04001357int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1358{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001359 int fd;
1360 ZipArchive zip, *pZip = NULL;
1361 long len;
1362 char* xmlFile = NULL;
Ethan Yonker74db1572015-10-28 12:44:49 -05001363 char* languageFile = NULL;
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001364 char* baseLanguageFile = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001365 PageSet* pageSet = NULL;
1366 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001367 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001368
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001369 mReloadTheme = false;
1370 mStartPage = startpage;
1371
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001372 // Open the XML file
1373 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001374 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001375 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001376 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001377 tw_x_offset = TW_X_OFFSET;
1378 tw_y_offset = TW_Y_OFFSET;
Ethan Yonker74db1572015-10-28 12:44:49 -05001379 LoadLanguageList(NULL);
1380 languageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001381 }
1382 else
1383 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001384 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001385 tw_x_offset = 0;
1386 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001387 if (!TWFunc::Path_Exists(package))
1388 return -1;
1389 if (sysMapFile(package.c_str(), &map) != 0) {
1390 LOGERR("Failed to map '%s'\n", package.c_str());
Ethan Yonker561c58d2015-10-05 08:48:22 -05001391 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001392 }
1393 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1394 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1395 sysReleaseMap(&map);
Ethan Yonker561c58d2015-10-05 08:48:22 -05001396 goto error;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001397 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001398 pZip = &zip;
Ethan Yonker561c58d2015-10-05 08:48:22 -05001399 package = "ui.xml";
Ethan Yonker74db1572015-10-28 12:44:49 -05001400 LoadLanguageList(pZip);
1401 languageFile = LoadFileToBuffer("languages/en.xml", pZip);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001402 baseLanguageFile = LoadFileToBuffer(TWRES "languages/en.xml", NULL);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001403 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001404
Ethan Yonker561c58d2015-10-05 08:48:22 -05001405 xmlFile = LoadFileToBuffer(package, pZip);
1406 if (xmlFile == NULL) {
1407 goto error;
1408 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001409
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001410 // Before loading, mCurrentSet must be the loading package so we can find resources
1411 pageSet = mCurrentSet;
1412 mCurrentSet = new PageSet(xmlFile);
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001413 ret = mCurrentSet->Load(pZip, xmlFile, languageFile, baseLanguageFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001414 if (languageFile) {
1415 free(languageFile);
1416 languageFile = NULL;
1417 }
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001418 if (ret == 0) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001419 mCurrentSet->SetPage(startpage);
1420 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
Ethan Yonker8e5692f2016-01-21 11:21:06 -06001421 } else {
1422 if (ret != TW_THEME_VER_ERR)
1423 LOGERR("Package %s failed to load.\n", name.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001424 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001425
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001426 mCurrentSet = pageSet;
1427
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001428 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001429 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001430 sysReleaseMap(&map);
1431 }
Ethan Yonker561c58d2015-10-05 08:48:22 -05001432 free(xmlFile);
Ethan Yonker74db1572015-10-28 12:44:49 -05001433 if (languageFile)
1434 free(languageFile);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001435 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001436
1437error:
Ethan Yonker561c58d2015-10-05 08:48:22 -05001438 // Sometimes we get here without a real error
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001439 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001440 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001441 sysReleaseMap(&map);
1442 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001443 if (xmlFile)
1444 free(xmlFile);
1445 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001446}
1447
1448PageSet* PageManager::FindPackage(std::string name)
1449{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001450 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001451
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001452 iter = mPageSets.find(name);
1453 if (iter != mPageSets.end())
1454 return (*iter).second;
1455
1456 LOGERR("Unable to locate package %s\n", name.c_str());
1457 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001458}
1459
1460PageSet* PageManager::SelectPackage(std::string name)
1461{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001462 LOGINFO("Switching packages (%s)\n", name.c_str());
1463 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001464
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001465 tmp = FindPackage(name);
1466 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001467 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001468 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001469 mCurrentSet->NotifyVarChange("", "");
1470 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001471 else
1472 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001473
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001474 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001475}
1476
1477int PageManager::ReloadPackage(std::string name, std::string package)
1478{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001479 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001480
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001481 mReloadTheme = false;
1482
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001483 iter = mPageSets.find(name);
1484 if (iter == mPageSets.end())
1485 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001486
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001487 if(mMouseCursor)
1488 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1489
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001490 PageSet* set = (*iter).second;
1491 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001492
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001493 if (LoadPackage(name, package, mStartPage) != 0)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001494 {
Ethan Yonker74db1572015-10-28 12:44:49 -05001495 LOGINFO("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001496 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1497 return -1;
1498 }
1499 if (mCurrentSet == set)
1500 SelectPackage(name);
1501 delete set;
Ethan Yonker74db1572015-10-28 12:44:49 -05001502 GUIConsole::Translate_Now();
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001503 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001504}
1505
1506void PageManager::ReleasePackage(std::string name)
1507{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001508 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001509
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001510 iter = mPageSets.find(name);
1511 if (iter == mPageSets.end())
1512 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001513
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001514 PageSet* set = (*iter).second;
1515 mPageSets.erase(iter);
1516 delete set;
that235c6482016-01-24 21:59:00 +01001517 if (set == mCurrentSet)
1518 mCurrentSet = NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001519 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001520}
1521
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001522int PageManager::RunReload() {
1523 int ret_val = 0;
1524 std::string theme_path;
1525
1526 if (!mReloadTheme)
1527 return 0;
1528
1529 mReloadTheme = false;
1530 theme_path = DataManager::GetSettingsStoragePath();
1531 if (PartitionManager.Mount_By_Path(theme_path.c_str(), 1) < 0) {
1532 LOGERR("Unable to mount %s during gui_reload_theme function.\n", theme_path.c_str());
1533 ret_val = 1;
1534 }
1535
1536 theme_path += "/TWRP/theme/ui.zip";
1537 if (ret_val != 0 || ReloadPackage("TWRP", theme_path) != 0)
1538 {
1539 // Loading the custom theme failed - try loading the stock theme
1540 LOGINFO("Attempting to reload stock theme...\n");
1541 if (ReloadPackage("TWRP", TWRES "ui.xml"))
1542 {
1543 LOGERR("Failed to load base packages.\n");
1544 ret_val = 1;
1545 }
1546 }
Ethan Yonker74db1572015-10-28 12:44:49 -05001547 if (ret_val == 0) {
1548 if (DataManager::GetStrValue("tw_language") != "en.xml") {
1549 LOGINFO("Loading language '%s'\n", DataManager::GetStrValue("tw_language").c_str());
1550 LoadLanguage(DataManager::GetStrValue("tw_language"));
1551 }
1552 }
1553
1554 // This makes the console re-translate
1555 last_message_count = 0;
1556 gConsole.clear();
1557 gConsoleColor.clear();
1558
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001559 return ret_val;
1560}
1561
1562void PageManager::RequestReload() {
1563 mReloadTheme = true;
1564}
1565
Ethan Yonkerafde0982016-01-23 08:55:35 -06001566void PageManager::SetStartPage(const std::string& page_name) {
1567 mStartPage = page_name;
1568}
1569
Dees_Troy51a0e822012-09-05 15:24:24 -04001570int PageManager::ChangePage(std::string name)
1571{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001572 DataManager::SetValue("tw_operation_state", 0);
1573 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1574 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001575}
1576
that10ae24f2015-12-26 20:53:51 +01001577std::string PageManager::GetCurrentPage()
1578{
1579 return mCurrentSet ? mCurrentSet->GetCurrentPage() : "";
1580}
1581
Dees_Troy51a0e822012-09-05 15:24:24 -04001582int PageManager::ChangeOverlay(std::string name)
1583{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001584 if (name.empty())
1585 return mCurrentSet->SetOverlay(NULL);
1586 else
1587 {
Ethan Yonker1308d532016-01-14 22:21:49 -06001588 Page* page = mCurrentSet ? mCurrentSet->FindPage(name) : NULL;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001589 return mCurrentSet->SetOverlay(page);
1590 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001591}
1592
that74ac6062015-03-04 22:39:34 +01001593const ResourceManager* PageManager::GetResources()
Dees_Troy51a0e822012-09-05 15:24:24 -04001594{
that74ac6062015-03-04 22:39:34 +01001595 return (mCurrentSet ? mCurrentSet->GetResources() : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001596}
1597
Dees_Troy51a0e822012-09-05 15:24:24 -04001598int PageManager::IsCurrentPage(Page* page)
1599{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001600 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001601}
1602
1603int PageManager::Render(void)
1604{
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001605 if(blankTimer.isScreenOff())
1606 return 0;
1607
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001608 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1609 if(mMouseCursor)
1610 mMouseCursor->Render();
1611 return res;
1612}
1613
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001614HardwareKeyboard *PageManager::GetHardwareKeyboard()
1615{
1616 if(!mHardwareKeyboard)
1617 mHardwareKeyboard = new HardwareKeyboard();
1618 return mHardwareKeyboard;
1619}
1620
Ethan Yonker21ff02a2015-02-18 14:35:00 -06001621xml_node<>* PageManager::FindStyle(std::string name)
1622{
1623 for (std::vector<xml_node<>*>::iterator itr = mCurrentSet->styles.begin(); itr != mCurrentSet->styles.end(); itr++) {
1624 xml_node<>* node = (*itr)->first_node("style");
1625
1626 while (node) {
1627 if (!node->first_attribute("name"))
1628 continue;
1629
1630 if (name == node->first_attribute("name")->value())
1631 return node;
1632 node = node->next_sibling("style");
1633 }
1634 }
1635 return NULL;
1636}
1637
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001638MouseCursor *PageManager::GetMouseCursor()
1639{
1640 if(!mMouseCursor)
1641 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1642 return mMouseCursor;
1643}
1644
1645void PageManager::LoadCursorData(xml_node<>* node)
1646{
1647 if(!mMouseCursor)
1648 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1649
1650 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001651}
1652
1653int PageManager::Update(void)
1654{
thatfb759d42015-01-11 12:16:53 +01001655 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001656 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001657
Ethan Yonkere0f1f3b2015-10-27 09:49:01 -05001658 if (RunReload())
1659 return -2;
1660
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001661 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1662
1663 if(mMouseCursor)
1664 {
1665 int c_res = mMouseCursor->Update();
1666 if(c_res > res)
1667 res = c_res;
1668 }
1669 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001670}
1671
1672int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1673{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001674 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001675}
1676
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001677int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001678{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001679 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001680}
1681
that8834a0f2016-01-05 23:29:30 +01001682int PageManager::NotifyCharInput(int ch)
Dees_Troy51a0e822012-09-05 15:24:24 -04001683{
that8834a0f2016-01-05 23:29:30 +01001684 return (mCurrentSet ? mCurrentSet->NotifyCharInput(ch) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001685}
1686
1687int PageManager::SetKeyBoardFocus(int inFocus)
1688{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001689 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001690}
1691
1692int PageManager::NotifyVarChange(std::string varName, std::string value)
1693{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001694 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001695}
1696
Ethan Yonker74db1572015-10-28 12:44:49 -05001697void PageManager::AddStringResource(std::string resource_source, std::string resource_name, std::string value)
1698{
1699 if (mCurrentSet)
1700 mCurrentSet->AddStringResource(resource_source, resource_name, value);
1701}
1702
Dees_Troy51a0e822012-09-05 15:24:24 -04001703extern "C" void gui_notifyVarChange(const char *name, const char* value)
1704{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001705 if (!gGuiRunning)
1706 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001707
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001708 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001709}