blob: 47e2edde885d4a2b832cbc24ad9ac535d7eaa02b [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"
Dees_Troy51a0e822012-09-05 15:24:24 -040036
37#include <string>
38
39extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000040#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040041#include "../minuitwrp/minui.h"
Ethan Yonkera2dc2f22014-11-08 08:13:40 -060042#include "../minzip/SysUtil.h"
43#include "../minzip/Zip.h"
Ethan Yonker63e414f2015-02-06 15:44:39 -060044#include "gui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040045}
46
47#include "rapidxml.hpp"
48#include "objects.hpp"
gordon13370d9133d2013-06-08 14:17:07 +020049#include "blanktimer.hpp"
Dees_Troy51a0e822012-09-05 15:24:24 -040050
51extern int gGuiRunning;
52
53std::map<std::string, PageSet*> PageManager::mPageSets;
54PageSet* PageManager::mCurrentSet;
55PageSet* PageManager::mBaseSet = NULL;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +010056MouseCursor *PageManager::mMouseCursor = NULL;
Vojtech Bocek0b7fe502014-03-13 17:36:52 +010057HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -040058
Ethan Yonker751a85e2014-12-12 16:59:10 -060059int tw_x_offset = 0;
60int tw_y_offset = 0;
61
Dees_Troy51a0e822012-09-05 15:24:24 -040062// Helper routine to convert a string to a color declaration
63int ConvertStrToColor(std::string str, COLOR* color)
64{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020065 // Set the default, solid black
66 memset(color, 0, sizeof(COLOR));
67 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040068
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020069 // Translate variables
70 DataManager::GetValue(str, str);
Matt Mowerfb1c4ff2014-04-16 13:43:36 -050071
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020072 // Look for some defaults
73 if (str == "black") return 0;
74 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
75 else if (str == "red") { color->red = 255; return 0; }
76 else if (str == "green") { color->green = 255; return 0; }
77 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040078
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020079 // At this point, we require an RGB(A) color
80 if (str[0] != '#')
81 return -1;
82
83 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040084
Dees_Troy30b962e2012-10-19 20:48:59 -040085 int result;
86 if (str.size() >= 8) {
87 // We have alpha channel
88 string alpha = str.substr(6, 2);
89 result = strtol(alpha.c_str(), NULL, 16);
90 color->alpha = result & 0x000000FF;
91 str.resize(6);
92 result = strtol(str.c_str(), NULL, 16);
93 color->red = (result >> 16) & 0x000000FF;
94 color->green = (result >> 8) & 0x000000FF;
95 color->blue = result & 0x000000FF;
96 } else {
97 result = strtol(str.c_str(), NULL, 16);
98 color->red = (result >> 16) & 0x000000FF;
99 color->green = (result >> 8) & 0x000000FF;
100 color->blue = result & 0x000000FF;
101 }
102 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400103}
104
105// Helper APIs
106bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
107{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200108 if (!node)
109 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400110
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200111 std::string value;
112 if (node->first_attribute("x"))
113 {
114 value = node->first_attribute("x")->value();
115 DataManager::GetValue(value, value);
116 *x = atol(value.c_str());
Ethan Yonker63e414f2015-02-06 15:44:39 -0600117 *x = scale_theme_x(*x);
Ethan Yonker751a85e2014-12-12 16:59:10 -0600118 *x += tw_x_offset;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200119 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400120
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200121 if (node->first_attribute("y"))
122 {
123 value = node->first_attribute("y")->value();
124 DataManager::GetValue(value, value);
125 *y = atol(value.c_str());
Ethan Yonker63e414f2015-02-06 15:44:39 -0600126 *y = scale_theme_y(*y);
Ethan Yonker751a85e2014-12-12 16:59:10 -0600127 *y += tw_y_offset;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200128 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400129
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200130 if (w && node->first_attribute("w"))
131 {
132 value = node->first_attribute("w")->value();
133 DataManager::GetValue(value, value);
134 *w = atol(value.c_str());
Ethan Yonker63e414f2015-02-06 15:44:39 -0600135 *w = scale_theme_x(*w);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200136 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400137
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200138 if (h && node->first_attribute("h"))
139 {
140 value = node->first_attribute("h")->value();
141 DataManager::GetValue(value, value);
142 *h = atol(value.c_str());
Ethan Yonker63e414f2015-02-06 15:44:39 -0600143 *h = scale_theme_y(*h);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200144 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400145
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200146 if (placement && node->first_attribute("placement"))
147 {
148 value = node->first_attribute("placement")->value();
149 DataManager::GetValue(value, value);
150 *placement = (RenderObject::Placement) atol(value.c_str());
151 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400152
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200153 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400154}
155
156int ActionObject::SetActionPos(int x, int y, int w, int h)
157{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200158 if (x < 0 || y < 0)
159 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400160
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500161 mActionX = x;
162 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200163 if (w || h)
164 {
165 mActionW = w;
166 mActionH = h;
167 }
168 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400169}
170
Ethan Yonker780cd392014-07-21 15:24:39 -0500171Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400172{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200173 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400174
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200175 // We can memset the whole structure, because the alpha channel is ignored
176 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400177
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200178 // With NULL, we make a console-only display
179 if (!page)
180 {
181 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400182
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200183 GUIConsole* element = new GUIConsole(NULL);
184 mRenders.push_back(element);
185 mActions.push_back(element);
186 return;
187 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400188
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200189 if (page->first_attribute("name"))
190 mName = page->first_attribute("name")->value();
191 else
192 {
193 LOGERR("No page name attribute found!\n");
194 return;
195 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400196
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200197 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400198
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200199 // This is a recursive routine for template handling
200 ProcessNode(page, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400201
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200202 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400203}
204
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100205Page::~Page()
206{
207 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
208 delete *itr;
209}
210
Ethan Yonker780cd392014-07-21 15:24:39 -0500211bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */, int depth /* = 0 */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400212{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200213 if (depth == 10)
214 {
215 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
216 return false;
217 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400218
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200219 // Let's retrieve the background value, if any
220 xml_node<>* bg = page->first_node("background");
221 if (bg)
222 {
223 xml_attribute<>* attr = bg->first_attribute("color");
224 if (attr)
225 {
226 std::string color = attr->value();
227 ConvertStrToColor(color, &mBackground);
228 }
229 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400230
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200231 xml_node<>* child;
232 child = page->first_node("object");
233 while (child)
234 {
235 if (!child->first_attribute("type"))
236 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400237
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200238 std::string type = child->first_attribute("type")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400239
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200240 if (type == "text")
241 {
242 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100243 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200244 mRenders.push_back(element);
245 mActions.push_back(element);
246 }
247 else if (type == "image")
248 {
249 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100250 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200251 mRenders.push_back(element);
252 }
253 else if (type == "fill")
254 {
255 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100256 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200257 mRenders.push_back(element);
258 }
259 else if (type == "action")
260 {
261 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100262 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200263 mActions.push_back(element);
264 }
265 else if (type == "console")
266 {
267 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100268 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200269 mRenders.push_back(element);
270 mActions.push_back(element);
271 }
272 else if (type == "button")
273 {
274 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100275 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200276 mRenders.push_back(element);
277 mActions.push_back(element);
278 }
279 else if (type == "checkbox")
280 {
281 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100282 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200283 mRenders.push_back(element);
284 mActions.push_back(element);
285 }
286 else if (type == "fileselector")
287 {
288 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100289 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200290 mRenders.push_back(element);
291 mActions.push_back(element);
292 }
293 else if (type == "animation")
294 {
295 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100296 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200297 mRenders.push_back(element);
298 }
299 else if (type == "progressbar")
300 {
301 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100302 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200303 mRenders.push_back(element);
304 mActions.push_back(element);
305 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400306 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200307 {
308 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100309 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200310 mRenders.push_back(element);
311 mActions.push_back(element);
312 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200313 else if (type == "slidervalue")
314 {
315 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100316 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200317 mRenders.push_back(element);
318 mActions.push_back(element);
319 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400320 else if (type == "listbox")
321 {
322 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100323 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400324 mRenders.push_back(element);
325 mActions.push_back(element);
326 }
327 else if (type == "keyboard")
328 {
329 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100330 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400331 mRenders.push_back(element);
332 mActions.push_back(element);
333 }
334 else if (type == "input")
335 {
336 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100337 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400338 mRenders.push_back(element);
339 mActions.push_back(element);
340 mInputs.push_back(element);
341 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500342 else if (type == "partitionlist")
343 {
344 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100345 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500346 mRenders.push_back(element);
347 mActions.push_back(element);
348 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 else if (type == "template")
350 {
351 if (!templates || !child->first_attribute("name"))
352 {
353 LOGERR("Invalid template request.\n");
354 }
355 else
356 {
357 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500358 xml_node<>* node;
359 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400360
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200361 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500362 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
363 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400364
Ethan Yonker780cd392014-07-21 15:24:39 -0500365 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200366 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500367 if (!node->first_attribute("name"))
368 continue;
369
370 if (name == node->first_attribute("name")->value())
371 {
372 if (!ProcessNode(node, templates, depth + 1))
373 return false;
374 else {
375 node_found = true;
376 break;
377 }
378 }
379 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200380 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500381 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200382 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200383 }
384 }
385 }
386 else
387 {
388 LOGERR("Unknown object type.\n");
389 }
390 child = child->next_sibling("object");
391 }
392 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400393}
394
395int Page::Render(void)
396{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200397 // Render background
398 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
399 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400400
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200401 // Render remaining objects
402 std::vector<RenderObject*>::iterator iter;
403 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
404 {
405 if ((*iter)->Render())
406 LOGERR("A render request has failed.\n");
407 }
408 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400409}
410
411int Page::Update(void)
412{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200413 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400414
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200415 std::vector<RenderObject*>::iterator iter;
416 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
417 {
418 int ret = (*iter)->Update();
419 if (ret < 0)
420 LOGERR("An update request has failed.\n");
421 else if (ret > retCode)
422 retCode = ret;
423 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400424
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200425 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400426}
427
428int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
429{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200430 // By default, return 1 to ignore further touches if nobody is listening
431 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400432
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200433 // Don't try to handle a lack of handlers
434 if (mActions.size() == 0)
435 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400436
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200437 // We record mTouchStart so we can pass all the touch stream to the same handler
438 if (state == TOUCH_START)
439 {
440 std::vector<ActionObject*>::reverse_iterator iter;
441 // We work backwards, from top-most element to bottom-most element
442 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
443 {
444 if ((*iter)->IsInRegion(x, y))
445 {
446 mTouchStart = (*iter);
447 ret = mTouchStart->NotifyTouch(state, x, y);
448 if (ret >= 0)
449 break;
450 mTouchStart = NULL;
451 }
452 }
453 }
454 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
455 {
456 ret = mTouchStart->NotifyTouch(state, x, y);
457 mTouchStart = NULL;
458 }
459 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
460 {
461 ret = mTouchStart->NotifyTouch(state, x, y);
462 }
463 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400464}
465
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100466int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400467{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200468 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400469
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200470 // Don't try to handle a lack of handlers
471 if (mActions.size() == 0)
472 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400473
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100474 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200475 // We work backwards, from top-most element to bottom-most element
476 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
477 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100478 ret = (*iter)->NotifyKey(key, down);
479 if (ret < 0) {
480 LOGERR("An action handler has returned an error\n");
481 ret = 1;
482 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200483 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100484 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400485}
486
487int Page::NotifyKeyboard(int key)
488{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200489 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400490
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200491 // Don't try to handle a lack of handlers
492 if (mInputs.size() == 0)
493 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400494
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200495 // We work backwards, from top-most element to bottom-most element
496 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
497 {
498 int ret = (*iter)->NotifyKeyboard(key);
499 if (ret == 0)
500 return 0;
501 else if (ret < 0)
502 LOGERR("A keyboard handler has returned an error");
503 }
504 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400505}
506
507int Page::SetKeyBoardFocus(int inFocus)
508{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200509 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400510
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200511 // Don't try to handle a lack of handlers
512 if (mInputs.size() == 0)
513 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400514
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 // We work backwards, from top-most element to bottom-most element
516 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
517 {
518 int ret = (*iter)->SetInputFocus(inFocus);
519 if (ret == 0)
520 return 0;
521 else if (ret < 0)
522 LOGERR("An input focus handler has returned an error");
523 }
524 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400525}
526
527void Page::SetPageFocus(int inFocus)
528{
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 (*iter)->SetPageFocus(inFocus);
533
534 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400535}
536
537int Page::NotifyVarChange(std::string varName, std::string value)
538{
Vojtech Bocek07220562014-02-08 02:05:33 +0100539 std::vector<GUIObject*>::iterator iter;
540 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200541 {
542 if ((*iter)->NotifyVarChange(varName, value))
543 LOGERR("An action handler errored on NotifyVarChange.\n");
544 }
545 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400546}
547
548PageSet::PageSet(char* xmlFile)
549{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200550 mResources = NULL;
551 mCurrentPage = NULL;
552 mOverlayPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400553
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200554 mXmlFile = xmlFile;
555 if (xmlFile)
556 mDoc.parse<0>(mXmlFile);
557 else
558 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400559}
560
561PageSet::~PageSet()
562{
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100563 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
564 delete *itr;
565
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200566 delete mResources;
567 free(mXmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100568
569 mDoc.clear();
570
571 for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
572 (*itr)->clear();
573 delete *itr;
574 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400575}
576
577int PageSet::Load(ZipArchive* package)
578{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200579 xml_node<>* parent;
580 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500581 xml_node<>* xmltemplate;
582 xml_node<>* blank_templates;
583 int pages_loaded = -1, ret;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500584
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200585 parent = mDoc.first_node("recovery");
586 if (!parent)
587 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400588
Ethan Yonker63e414f2015-02-06 15:44:39 -0600589 set_scale_values(1, 1); // Reset any previous scaling values
590
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200591 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600592 LOGINFO("Checking resolution...\n");
593 child = parent->first_node("details");
594 if (child) {
595 xml_node<>* resolution = child->first_node("resolution");
596 if (resolution) {
597 xml_attribute<>* width_attr = resolution->first_attribute("width");
598 xml_attribute<>* height_attr = resolution->first_attribute("height");
599 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
600 if (width_attr && height_attr && !noscale_attr) {
601 int width = atoi(width_attr->value());
602 int height = atoi(height_attr->value());
603 int offx = 0, offy = 0;
604#ifdef TW_ROUND_SCREEN
605 xml_node<>* roundscreen = child->first_node("roundscreen");
606 if (roundscreen) {
607 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
608 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
609 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
610 if (offx_attr) {
611 offx = atoi(offx_attr->value());
612 }
613 if (offy_attr) {
614 offy = atoi(offy_attr->value());
615 }
616 }
617#endif
618 if (width != 0 && height != 0) {
619 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
620 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
621#ifdef TW_ROUND_SCREEN
622 float scale_off_w = (float)gr_fb_width() / (float)width;
623 float scale_off_h = (float)gr_fb_height() / (float)height;
624 tw_x_offset = offx * scale_off_w;
625 tw_y_offset = offy * scale_off_h;
626#endif
627 if (scale_w != 1 || scale_h != 1) {
628 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
629 set_scale_values(scale_w, scale_h);
630 }
631 }
632 } else {
633 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
634 }
635 } else {
636 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
637 }
638 } else {
639 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
640 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200641 LOGINFO("Loading resources...\n");
642 child = parent->first_node("resources");
643 if (child)
644 mResources = new ResourceManager(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400645
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200646 LOGINFO("Loading variables...\n");
647 child = parent->first_node("variables");
648 if (child)
649 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400650
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100651 LOGINFO("Loading mouse cursor...\n");
652 child = parent->first_node("mousecursor");
653 if(child)
654 PageManager::LoadCursorData(child);
655
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200656 LOGINFO("Loading pages...\n");
657 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500658 xmltemplate = parent->first_node("templates");
659 if (xmltemplate)
660 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400661
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200662 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500663 if (child) {
664 if (LoadPages(child)) {
665 LOGERR("PageSet::Load returning -1\n");
666 return -1;
667 }
668 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100669
Ethan Yonker780cd392014-07-21 15:24:39 -0500670 return CheckInclude(package, &mDoc);
671}
Dees_Troy51a0e822012-09-05 15:24:24 -0400672
Ethan Yonker780cd392014-07-21 15:24:39 -0500673int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
674{
675 xml_node<>* par;
676 xml_node<>* par2;
677 xml_node<>* chld;
678 xml_node<>* parent;
679 xml_node<>* child;
680 xml_node<>* xmltemplate;
681 long len;
682 char* xmlFile = NULL;
683 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100684 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500685
686 par = parentDoc->first_node("recovery");
687 if (!par) {
688 par = parentDoc->first_node("install");
689 }
690 if (!par) {
691 return 0;
692 }
693
694 par2 = par->first_node("include");
695 if (!par2)
696 return 0;
697 chld = par2->first_node("xmlfile");
698 while (chld != NULL) {
699 xml_attribute<>* attr = chld->first_attribute("name");
700 if (!attr)
701 break;
702
Ethan Yonker780cd392014-07-21 15:24:39 -0500703 if (!package) {
704 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000705 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500706 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000707 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500708 struct stat st;
709 if(stat(filename.c_str(),&st) != 0) {
710 LOGERR("Unable to locate '%s'\n", filename.c_str());
711 return -1;
712 }
713
714 len = st.st_size;
715 xmlFile = (char*) malloc(len + 1);
716 if (!xmlFile)
717 return -1;
718
719 int fd = open(filename.c_str(), O_RDONLY);
720 if (fd == -1)
721 return -1;
722
723 read(fd, xmlFile, len);
724 close(fd);
725 } else {
726 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000727 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500728 const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
729 if (ui_xml == NULL)
730 {
731 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
732 return -1;
733 }
734
735 // Allocate the buffer for the file
736 len = mzGetZipEntryUncompLen(ui_xml);
737 xmlFile = (char*) malloc(len + 1);
738 if (!xmlFile)
739 return -1;
740
741 if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
742 {
743 LOGERR("Unable to extract '%s'\n", filename.c_str());
744 return -1;
745 }
746 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500747
Vojtech Boceke979abd2015-01-12 18:29:12 +0100748 xmlFile[len] = '\0';
749 doc = new xml_document<>();
750 doc->parse<0>(xmlFile);
751
752 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500753 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100754 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500755
756 // Now, let's parse the XML
757 LOGINFO("Loading included resources...\n");
758 child = parent->first_node("resources");
759 if (child)
760 mResources->LoadResources(child, package);
761
762 LOGINFO("Loading included variables...\n");
763 child = parent->first_node("variables");
764 if (child)
765 LoadVariables(child);
766
767 LOGINFO("Loading mouse cursor...\n");
768 child = parent->first_node("mousecursor");
769 if(child)
770 PageManager::LoadCursorData(child);
771
772 LOGINFO("Loading included pages...\n");
773 // This may be NULL if no templates are present
774 xmltemplate = parent->first_node("templates");
775 if (xmltemplate)
776 templates.push_back(xmltemplate);
777
778 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100779 if (child && LoadPages(child))
780 {
781 templates.pop_back();
782 doc->clear();
783 delete doc;
784 return -1;
785 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500786
Vojtech Boceke979abd2015-01-12 18:29:12 +0100787 mIncludedDocs.push_back(doc);
788
789 if (CheckInclude(package, doc))
Ethan Yonker780cd392014-07-21 15:24:39 -0500790 return -1;
791
792 chld = chld->next_sibling("xmlfile");
793 }
794
795 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400796}
797
798int PageSet::SetPage(std::string page)
799{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200800 Page* tmp = FindPage(page);
801 if (tmp)
802 {
803 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
804 mCurrentPage = tmp;
805 mCurrentPage->SetPageFocus(1);
806 mCurrentPage->NotifyVarChange("", "");
807 return 0;
808 }
809 else
810 {
811 LOGERR("Unable to locate page (%s)\n", page.c_str());
812 }
813 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400814}
815
816int PageSet::SetOverlay(Page* page)
817{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200818 if (mOverlayPage) mOverlayPage->SetPageFocus(0);
819 mOverlayPage = page;
820 if (mOverlayPage)
821 {
822 mOverlayPage->SetPageFocus(1);
823 mOverlayPage->NotifyVarChange("", "");
824 }
825 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400826}
827
828Resource* PageSet::FindResource(std::string name)
829{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200830 return mResources ? mResources->FindResource(name) : NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400831}
832
833Page* PageSet::FindPage(std::string name)
834{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200835 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400836
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200837 for (iter = mPages.begin(); iter != mPages.end(); iter++)
838 {
839 if (name == (*iter)->GetName())
840 return (*iter);
841 }
842 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400843}
844
845int PageSet::LoadVariables(xml_node<>* vars)
846{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200847 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100848 xml_attribute<> *name, *value, *persist;
849 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400850
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200851 child = vars->first_node("variable");
852 while (child)
853 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100854 name = child->first_attribute("name");
855 value = child->first_attribute("value");
856 persist = child->first_attribute("persist");
857 if(name && value)
858 {
Ethan Yonker751a85e2014-12-12 16:59:10 -0600859 if (strcmp(name->value(), "tw_x_offset") == 0) {
860 tw_x_offset = atoi(value->value());
861 child = child->next_sibling("variable");
862 continue;
863 }
864 if (strcmp(name->value(), "tw_y_offset") == 0) {
865 tw_y_offset = atoi(value->value());
866 child = child->next_sibling("variable");
867 continue;
868 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100869 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -0500870 string temp = value->value();
871 string valstr = gui_parse_text(temp);
872
873 if (valstr.find("+") != string::npos) {
874 string val1str = valstr;
875 val1str = val1str.substr(0, val1str.find('+'));
876 string val2str = valstr;
877 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
878 int val1 = atoi(val1str.c_str());
879 int val2 = atoi(val2str.c_str());
880 int val = val1 + val2;
881
882 DataManager::SetValue(name->value(), val, p);
883 } else if (valstr.find("-") != string::npos) {
884 string val1str = valstr;
885 val1str = val1str.substr(0, val1str.find('-'));
886 string val2str = valstr;
887 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
888 int val1 = atoi(val1str.c_str());
889 int val2 = atoi(val2str.c_str());
890 int val = val1 - val2;
891
892 DataManager::SetValue(name->value(), val, p);
893 } else {
894 DataManager::SetValue(name->value(), valstr, p);
895 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100896 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400897
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200898 child = child->next_sibling("variable");
899 }
900 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400901}
902
Ethan Yonker780cd392014-07-21 15:24:39 -0500903int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -0400904{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200905 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -0400906
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200907 if (!pages)
908 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400909
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200910 child = pages->first_node("page");
911 while (child != NULL)
912 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500913 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200914 if (page->GetName().empty())
915 {
916 LOGERR("Unable to process load page\n");
917 delete page;
918 }
919 else
920 {
921 mPages.push_back(page);
922 }
923 child = child->next_sibling("page");
924 }
925 if (mPages.size() > 0)
926 return 0;
927 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400928}
929
930int PageSet::IsCurrentPage(Page* page)
931{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200932 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400933}
934
935int PageSet::Render(void)
936{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200937 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400938
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200939 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
940 if (ret < 0)
941 return ret;
942 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
943 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400944}
945
946int PageSet::Update(void)
947{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200948 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400949
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200950 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
951 if (ret < 0 || ret > 1)
952 return ret;
953 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
954 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400955}
956
957int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
958{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200959 if (mOverlayPage)
960 return (mOverlayPage->NotifyTouch(state, x, y));
961
962 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400963}
964
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100965int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400966{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200967 if (mOverlayPage)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100968 return (mOverlayPage->NotifyKey(key, down));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200969
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100970 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400971}
972
973int PageSet::NotifyKeyboard(int key)
974{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200975 if (mOverlayPage)
976 return (mOverlayPage->NotifyKeyboard(key));
977
978 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400979}
980
981int PageSet::SetKeyBoardFocus(int inFocus)
982{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200983 if (mOverlayPage)
984 return (mOverlayPage->SetKeyBoardFocus(inFocus));
985
986 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400987}
988
989int PageSet::NotifyVarChange(std::string varName, std::string value)
990{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200991 if (mOverlayPage)
992 mOverlayPage->NotifyVarChange(varName, value);
993
994 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400995}
996
997int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
998{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200999 int fd;
1000 ZipArchive zip, *pZip = NULL;
1001 long len;
1002 char* xmlFile = NULL;
1003 PageSet* pageSet = NULL;
1004 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001005 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001006
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001007 // Open the XML file
1008 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001009 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001010 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001011 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001012 tw_x_offset = TW_X_OFFSET;
1013 tw_y_offset = TW_Y_OFFSET;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001014 // We can try to load the XML directly...
1015 struct stat st;
1016 if(stat(package.c_str(),&st) != 0)
1017 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001018
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001019 len = st.st_size;
1020 xmlFile = (char*) malloc(len + 1);
1021 if (!xmlFile)
1022 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001023
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001024 fd = open(package.c_str(), O_RDONLY);
1025 if (fd == -1)
1026 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -04001027
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001028 read(fd, xmlFile, len);
1029 close(fd);
1030 }
1031 else
1032 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001033 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001034 tw_x_offset = 0;
1035 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001036 if (!TWFunc::Path_Exists(package))
1037 return -1;
1038 if (sysMapFile(package.c_str(), &map) != 0) {
1039 LOGERR("Failed to map '%s'\n", package.c_str());
1040 return -1;
1041 }
1042 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1043 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1044 sysReleaseMap(&map);
1045 return -1;
1046 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001047 pZip = &zip;
1048 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
1049 if (ui_xml == NULL)
1050 {
1051 LOGERR("Unable to locate ui.xml in zip file\n");
1052 goto error;
1053 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001054
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001055 // Allocate the buffer for the file
1056 len = mzGetZipEntryUncompLen(ui_xml);
1057 xmlFile = (char*) malloc(len + 1);
1058 if (!xmlFile)
1059 goto error;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001060
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001061 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
1062 {
1063 LOGERR("Unable to extract ui.xml\n");
1064 goto error;
1065 }
1066 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001067
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001068 // NULL-terminate the string
1069 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -04001070
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001071 // Before loading, mCurrentSet must be the loading package so we can find resources
1072 pageSet = mCurrentSet;
1073 mCurrentSet = new PageSet(xmlFile);
1074
1075 ret = mCurrentSet->Load(pZip);
1076 if (ret == 0)
1077 {
1078 mCurrentSet->SetPage(startpage);
1079 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1080 }
1081 else
1082 {
1083 LOGERR("Package %s failed to load.\n", name.c_str());
1084 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001085
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001086 // The first successful package we loaded is the base
1087 if (mBaseSet == NULL)
1088 mBaseSet = mCurrentSet;
1089
1090 mCurrentSet = pageSet;
1091
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001092 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001093 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001094 sysReleaseMap(&map);
1095 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001096 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001097
1098error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001099 LOGERR("An internal error has occurred.\n");
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001100 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001101 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001102 sysReleaseMap(&map);
1103 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001104 if (xmlFile)
1105 free(xmlFile);
1106 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001107}
1108
1109PageSet* PageManager::FindPackage(std::string name)
1110{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001111 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001112
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001113 iter = mPageSets.find(name);
1114 if (iter != mPageSets.end())
1115 return (*iter).second;
1116
1117 LOGERR("Unable to locate package %s\n", name.c_str());
1118 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001119}
1120
1121PageSet* PageManager::SelectPackage(std::string name)
1122{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001123 LOGINFO("Switching packages (%s)\n", name.c_str());
1124 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001125
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001126 tmp = FindPackage(name);
1127 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001128 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001129 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001130 mCurrentSet->NotifyVarChange("", "");
1131 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001132 else
1133 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001134
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001135 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001136}
1137
1138int PageManager::ReloadPackage(std::string name, std::string package)
1139{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001140 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001141
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001142 iter = mPageSets.find(name);
1143 if (iter == mPageSets.end())
1144 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001145
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001146 if(mMouseCursor)
1147 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1148
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001149 PageSet* set = (*iter).second;
1150 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001151
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001152 if (LoadPackage(name, package, "main") != 0)
1153 {
Dees Troy3454ade2015-01-20 19:21:04 +00001154 LOGERR("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001155 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1156 return -1;
1157 }
1158 if (mCurrentSet == set)
1159 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001160 if (mBaseSet == set)
1161 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001162 delete set;
1163 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001164}
1165
1166void PageManager::ReleasePackage(std::string name)
1167{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001168 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001169
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001170 iter = mPageSets.find(name);
1171 if (iter == mPageSets.end())
1172 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001173
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001174 PageSet* set = (*iter).second;
1175 mPageSets.erase(iter);
1176 delete set;
1177 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001178}
1179
1180int PageManager::ChangePage(std::string name)
1181{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001182 DataManager::SetValue("tw_operation_state", 0);
1183 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1184 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001185}
1186
1187int PageManager::ChangeOverlay(std::string name)
1188{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001189 if (name.empty())
1190 return mCurrentSet->SetOverlay(NULL);
1191 else
1192 {
1193 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1194 return mCurrentSet->SetOverlay(page);
1195 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001196}
1197
1198Resource* PageManager::FindResource(std::string name)
1199{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001200 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001201}
1202
1203Resource* PageManager::FindResource(std::string package, std::string name)
1204{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001205 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001206
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001207 tmp = FindPackage(name);
1208 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001209}
1210
1211int PageManager::SwitchToConsole(void)
1212{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001213 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001214
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001215 mCurrentSet = console;
1216 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001217}
1218
Ethan Yonker03a42f62014-08-08 11:03:51 -05001219int PageManager::EndConsole(void)
1220{
1221 if (mCurrentSet && mBaseSet) {
1222 delete mCurrentSet;
1223 mCurrentSet = mBaseSet;
1224 return 0;
1225 }
1226 return -1;
1227}
1228
Dees_Troy51a0e822012-09-05 15:24:24 -04001229int PageManager::IsCurrentPage(Page* page)
1230{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001231 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001232}
1233
1234int PageManager::Render(void)
1235{
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001236 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1237 if(mMouseCursor)
1238 mMouseCursor->Render();
1239 return res;
1240}
1241
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001242HardwareKeyboard *PageManager::GetHardwareKeyboard()
1243{
1244 if(!mHardwareKeyboard)
1245 mHardwareKeyboard = new HardwareKeyboard();
1246 return mHardwareKeyboard;
1247}
1248
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001249MouseCursor *PageManager::GetMouseCursor()
1250{
1251 if(!mMouseCursor)
1252 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1253 return mMouseCursor;
1254}
1255
1256void PageManager::LoadCursorData(xml_node<>* node)
1257{
1258 if(!mMouseCursor)
1259 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1260
1261 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001262}
1263
1264int PageManager::Update(void)
1265{
thatfb759d42015-01-11 12:16:53 +01001266 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001267 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001268
1269 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1270
1271 if(mMouseCursor)
1272 {
1273 int c_res = mMouseCursor->Update();
1274 if(c_res > res)
1275 res = c_res;
1276 }
1277 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001278}
1279
1280int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1281{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001282 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001283}
1284
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001285int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001286{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001287 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001288}
1289
1290int PageManager::NotifyKeyboard(int key)
1291{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001292 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001293}
1294
1295int PageManager::SetKeyBoardFocus(int inFocus)
1296{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001297 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001298}
1299
1300int PageManager::NotifyVarChange(std::string varName, std::string value)
1301{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001302 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001303}
1304
1305extern "C" void gui_notifyVarChange(const char *name, const char* value)
1306{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001307 if (!gGuiRunning)
1308 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001309
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001310 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001311}