blob: 58e99e60c7d58c7023626caeff8f385aff86dd96 [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
thatf6ed8fc2015-02-14 20:23:16 +010073 if (str == "black") return 0;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020074 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
thatf6ed8fc2015-02-14 20:23:16 +0100106std::string LoadAttrString(xml_node<>* element, const char* attrname, const char* defaultvalue)
107{
108 if (!element)
109 return defaultvalue;
110
111 xml_attribute<>* attr = element->first_attribute(attrname);
112 return attr ? attr->value() : defaultvalue;
113}
114
115int LoadAttrInt(xml_node<>* element, const char* attrname, int defaultvalue)
116{
117 string value = LoadAttrString(element, attrname);
118 // resolve variables
119 DataManager::GetValue(value, value);
120 return value.empty() ? defaultvalue : atoi(value.c_str());
121}
122
123int LoadAttrIntScaleX(xml_node<>* element, const char* attrname, int defaultvalue)
124{
125 return scale_theme_x(LoadAttrInt(element, attrname, defaultvalue));
126}
127
128int LoadAttrIntScaleY(xml_node<>* element, const char* attrname, int defaultvalue)
129{
130 return scale_theme_y(LoadAttrInt(element, attrname, defaultvalue));
131}
132
133COLOR LoadAttrColor(xml_node<>* element, const char* attrname, COLOR defaultvalue)
134{
135 string value = LoadAttrString(element, attrname);
136 // resolve variables
137 DataManager::GetValue(value, value);
138 COLOR ret = defaultvalue;
139 if (ConvertStrToColor(value, &ret) == 0)
140 return ret;
141 else
142 return defaultvalue;
143}
144
145FontResource* LoadAttrFont(xml_node<>* element, const char* attrname)
146{
147 std::string name = LoadAttrString(element, attrname, "");
148 if (name.empty())
149 return NULL;
150 else
151 return (FontResource*) PageManager::FindResource(name);
152 // TODO: make resource lookup type-safe
153}
154
155ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname)
156{
157 std::string name = LoadAttrString(element, attrname, "");
158 if (name.empty())
159 return NULL;
160 else
161 return (ImageResource*) PageManager::FindResource(name);
162 // TODO: make resource lookup type-safe
163}
164
165AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname)
166{
167 std::string name = LoadAttrString(element, attrname, "");
168 if (name.empty())
169 return NULL;
170 else
171 return (AnimationResource*) PageManager::FindResource(name);
172 // TODO: make resource lookup type-safe
173}
174
Dees_Troy51a0e822012-09-05 15:24:24 -0400175bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
176{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200177 if (!node)
178 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400179
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200180 if (node->first_attribute("x"))
thatf6ed8fc2015-02-14 20:23:16 +0100181 *x = LoadAttrIntScaleX(node, "x") + tw_x_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400182
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200183 if (node->first_attribute("y"))
thatf6ed8fc2015-02-14 20:23:16 +0100184 *y = LoadAttrIntScaleY(node, "y") + tw_y_offset;
Dees_Troy51a0e822012-09-05 15:24:24 -0400185
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200186 if (w && node->first_attribute("w"))
thatf6ed8fc2015-02-14 20:23:16 +0100187 *w = LoadAttrIntScaleX(node, "w");
Dees_Troy51a0e822012-09-05 15:24:24 -0400188
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200189 if (h && node->first_attribute("h"))
thatf6ed8fc2015-02-14 20:23:16 +0100190 *h = LoadAttrIntScaleY(node, "h");
Dees_Troy51a0e822012-09-05 15:24:24 -0400191
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200192 if (placement && node->first_attribute("placement"))
thatf6ed8fc2015-02-14 20:23:16 +0100193 *placement = (RenderObject::Placement) LoadAttrInt(node, "placement");
Dees_Troy51a0e822012-09-05 15:24:24 -0400194
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200195 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400196}
197
198int ActionObject::SetActionPos(int x, int y, int w, int h)
199{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200200 if (x < 0 || y < 0)
201 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400202
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500203 mActionX = x;
204 mActionY = y;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200205 if (w || h)
206 {
207 mActionW = w;
208 mActionH = h;
209 }
210 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400211}
212
Ethan Yonker780cd392014-07-21 15:24:39 -0500213Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400214{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200215 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400216
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200217 // We can memset the whole structure, because the alpha channel is ignored
218 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400219
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200220 // With NULL, we make a console-only display
221 if (!page)
222 {
223 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400224
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200225 GUIConsole* element = new GUIConsole(NULL);
226 mRenders.push_back(element);
227 mActions.push_back(element);
228 return;
229 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400230
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200231 if (page->first_attribute("name"))
232 mName = page->first_attribute("name")->value();
233 else
234 {
235 LOGERR("No page name attribute found!\n");
236 return;
237 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400238
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200239 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400240
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200241 // This is a recursive routine for template handling
242 ProcessNode(page, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400243
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200244 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400245}
246
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100247Page::~Page()
248{
249 for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
250 delete *itr;
251}
252
Ethan Yonker780cd392014-07-21 15:24:39 -0500253bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */, int depth /* = 0 */)
Dees_Troy51a0e822012-09-05 15:24:24 -0400254{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200255 if (depth == 10)
256 {
257 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
258 return false;
259 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400260
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200261 // Let's retrieve the background value, if any
262 xml_node<>* bg = page->first_node("background");
263 if (bg)
264 {
265 xml_attribute<>* attr = bg->first_attribute("color");
266 if (attr)
267 {
268 std::string color = attr->value();
269 ConvertStrToColor(color, &mBackground);
270 }
271 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400272
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200273 xml_node<>* child;
274 child = page->first_node("object");
275 while (child)
276 {
277 if (!child->first_attribute("type"))
278 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400279
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200280 std::string type = child->first_attribute("type")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400281
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200282 if (type == "text")
283 {
284 GUIText* element = new GUIText(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100285 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200286 mRenders.push_back(element);
287 mActions.push_back(element);
288 }
289 else if (type == "image")
290 {
291 GUIImage* element = new GUIImage(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100292 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200293 mRenders.push_back(element);
294 }
295 else if (type == "fill")
296 {
297 GUIFill* element = new GUIFill(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100298 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200299 mRenders.push_back(element);
300 }
301 else if (type == "action")
302 {
303 GUIAction* element = new GUIAction(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100304 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200305 mActions.push_back(element);
306 }
307 else if (type == "console")
308 {
309 GUIConsole* element = new GUIConsole(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100310 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200311 mRenders.push_back(element);
312 mActions.push_back(element);
313 }
314 else if (type == "button")
315 {
316 GUIButton* element = new GUIButton(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100317 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200318 mRenders.push_back(element);
319 mActions.push_back(element);
320 }
321 else if (type == "checkbox")
322 {
323 GUICheckbox* element = new GUICheckbox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100324 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200325 mRenders.push_back(element);
326 mActions.push_back(element);
327 }
328 else if (type == "fileselector")
329 {
330 GUIFileSelector* element = new GUIFileSelector(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100331 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200332 mRenders.push_back(element);
333 mActions.push_back(element);
334 }
335 else if (type == "animation")
336 {
337 GUIAnimation* element = new GUIAnimation(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100338 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200339 mRenders.push_back(element);
340 }
341 else if (type == "progressbar")
342 {
343 GUIProgressBar* element = new GUIProgressBar(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100344 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200345 mRenders.push_back(element);
346 mActions.push_back(element);
347 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400348 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200349 {
350 GUISlider* element = new GUISlider(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100351 mObjects.push_back(element);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200352 mRenders.push_back(element);
353 mActions.push_back(element);
354 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200355 else if (type == "slidervalue")
356 {
357 GUISliderValue *element = new GUISliderValue(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100358 mObjects.push_back(element);
Vojtech Bocek85932342013-04-01 22:11:33 +0200359 mRenders.push_back(element);
360 mActions.push_back(element);
361 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400362 else if (type == "listbox")
363 {
364 GUIListBox* element = new GUIListBox(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100365 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400366 mRenders.push_back(element);
367 mActions.push_back(element);
368 }
369 else if (type == "keyboard")
370 {
371 GUIKeyboard* element = new GUIKeyboard(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100372 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400373 mRenders.push_back(element);
374 mActions.push_back(element);
375 }
376 else if (type == "input")
377 {
378 GUIInput* element = new GUIInput(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100379 mObjects.push_back(element);
Dees_Troy51a0e822012-09-05 15:24:24 -0400380 mRenders.push_back(element);
381 mActions.push_back(element);
382 mInputs.push_back(element);
383 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500384 else if (type == "partitionlist")
385 {
386 GUIPartitionList* element = new GUIPartitionList(child);
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100387 mObjects.push_back(element);
Dees_Troya13d74f2013-03-24 08:54:55 -0500388 mRenders.push_back(element);
389 mActions.push_back(element);
390 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200391 else if (type == "template")
392 {
393 if (!templates || !child->first_attribute("name"))
394 {
395 LOGERR("Invalid template request.\n");
396 }
397 else
398 {
399 std::string name = child->first_attribute("name")->value();
Ethan Yonker780cd392014-07-21 15:24:39 -0500400 xml_node<>* node;
401 bool node_found = false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400402
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200403 // We need to find the correct template
Ethan Yonker780cd392014-07-21 15:24:39 -0500404 for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
405 node = (*itr)->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400406
Ethan Yonker780cd392014-07-21 15:24:39 -0500407 while (node)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200408 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500409 if (!node->first_attribute("name"))
410 continue;
411
412 if (name == node->first_attribute("name")->value())
413 {
414 if (!ProcessNode(node, templates, depth + 1))
415 return false;
416 else {
417 node_found = true;
418 break;
419 }
420 }
421 if (node_found)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200422 break;
Ethan Yonker780cd392014-07-21 15:24:39 -0500423 node = node->next_sibling("template");
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200424 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200425 }
426 }
427 }
428 else
429 {
430 LOGERR("Unknown object type.\n");
431 }
432 child = child->next_sibling("object");
433 }
434 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400435}
436
437int Page::Render(void)
438{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200439 // Render background
440 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
441 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400442
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200443 // Render remaining objects
444 std::vector<RenderObject*>::iterator iter;
445 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
446 {
447 if ((*iter)->Render())
448 LOGERR("A render request has failed.\n");
449 }
450 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400451}
452
453int Page::Update(void)
454{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200455 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400456
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200457 std::vector<RenderObject*>::iterator iter;
458 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
459 {
460 int ret = (*iter)->Update();
461 if (ret < 0)
462 LOGERR("An update request has failed.\n");
463 else if (ret > retCode)
464 retCode = ret;
465 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400466
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200467 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400468}
469
470int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
471{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200472 // By default, return 1 to ignore further touches if nobody is listening
473 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400474
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200475 // Don't try to handle a lack of handlers
476 if (mActions.size() == 0)
477 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400478
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200479 // We record mTouchStart so we can pass all the touch stream to the same handler
480 if (state == TOUCH_START)
481 {
482 std::vector<ActionObject*>::reverse_iterator iter;
483 // We work backwards, from top-most element to bottom-most element
484 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
485 {
486 if ((*iter)->IsInRegion(x, y))
487 {
488 mTouchStart = (*iter);
489 ret = mTouchStart->NotifyTouch(state, x, y);
490 if (ret >= 0)
491 break;
492 mTouchStart = NULL;
493 }
494 }
495 }
496 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
497 {
498 ret = mTouchStart->NotifyTouch(state, x, y);
499 mTouchStart = NULL;
500 }
501 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
502 {
503 ret = mTouchStart->NotifyTouch(state, x, y);
504 }
505 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400506}
507
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100508int Page::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -0400509{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200510 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400511
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200512 // Don't try to handle a lack of handlers
513 if (mActions.size() == 0)
514 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400515
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100516 int ret = 1;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200517 // We work backwards, from top-most element to bottom-most element
518 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
519 {
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100520 ret = (*iter)->NotifyKey(key, down);
521 if (ret < 0) {
522 LOGERR("An action handler has returned an error\n");
523 ret = 1;
524 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200525 }
Vojtech Bocek0b7fe502014-03-13 17:36:52 +0100526 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400527}
528
529int Page::NotifyKeyboard(int key)
530{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200531 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400532
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200533 // Don't try to handle a lack of handlers
534 if (mInputs.size() == 0)
535 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400536
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200537 // We work backwards, from top-most element to bottom-most element
538 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
539 {
540 int ret = (*iter)->NotifyKeyboard(key);
541 if (ret == 0)
542 return 0;
543 else if (ret < 0)
544 LOGERR("A keyboard handler has returned an error");
545 }
546 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400547}
548
549int Page::SetKeyBoardFocus(int inFocus)
550{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200551 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400552
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200553 // Don't try to handle a lack of handlers
554 if (mInputs.size() == 0)
555 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400556
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200557 // We work backwards, from top-most element to bottom-most element
558 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
559 {
560 int ret = (*iter)->SetInputFocus(inFocus);
561 if (ret == 0)
562 return 0;
563 else if (ret < 0)
564 LOGERR("An input focus handler has returned an error");
565 }
566 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400567}
568
569void Page::SetPageFocus(int inFocus)
570{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200571 // Render remaining objects
572 std::vector<RenderObject*>::iterator iter;
573 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
574 (*iter)->SetPageFocus(inFocus);
575
576 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400577}
578
579int Page::NotifyVarChange(std::string varName, std::string value)
580{
Vojtech Bocek07220562014-02-08 02:05:33 +0100581 std::vector<GUIObject*>::iterator iter;
582 for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200583 {
584 if ((*iter)->NotifyVarChange(varName, value))
585 LOGERR("An action handler errored on NotifyVarChange.\n");
586 }
587 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400588}
589
590PageSet::PageSet(char* xmlFile)
591{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200592 mResources = NULL;
593 mCurrentPage = NULL;
594 mOverlayPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400595
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 mXmlFile = xmlFile;
597 if (xmlFile)
598 mDoc.parse<0>(mXmlFile);
599 else
600 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400601}
602
603PageSet::~PageSet()
604{
Vojtech Bocekbfb63342014-02-08 00:32:31 +0100605 for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
606 delete *itr;
607
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200608 delete mResources;
609 free(mXmlFile);
Vojtech Boceke979abd2015-01-12 18:29:12 +0100610
611 mDoc.clear();
612
613 for (std::vector<xml_document<>*>::iterator itr = mIncludedDocs.begin(); itr != mIncludedDocs.end(); ++itr) {
614 (*itr)->clear();
615 delete *itr;
616 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400617}
618
619int PageSet::Load(ZipArchive* package)
620{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200621 xml_node<>* parent;
622 xml_node<>* child;
Ethan Yonker780cd392014-07-21 15:24:39 -0500623 xml_node<>* xmltemplate;
624 xml_node<>* blank_templates;
625 int pages_loaded = -1, ret;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -0500626
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200627 parent = mDoc.first_node("recovery");
628 if (!parent)
629 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400630
Ethan Yonker63e414f2015-02-06 15:44:39 -0600631 set_scale_values(1, 1); // Reset any previous scaling values
632
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200633 // Now, let's parse the XML
Ethan Yonker63e414f2015-02-06 15:44:39 -0600634 LOGINFO("Checking resolution...\n");
635 child = parent->first_node("details");
636 if (child) {
637 xml_node<>* resolution = child->first_node("resolution");
638 if (resolution) {
639 xml_attribute<>* width_attr = resolution->first_attribute("width");
640 xml_attribute<>* height_attr = resolution->first_attribute("height");
641 xml_attribute<>* noscale_attr = resolution->first_attribute("noscaling");
642 if (width_attr && height_attr && !noscale_attr) {
643 int width = atoi(width_attr->value());
644 int height = atoi(height_attr->value());
645 int offx = 0, offy = 0;
646#ifdef TW_ROUND_SCREEN
647 xml_node<>* roundscreen = child->first_node("roundscreen");
648 if (roundscreen) {
649 LOGINFO("TW_ROUND_SCREEN := true, using round screen XML settings.\n");
650 xml_attribute<>* offx_attr = roundscreen->first_attribute("offset_x");
651 xml_attribute<>* offy_attr = roundscreen->first_attribute("offset_y");
652 if (offx_attr) {
653 offx = atoi(offx_attr->value());
654 }
655 if (offy_attr) {
656 offy = atoi(offy_attr->value());
657 }
658 }
659#endif
660 if (width != 0 && height != 0) {
661 float scale_w = ((float)gr_fb_width() - ((float)offx * 2.0)) / (float)width;
662 float scale_h = ((float)gr_fb_height() - ((float)offy * 2.0)) / (float)height;
663#ifdef TW_ROUND_SCREEN
664 float scale_off_w = (float)gr_fb_width() / (float)width;
665 float scale_off_h = (float)gr_fb_height() / (float)height;
666 tw_x_offset = offx * scale_off_w;
667 tw_y_offset = offy * scale_off_h;
668#endif
669 if (scale_w != 1 || scale_h != 1) {
670 LOGINFO("Scaling theme width %fx and height %fx, offsets x: %i y: %i\n", scale_w, scale_h, tw_x_offset, tw_y_offset);
671 set_scale_values(scale_w, scale_h);
672 }
673 }
674 } else {
675 LOGINFO("XML does not contain width and height, no scaling will be applied\n");
676 }
677 } else {
678 LOGINFO("XML contains no resolution tag, no scaling will be applied.\n");
679 }
680 } else {
681 LOGINFO("XML contains no details tag, no scaling will be applied.\n");
682 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200683 LOGINFO("Loading resources...\n");
684 child = parent->first_node("resources");
685 if (child)
686 mResources = new ResourceManager(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400687
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200688 LOGINFO("Loading variables...\n");
689 child = parent->first_node("variables");
690 if (child)
691 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400692
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +0100693 LOGINFO("Loading mouse cursor...\n");
694 child = parent->first_node("mousecursor");
695 if(child)
696 PageManager::LoadCursorData(child);
697
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200698 LOGINFO("Loading pages...\n");
699 // This may be NULL if no templates are present
Ethan Yonker780cd392014-07-21 15:24:39 -0500700 xmltemplate = parent->first_node("templates");
701 if (xmltemplate)
702 templates.push_back(xmltemplate);
Dees_Troy51a0e822012-09-05 15:24:24 -0400703
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200704 child = parent->first_node("pages");
Ethan Yonker780cd392014-07-21 15:24:39 -0500705 if (child) {
706 if (LoadPages(child)) {
707 LOGERR("PageSet::Load returning -1\n");
708 return -1;
709 }
710 }
Vojtech Boceke979abd2015-01-12 18:29:12 +0100711
Ethan Yonker780cd392014-07-21 15:24:39 -0500712 return CheckInclude(package, &mDoc);
713}
Dees_Troy51a0e822012-09-05 15:24:24 -0400714
Ethan Yonker780cd392014-07-21 15:24:39 -0500715int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
716{
717 xml_node<>* par;
718 xml_node<>* par2;
719 xml_node<>* chld;
720 xml_node<>* parent;
721 xml_node<>* child;
722 xml_node<>* xmltemplate;
723 long len;
724 char* xmlFile = NULL;
725 string filename;
Vojtech Boceke979abd2015-01-12 18:29:12 +0100726 xml_document<> *doc = NULL;
Ethan Yonker780cd392014-07-21 15:24:39 -0500727
728 par = parentDoc->first_node("recovery");
729 if (!par) {
730 par = parentDoc->first_node("install");
731 }
732 if (!par) {
733 return 0;
734 }
735
736 par2 = par->first_node("include");
737 if (!par2)
738 return 0;
739 chld = par2->first_node("xmlfile");
740 while (chld != NULL) {
741 xml_attribute<>* attr = chld->first_attribute("name");
742 if (!attr)
743 break;
744
Ethan Yonker780cd392014-07-21 15:24:39 -0500745 if (!package) {
746 // We can try to load the XML directly...
Dees Troy3454ade2015-01-20 19:21:04 +0000747 filename = TWRES;
Ethan Yonker780cd392014-07-21 15:24:39 -0500748 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000749 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500750 struct stat st;
751 if(stat(filename.c_str(),&st) != 0) {
752 LOGERR("Unable to locate '%s'\n", filename.c_str());
753 return -1;
754 }
755
756 len = st.st_size;
757 xmlFile = (char*) malloc(len + 1);
758 if (!xmlFile)
759 return -1;
760
761 int fd = open(filename.c_str(), O_RDONLY);
762 if (fd == -1)
763 return -1;
764
765 read(fd, xmlFile, len);
766 close(fd);
767 } else {
768 filename += attr->value();
Dees Troy3454ade2015-01-20 19:21:04 +0000769 LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
Ethan Yonker780cd392014-07-21 15:24:39 -0500770 const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
771 if (ui_xml == NULL)
772 {
773 LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
774 return -1;
775 }
776
777 // Allocate the buffer for the file
778 len = mzGetZipEntryUncompLen(ui_xml);
779 xmlFile = (char*) malloc(len + 1);
780 if (!xmlFile)
781 return -1;
782
783 if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
784 {
785 LOGERR("Unable to extract '%s'\n", filename.c_str());
786 return -1;
787 }
788 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500789
Vojtech Boceke979abd2015-01-12 18:29:12 +0100790 xmlFile[len] = '\0';
791 doc = new xml_document<>();
792 doc->parse<0>(xmlFile);
793
794 parent = doc->first_node("recovery");
Ethan Yonker780cd392014-07-21 15:24:39 -0500795 if (!parent)
Vojtech Boceke979abd2015-01-12 18:29:12 +0100796 parent = doc->first_node("install");
Ethan Yonker780cd392014-07-21 15:24:39 -0500797
798 // Now, let's parse the XML
799 LOGINFO("Loading included resources...\n");
800 child = parent->first_node("resources");
801 if (child)
802 mResources->LoadResources(child, package);
803
804 LOGINFO("Loading included variables...\n");
805 child = parent->first_node("variables");
806 if (child)
807 LoadVariables(child);
808
809 LOGINFO("Loading mouse cursor...\n");
810 child = parent->first_node("mousecursor");
811 if(child)
812 PageManager::LoadCursorData(child);
813
814 LOGINFO("Loading included pages...\n");
815 // This may be NULL if no templates are present
816 xmltemplate = parent->first_node("templates");
817 if (xmltemplate)
818 templates.push_back(xmltemplate);
819
820 child = parent->first_node("pages");
Vojtech Boceke979abd2015-01-12 18:29:12 +0100821 if (child && LoadPages(child))
822 {
823 templates.pop_back();
824 doc->clear();
825 delete doc;
826 return -1;
827 }
Ethan Yonker780cd392014-07-21 15:24:39 -0500828
Vojtech Boceke979abd2015-01-12 18:29:12 +0100829 mIncludedDocs.push_back(doc);
830
831 if (CheckInclude(package, doc))
Ethan Yonker780cd392014-07-21 15:24:39 -0500832 return -1;
833
834 chld = chld->next_sibling("xmlfile");
835 }
836
837 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400838}
839
840int PageSet::SetPage(std::string page)
841{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200842 Page* tmp = FindPage(page);
843 if (tmp)
844 {
845 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
846 mCurrentPage = tmp;
847 mCurrentPage->SetPageFocus(1);
848 mCurrentPage->NotifyVarChange("", "");
849 return 0;
850 }
851 else
852 {
853 LOGERR("Unable to locate page (%s)\n", page.c_str());
854 }
855 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400856}
857
858int PageSet::SetOverlay(Page* page)
859{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200860 if (mOverlayPage) mOverlayPage->SetPageFocus(0);
861 mOverlayPage = page;
862 if (mOverlayPage)
863 {
864 mOverlayPage->SetPageFocus(1);
865 mOverlayPage->NotifyVarChange("", "");
866 }
867 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400868}
869
870Resource* PageSet::FindResource(std::string name)
871{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200872 return mResources ? mResources->FindResource(name) : NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400873}
874
875Page* PageSet::FindPage(std::string name)
876{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200877 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400878
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200879 for (iter = mPages.begin(); iter != mPages.end(); iter++)
880 {
881 if (name == (*iter)->GetName())
882 return (*iter);
883 }
884 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400885}
886
887int PageSet::LoadVariables(xml_node<>* vars)
888{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200889 xml_node<>* child;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100890 xml_attribute<> *name, *value, *persist;
891 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400892
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200893 child = vars->first_node("variable");
894 while (child)
895 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100896 name = child->first_attribute("name");
897 value = child->first_attribute("value");
898 persist = child->first_attribute("persist");
899 if(name && value)
900 {
Ethan Yonker751a85e2014-12-12 16:59:10 -0600901 if (strcmp(name->value(), "tw_x_offset") == 0) {
902 tw_x_offset = atoi(value->value());
903 child = child->next_sibling("variable");
904 continue;
905 }
906 if (strcmp(name->value(), "tw_y_offset") == 0) {
907 tw_y_offset = atoi(value->value());
908 child = child->next_sibling("variable");
909 continue;
910 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100911 p = persist ? atoi(persist->value()) : 0;
Ethan Yonker96acb3d2014-08-05 09:20:30 -0500912 string temp = value->value();
913 string valstr = gui_parse_text(temp);
914
915 if (valstr.find("+") != string::npos) {
916 string val1str = valstr;
917 val1str = val1str.substr(0, val1str.find('+'));
918 string val2str = valstr;
919 val2str = val2str.substr(val2str.find('+') + 1, string::npos);
920 int val1 = atoi(val1str.c_str());
921 int val2 = atoi(val2str.c_str());
922 int val = val1 + val2;
923
924 DataManager::SetValue(name->value(), val, p);
925 } else if (valstr.find("-") != string::npos) {
926 string val1str = valstr;
927 val1str = val1str.substr(0, val1str.find('-'));
928 string val2str = valstr;
929 val2str = val2str.substr(val2str.find('-') + 1, string::npos);
930 int val1 = atoi(val1str.c_str());
931 int val2 = atoi(val2str.c_str());
932 int val = val1 - val2;
933
934 DataManager::SetValue(name->value(), val, p);
935 } else {
936 DataManager::SetValue(name->value(), valstr, p);
937 }
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100938 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400939
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200940 child = child->next_sibling("variable");
941 }
942 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400943}
944
Ethan Yonker780cd392014-07-21 15:24:39 -0500945int PageSet::LoadPages(xml_node<>* pages)
Dees_Troy51a0e822012-09-05 15:24:24 -0400946{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200947 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -0400948
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200949 if (!pages)
950 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400951
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200952 child = pages->first_node("page");
953 while (child != NULL)
954 {
Ethan Yonker780cd392014-07-21 15:24:39 -0500955 Page* page = new Page(child, &templates);
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200956 if (page->GetName().empty())
957 {
958 LOGERR("Unable to process load page\n");
959 delete page;
960 }
961 else
962 {
963 mPages.push_back(page);
964 }
965 child = child->next_sibling("page");
966 }
967 if (mPages.size() > 0)
968 return 0;
969 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400970}
971
972int PageSet::IsCurrentPage(Page* page)
973{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200974 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400975}
976
977int PageSet::Render(void)
978{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200979 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400980
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200981 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
982 if (ret < 0)
983 return ret;
984 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
985 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400986}
987
988int PageSet::Update(void)
989{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200990 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400991
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200992 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
993 if (ret < 0 || ret > 1)
994 return ret;
995 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
996 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400997}
998
999int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
1000{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001001 if (mOverlayPage)
1002 return (mOverlayPage->NotifyTouch(state, x, y));
1003
1004 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001005}
1006
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001007int PageSet::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001008{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001009 if (mOverlayPage)
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001010 return (mOverlayPage->NotifyKey(key, down));
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001011
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001012 return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001013}
1014
1015int PageSet::NotifyKeyboard(int key)
1016{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001017 if (mOverlayPage)
1018 return (mOverlayPage->NotifyKeyboard(key));
1019
1020 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001021}
1022
1023int PageSet::SetKeyBoardFocus(int inFocus)
1024{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001025 if (mOverlayPage)
1026 return (mOverlayPage->SetKeyBoardFocus(inFocus));
1027
1028 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001029}
1030
1031int PageSet::NotifyVarChange(std::string varName, std::string value)
1032{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001033 if (mOverlayPage)
1034 mOverlayPage->NotifyVarChange(varName, value);
1035
1036 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001037}
1038
1039int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
1040{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001041 int fd;
1042 ZipArchive zip, *pZip = NULL;
1043 long len;
1044 char* xmlFile = NULL;
1045 PageSet* pageSet = NULL;
1046 int ret;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001047 MemMapping map;
Dees_Troy51a0e822012-09-05 15:24:24 -04001048
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001049 // Open the XML file
1050 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001051 if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001052 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001053 LOGINFO("Load XML directly\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001054 tw_x_offset = TW_X_OFFSET;
1055 tw_y_offset = TW_Y_OFFSET;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001056 // We can try to load the XML directly...
1057 struct stat st;
1058 if(stat(package.c_str(),&st) != 0)
1059 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001060
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001061 len = st.st_size;
1062 xmlFile = (char*) malloc(len + 1);
1063 if (!xmlFile)
1064 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001065
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001066 fd = open(package.c_str(), O_RDONLY);
1067 if (fd == -1)
1068 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -04001069
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001070 read(fd, xmlFile, len);
1071 close(fd);
1072 }
1073 else
1074 {
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001075 LOGINFO("Loading zip theme\n");
Ethan Yonker751a85e2014-12-12 16:59:10 -06001076 tw_x_offset = 0;
1077 tw_y_offset = 0;
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001078 if (!TWFunc::Path_Exists(package))
1079 return -1;
1080 if (sysMapFile(package.c_str(), &map) != 0) {
1081 LOGERR("Failed to map '%s'\n", package.c_str());
1082 return -1;
1083 }
1084 if (mzOpenZipArchive(map.addr, map.length, &zip)) {
1085 LOGERR("Unable to open zip archive '%s'\n", package.c_str());
1086 sysReleaseMap(&map);
1087 return -1;
1088 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001089 pZip = &zip;
1090 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
1091 if (ui_xml == NULL)
1092 {
1093 LOGERR("Unable to locate ui.xml in zip file\n");
1094 goto error;
1095 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001096
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001097 // Allocate the buffer for the file
1098 len = mzGetZipEntryUncompLen(ui_xml);
1099 xmlFile = (char*) malloc(len + 1);
1100 if (!xmlFile)
1101 goto error;
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001102
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001103 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
1104 {
1105 LOGERR("Unable to extract ui.xml\n");
1106 goto error;
1107 }
1108 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001109
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001110 // NULL-terminate the string
1111 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -04001112
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001113 // Before loading, mCurrentSet must be the loading package so we can find resources
1114 pageSet = mCurrentSet;
1115 mCurrentSet = new PageSet(xmlFile);
1116
1117 ret = mCurrentSet->Load(pZip);
1118 if (ret == 0)
1119 {
1120 mCurrentSet->SetPage(startpage);
1121 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
1122 }
1123 else
1124 {
1125 LOGERR("Package %s failed to load.\n", name.c_str());
1126 }
Matt Mowerfb1c4ff2014-04-16 13:43:36 -05001127
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001128 // The first successful package we loaded is the base
1129 if (mBaseSet == NULL)
1130 mBaseSet = mCurrentSet;
1131
1132 mCurrentSet = pageSet;
1133
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001134 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001135 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001136 sysReleaseMap(&map);
1137 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001138 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001139
1140error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001141 LOGERR("An internal error has occurred.\n");
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001142 if (pZip) {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001143 mzCloseZipArchive(pZip);
Ethan Yonkera2dc2f22014-11-08 08:13:40 -06001144 sysReleaseMap(&map);
1145 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001146 if (xmlFile)
1147 free(xmlFile);
1148 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001149}
1150
1151PageSet* PageManager::FindPackage(std::string name)
1152{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001153 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001154
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001155 iter = mPageSets.find(name);
1156 if (iter != mPageSets.end())
1157 return (*iter).second;
1158
1159 LOGERR("Unable to locate package %s\n", name.c_str());
1160 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -04001161}
1162
1163PageSet* PageManager::SelectPackage(std::string name)
1164{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001165 LOGINFO("Switching packages (%s)\n", name.c_str());
1166 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001167
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001168 tmp = FindPackage(name);
1169 if (tmp)
Vojtech Bocek07220562014-02-08 02:05:33 +01001170 {
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001171 mCurrentSet = tmp;
Vojtech Bocek07220562014-02-08 02:05:33 +01001172 mCurrentSet->NotifyVarChange("", "");
1173 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001174 else
1175 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -04001176
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001177 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -04001178}
1179
1180int PageManager::ReloadPackage(std::string name, std::string package)
1181{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001182 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001183
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001184 iter = mPageSets.find(name);
1185 if (iter == mPageSets.end())
1186 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -04001187
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001188 if(mMouseCursor)
1189 mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
1190
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001191 PageSet* set = (*iter).second;
1192 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -04001193
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001194 if (LoadPackage(name, package, "main") != 0)
1195 {
Dees Troy3454ade2015-01-20 19:21:04 +00001196 LOGERR("Failed to load package '%s'.\n", package.c_str());
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001197 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
1198 return -1;
1199 }
1200 if (mCurrentSet == set)
1201 SelectPackage(name);
Vojtech Bocekbfb63342014-02-08 00:32:31 +01001202 if (mBaseSet == set)
1203 mBaseSet = mCurrentSet;
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001204 delete set;
1205 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001206}
1207
1208void PageManager::ReleasePackage(std::string name)
1209{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001210 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -04001211
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001212 iter = mPageSets.find(name);
1213 if (iter == mPageSets.end())
1214 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001215
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001216 PageSet* set = (*iter).second;
1217 mPageSets.erase(iter);
1218 delete set;
1219 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001220}
1221
1222int PageManager::ChangePage(std::string name)
1223{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001224 DataManager::SetValue("tw_operation_state", 0);
1225 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
1226 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -04001227}
1228
1229int PageManager::ChangeOverlay(std::string name)
1230{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001231 if (name.empty())
1232 return mCurrentSet->SetOverlay(NULL);
1233 else
1234 {
1235 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
1236 return mCurrentSet->SetOverlay(page);
1237 }
Dees_Troy51a0e822012-09-05 15:24:24 -04001238}
1239
1240Resource* PageManager::FindResource(std::string name)
1241{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001242 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001243}
1244
1245Resource* PageManager::FindResource(std::string package, std::string name)
1246{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001247 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -04001248
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001249 tmp = FindPackage(name);
1250 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001251}
1252
1253int PageManager::SwitchToConsole(void)
1254{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001255 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -04001256
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001257 mCurrentSet = console;
1258 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -04001259}
1260
Ethan Yonker03a42f62014-08-08 11:03:51 -05001261int PageManager::EndConsole(void)
1262{
1263 if (mCurrentSet && mBaseSet) {
1264 delete mCurrentSet;
1265 mCurrentSet = mBaseSet;
1266 return 0;
1267 }
1268 return -1;
1269}
1270
Dees_Troy51a0e822012-09-05 15:24:24 -04001271int PageManager::IsCurrentPage(Page* page)
1272{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001273 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -04001274}
1275
1276int PageManager::Render(void)
1277{
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001278 int res = (mCurrentSet ? mCurrentSet->Render() : -1);
1279 if(mMouseCursor)
1280 mMouseCursor->Render();
1281 return res;
1282}
1283
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001284HardwareKeyboard *PageManager::GetHardwareKeyboard()
1285{
1286 if(!mHardwareKeyboard)
1287 mHardwareKeyboard = new HardwareKeyboard();
1288 return mHardwareKeyboard;
1289}
1290
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001291MouseCursor *PageManager::GetMouseCursor()
1292{
1293 if(!mMouseCursor)
1294 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1295 return mMouseCursor;
1296}
1297
1298void PageManager::LoadCursorData(xml_node<>* node)
1299{
1300 if(!mMouseCursor)
1301 mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
1302
1303 mMouseCursor->LoadData(node);
Dees_Troy51a0e822012-09-05 15:24:24 -04001304}
1305
1306int PageManager::Update(void)
1307{
thatfb759d42015-01-11 12:16:53 +01001308 if(blankTimer.isScreenOff())
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001309 return 0;
Vojtech Bocek1fc30fc2014-01-29 18:37:19 +01001310
1311 int res = (mCurrentSet ? mCurrentSet->Update() : -1);
1312
1313 if(mMouseCursor)
1314 {
1315 int c_res = mMouseCursor->Update();
1316 if(c_res > res)
1317 res = c_res;
1318 }
1319 return res;
Dees_Troy51a0e822012-09-05 15:24:24 -04001320}
1321
1322int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
1323{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001324 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001325}
1326
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001327int PageManager::NotifyKey(int key, bool down)
Dees_Troy51a0e822012-09-05 15:24:24 -04001328{
Vojtech Bocek0b7fe502014-03-13 17:36:52 +01001329 return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001330}
1331
1332int PageManager::NotifyKeyboard(int key)
1333{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001334 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001335}
1336
1337int PageManager::SetKeyBoardFocus(int inFocus)
1338{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001339 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001340}
1341
1342int PageManager::NotifyVarChange(std::string varName, std::string value)
1343{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001344 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -04001345}
1346
1347extern "C" void gui_notifyVarChange(const char *name, const char* value)
1348{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001349 if (!gGuiRunning)
1350 return;
Dees_Troy51a0e822012-09-05 15:24:24 -04001351
Vojtech Bocekfafb0c52013-07-25 22:53:02 +02001352 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -04001353}