blob: d02dd216da0791a0157cf6a30cd6cbe6b96fe905 [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>
35
36#include <string>
37
38extern "C" {
Dees_Troy2673cec2013-04-02 20:22:16 +000039#include "../twcommon.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040040#include "../minuitwrp/minui.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040041}
42
43#include "rapidxml.hpp"
44#include "objects.hpp"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070045#ifndef TW_NO_SCREEN_TIMEOUT
gordon13370d9133d2013-06-08 14:17:07 +020046#include "blanktimer.hpp"
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070047#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040048
49extern int gGuiRunning;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070050#ifndef TW_NO_SCREEN_TIMEOUT
gordon13370d9133d2013-06-08 14:17:07 +020051extern blanktimer blankTimer;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -070052#endif
Dees_Troy51a0e822012-09-05 15:24:24 -040053
54std::map<std::string, PageSet*> PageManager::mPageSets;
55PageSet* PageManager::mCurrentSet;
56PageSet* PageManager::mBaseSet = NULL;
57
Dees_Troy51a0e822012-09-05 15:24:24 -040058// Helper routine to convert a string to a color declaration
59int ConvertStrToColor(std::string str, COLOR* color)
60{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020061 // Set the default, solid black
62 memset(color, 0, sizeof(COLOR));
63 color->alpha = 255;
Dees_Troy51a0e822012-09-05 15:24:24 -040064
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020065 // Translate variables
66 DataManager::GetValue(str, str);
67
68 // Look for some defaults
69 if (str == "black") return 0;
70 else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
71 else if (str == "red") { color->red = 255; return 0; }
72 else if (str == "green") { color->green = 255; return 0; }
73 else if (str == "blue") { color->blue = 255; return 0; }
Dees_Troy51a0e822012-09-05 15:24:24 -040074
Vojtech Bocekfafb0c52013-07-25 22:53:02 +020075 // At this point, we require an RGB(A) color
76 if (str[0] != '#')
77 return -1;
78
79 str.erase(0, 1);
Dees_Troy51a0e822012-09-05 15:24:24 -040080
Dees_Troy30b962e2012-10-19 20:48:59 -040081 int result;
82 if (str.size() >= 8) {
83 // We have alpha channel
84 string alpha = str.substr(6, 2);
85 result = strtol(alpha.c_str(), NULL, 16);
86 color->alpha = result & 0x000000FF;
87 str.resize(6);
88 result = strtol(str.c_str(), NULL, 16);
89 color->red = (result >> 16) & 0x000000FF;
90 color->green = (result >> 8) & 0x000000FF;
91 color->blue = result & 0x000000FF;
92 } else {
93 result = strtol(str.c_str(), NULL, 16);
94 color->red = (result >> 16) & 0x000000FF;
95 color->green = (result >> 8) & 0x000000FF;
96 color->blue = result & 0x000000FF;
97 }
98 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -040099}
100
101// Helper APIs
102bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
103{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200104 if (!node)
105 return false;
Dees_Troy51a0e822012-09-05 15:24:24 -0400106
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200107 std::string value;
108 if (node->first_attribute("x"))
109 {
110 value = node->first_attribute("x")->value();
111 DataManager::GetValue(value, value);
112 *x = atol(value.c_str());
113 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400114
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200115 if (node->first_attribute("y"))
116 {
117 value = node->first_attribute("y")->value();
118 DataManager::GetValue(value, value);
119 *y = atol(value.c_str());
120 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400121
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200122 if (w && node->first_attribute("w"))
123 {
124 value = node->first_attribute("w")->value();
125 DataManager::GetValue(value, value);
126 *w = atol(value.c_str());
127 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400128
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200129 if (h && node->first_attribute("h"))
130 {
131 value = node->first_attribute("h")->value();
132 DataManager::GetValue(value, value);
133 *h = atol(value.c_str());
134 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400135
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200136 if (placement && node->first_attribute("placement"))
137 {
138 value = node->first_attribute("placement")->value();
139 DataManager::GetValue(value, value);
140 *placement = (RenderObject::Placement) atol(value.c_str());
141 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400142
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200143 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400144}
145
146int ActionObject::SetActionPos(int x, int y, int w, int h)
147{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200148 if (x < 0 || y < 0)
149 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400150
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200151 mActionX = x;
152 mActionY = y;
153 if (w || h)
154 {
155 mActionW = w;
156 mActionH = h;
157 }
158 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400159}
160
161Page::Page(xml_node<>* page, xml_node<>* templates /* = NULL */)
162{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200163 mTouchStart = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400164
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200165 // We can memset the whole structure, because the alpha channel is ignored
166 memset(&mBackground, 0, sizeof(COLOR));
Dees_Troy51a0e822012-09-05 15:24:24 -0400167
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200168 // With NULL, we make a console-only display
169 if (!page)
170 {
171 mName = "console";
Dees_Troy51a0e822012-09-05 15:24:24 -0400172
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200173 GUIConsole* element = new GUIConsole(NULL);
174 mRenders.push_back(element);
175 mActions.push_back(element);
176 return;
177 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400178
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200179 if (page->first_attribute("name"))
180 mName = page->first_attribute("name")->value();
181 else
182 {
183 LOGERR("No page name attribute found!\n");
184 return;
185 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400186
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200187 LOGINFO("Loading page %s\n", mName.c_str());
Dees_Troy51a0e822012-09-05 15:24:24 -0400188
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200189 // This is a recursive routine for template handling
190 ProcessNode(page, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400191
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200192 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400193}
194
195bool Page::ProcessNode(xml_node<>* page, xml_node<>* templates /* = NULL */, int depth /* = 0 */)
196{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200197 if (depth == 10)
198 {
199 LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
200 return false;
201 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400202
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200203 // Let's retrieve the background value, if any
204 xml_node<>* bg = page->first_node("background");
205 if (bg)
206 {
207 xml_attribute<>* attr = bg->first_attribute("color");
208 if (attr)
209 {
210 std::string color = attr->value();
211 ConvertStrToColor(color, &mBackground);
212 }
213 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400214
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200215 xml_node<>* child;
216 child = page->first_node("object");
217 while (child)
218 {
219 if (!child->first_attribute("type"))
220 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400221
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200222 std::string type = child->first_attribute("type")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400223
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200224 if (type == "text")
225 {
226 GUIText* element = new GUIText(child);
227 mRenders.push_back(element);
228 mActions.push_back(element);
229 }
230 else if (type == "image")
231 {
232 GUIImage* element = new GUIImage(child);
233 mRenders.push_back(element);
234 }
235 else if (type == "fill")
236 {
237 GUIFill* element = new GUIFill(child);
238 mRenders.push_back(element);
239 }
240 else if (type == "action")
241 {
242 GUIAction* element = new GUIAction(child);
243 mActions.push_back(element);
244 }
245 else if (type == "console")
246 {
247 GUIConsole* element = new GUIConsole(child);
248 mRenders.push_back(element);
249 mActions.push_back(element);
250 }
251 else if (type == "button")
252 {
253 GUIButton* element = new GUIButton(child);
254 mRenders.push_back(element);
255 mActions.push_back(element);
256 }
257 else if (type == "checkbox")
258 {
259 GUICheckbox* element = new GUICheckbox(child);
260 mRenders.push_back(element);
261 mActions.push_back(element);
262 }
263 else if (type == "fileselector")
264 {
265 GUIFileSelector* element = new GUIFileSelector(child);
266 mRenders.push_back(element);
267 mActions.push_back(element);
268 }
269 else if (type == "animation")
270 {
271 GUIAnimation* element = new GUIAnimation(child);
272 mRenders.push_back(element);
273 }
274 else if (type == "progressbar")
275 {
276 GUIProgressBar* element = new GUIProgressBar(child);
277 mRenders.push_back(element);
278 mActions.push_back(element);
279 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400280 else if (type == "slider")
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200281 {
282 GUISlider* element = new GUISlider(child);
283 mRenders.push_back(element);
284 mActions.push_back(element);
285 }
Vojtech Bocek85932342013-04-01 22:11:33 +0200286 else if (type == "slidervalue")
287 {
288 GUISliderValue *element = new GUISliderValue(child);
289 mRenders.push_back(element);
290 mActions.push_back(element);
291 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400292 else if (type == "listbox")
293 {
294 GUIListBox* element = new GUIListBox(child);
295 mRenders.push_back(element);
296 mActions.push_back(element);
297 }
298 else if (type == "keyboard")
299 {
300 GUIKeyboard* element = new GUIKeyboard(child);
301 mRenders.push_back(element);
302 mActions.push_back(element);
303 }
304 else if (type == "input")
305 {
306 GUIInput* element = new GUIInput(child);
307 mRenders.push_back(element);
308 mActions.push_back(element);
309 mInputs.push_back(element);
310 }
Dees_Troya13d74f2013-03-24 08:54:55 -0500311 else if (type == "partitionlist")
312 {
313 GUIPartitionList* element = new GUIPartitionList(child);
314 mRenders.push_back(element);
315 mActions.push_back(element);
316 }
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200317 else if (type == "template")
318 {
319 if (!templates || !child->first_attribute("name"))
320 {
321 LOGERR("Invalid template request.\n");
322 }
323 else
324 {
325 std::string name = child->first_attribute("name")->value();
Dees_Troy51a0e822012-09-05 15:24:24 -0400326
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200327 // We need to find the correct template
328 xml_node<>* node;
329 node = templates->first_node("template");
Dees_Troy51a0e822012-09-05 15:24:24 -0400330
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200331 while (node)
332 {
333 if (!node->first_attribute("name"))
334 continue;
Dees_Troy51a0e822012-09-05 15:24:24 -0400335
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200336 if (name == node->first_attribute("name")->value())
337 {
338 if (!ProcessNode(node, templates, depth + 1))
339 return false;
340 else
341 break;
342 }
343 node = node->next_sibling("template");
344 }
345 }
346 }
347 else
348 {
349 LOGERR("Unknown object type.\n");
350 }
351 child = child->next_sibling("object");
352 }
353 return true;
Dees_Troy51a0e822012-09-05 15:24:24 -0400354}
355
356int Page::Render(void)
357{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200358 // Render background
359 gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
360 gr_fill(0, 0, gr_fb_width(), gr_fb_height());
Dees_Troy51a0e822012-09-05 15:24:24 -0400361
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200362 // Render remaining objects
363 std::vector<RenderObject*>::iterator iter;
364 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
365 {
366 if ((*iter)->Render())
367 LOGERR("A render request has failed.\n");
368 }
369 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400370}
371
372int Page::Update(void)
373{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200374 int retCode = 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400375
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200376 std::vector<RenderObject*>::iterator iter;
377 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
378 {
379 int ret = (*iter)->Update();
380 if (ret < 0)
381 LOGERR("An update request has failed.\n");
382 else if (ret > retCode)
383 retCode = ret;
384 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400385
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200386 return retCode;
Dees_Troy51a0e822012-09-05 15:24:24 -0400387}
388
389int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
390{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200391 // By default, return 1 to ignore further touches if nobody is listening
392 int ret = 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400393
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200394 // Don't try to handle a lack of handlers
395 if (mActions.size() == 0)
396 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400397
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200398 // We record mTouchStart so we can pass all the touch stream to the same handler
399 if (state == TOUCH_START)
400 {
401 std::vector<ActionObject*>::reverse_iterator iter;
402 // We work backwards, from top-most element to bottom-most element
403 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
404 {
405 if ((*iter)->IsInRegion(x, y))
406 {
407 mTouchStart = (*iter);
408 ret = mTouchStart->NotifyTouch(state, x, y);
409 if (ret >= 0)
410 break;
411 mTouchStart = NULL;
412 }
413 }
414 }
415 else if (state == TOUCH_RELEASE && mTouchStart != NULL)
416 {
417 ret = mTouchStart->NotifyTouch(state, x, y);
418 mTouchStart = NULL;
419 }
420 else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
421 {
422 ret = mTouchStart->NotifyTouch(state, x, y);
423 }
424 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400425}
426
427int Page::NotifyKey(int key)
428{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200429 std::vector<ActionObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400430
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200431 // Don't try to handle a lack of handlers
432 if (mActions.size() == 0)
433 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400434
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200435 // We work backwards, from top-most element to bottom-most element
436 for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
437 {
438 int ret = (*iter)->NotifyKey(key);
439 if (ret == 0)
440 return 0;
441 else if (ret < 0)
442 LOGERR("An action handler has returned an error");
443 }
444 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400445}
446
447int Page::NotifyKeyboard(int key)
448{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200449 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400450
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200451 // Don't try to handle a lack of handlers
452 if (mInputs.size() == 0)
453 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400454
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200455 // We work backwards, from top-most element to bottom-most element
456 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
457 {
458 int ret = (*iter)->NotifyKeyboard(key);
459 if (ret == 0)
460 return 0;
461 else if (ret < 0)
462 LOGERR("A keyboard handler has returned an error");
463 }
464 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400465}
466
467int Page::SetKeyBoardFocus(int inFocus)
468{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200469 std::vector<InputObject*>::reverse_iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400470
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200471 // Don't try to handle a lack of handlers
472 if (mInputs.size() == 0)
473 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400474
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200475 // We work backwards, from top-most element to bottom-most element
476 for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
477 {
478 int ret = (*iter)->SetInputFocus(inFocus);
479 if (ret == 0)
480 return 0;
481 else if (ret < 0)
482 LOGERR("An input focus handler has returned an error");
483 }
484 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400485}
486
487void Page::SetPageFocus(int inFocus)
488{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200489 // Render remaining objects
490 std::vector<RenderObject*>::iterator iter;
491 for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
492 (*iter)->SetPageFocus(inFocus);
493
494 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400495}
496
497int Page::NotifyVarChange(std::string varName, std::string value)
498{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200499 std::vector<ActionObject*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400500
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200501 // Don't try to handle a lack of handlers
502 if (mActions.size() == 0)
503 return 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400504
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200505 for (iter = mActions.begin(); iter != mActions.end(); ++iter)
506 {
507 if ((*iter)->NotifyVarChange(varName, value))
508 LOGERR("An action handler errored on NotifyVarChange.\n");
509 }
510 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400511}
512
513PageSet::PageSet(char* xmlFile)
514{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200515 mResources = NULL;
516 mCurrentPage = NULL;
517 mOverlayPage = NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400518
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200519 mXmlFile = xmlFile;
520 if (xmlFile)
521 mDoc.parse<0>(mXmlFile);
522 else
523 mCurrentPage = new Page(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400524}
525
526PageSet::~PageSet()
527{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200528 delete mResources;
529 free(mXmlFile);
Dees_Troy51a0e822012-09-05 15:24:24 -0400530}
531
532int PageSet::Load(ZipArchive* package)
533{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200534 xml_node<>* parent;
535 xml_node<>* child;
536 xml_node<>* templates;
Dees_Troy51a0e822012-09-05 15:24:24 -0400537
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200538 parent = mDoc.first_node("recovery");
539 if (!parent)
540 parent = mDoc.first_node("install");
Dees_Troy51a0e822012-09-05 15:24:24 -0400541
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200542 // Now, let's parse the XML
543 LOGINFO("Loading resources...\n");
544 child = parent->first_node("resources");
545 if (child)
546 mResources = new ResourceManager(child, package);
Dees_Troy51a0e822012-09-05 15:24:24 -0400547
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200548 LOGINFO("Loading variables...\n");
549 child = parent->first_node("variables");
550 if (child)
551 LoadVariables(child);
Dees_Troy51a0e822012-09-05 15:24:24 -0400552
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200553 LOGINFO("Loading pages...\n");
554 // This may be NULL if no templates are present
555 templates = parent->first_node("templates");
Dees_Troy51a0e822012-09-05 15:24:24 -0400556
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200557 child = parent->first_node("pages");
558 if (!child)
559 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400560
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200561 return LoadPages(child, templates);
Dees_Troy51a0e822012-09-05 15:24:24 -0400562}
563
564int PageSet::SetPage(std::string page)
565{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200566 Page* tmp = FindPage(page);
567 if (tmp)
568 {
569 if (mCurrentPage) mCurrentPage->SetPageFocus(0);
570 mCurrentPage = tmp;
571 mCurrentPage->SetPageFocus(1);
572 mCurrentPage->NotifyVarChange("", "");
573 return 0;
574 }
575 else
576 {
577 LOGERR("Unable to locate page (%s)\n", page.c_str());
578 }
579 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400580}
581
582int PageSet::SetOverlay(Page* page)
583{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200584 if (mOverlayPage) mOverlayPage->SetPageFocus(0);
585 mOverlayPage = page;
586 if (mOverlayPage)
587 {
588 mOverlayPage->SetPageFocus(1);
589 mOverlayPage->NotifyVarChange("", "");
590 }
591 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400592}
593
594Resource* PageSet::FindResource(std::string name)
595{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200596 return mResources ? mResources->FindResource(name) : NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400597}
598
599Page* PageSet::FindPage(std::string name)
600{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200601 std::vector<Page*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400602
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200603 for (iter = mPages.begin(); iter != mPages.end(); iter++)
604 {
605 if (name == (*iter)->GetName())
606 return (*iter);
607 }
608 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400609}
610
611int PageSet::LoadVariables(xml_node<>* vars)
612{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200613 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -0400614
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200615 child = vars->first_node("variable");
616 while (child)
617 {
618 if (!child->first_attribute("name"))
619 break;
620 if (!child->first_attribute("value"))
621 break;
Dees_Troy51a0e822012-09-05 15:24:24 -0400622
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200623 DataManager::SetValue(child->first_attribute("name")->value(), child->first_attribute("value")->value());
624 child = child->next_sibling("variable");
625 }
626 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400627}
628
629int PageSet::LoadPages(xml_node<>* pages, xml_node<>* templates /* = NULL */)
630{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200631 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -0400632
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200633 if (!pages)
634 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400635
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200636 child = pages->first_node("page");
637 while (child != NULL)
638 {
639 Page* page = new Page(child, templates);
640 if (page->GetName().empty())
641 {
642 LOGERR("Unable to process load page\n");
643 delete page;
644 }
645 else
646 {
647 mPages.push_back(page);
648 }
649 child = child->next_sibling("page");
650 }
651 if (mPages.size() > 0)
652 return 0;
653 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400654}
655
656int PageSet::IsCurrentPage(Page* page)
657{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200658 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400659}
660
661int PageSet::Render(void)
662{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200663 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400664
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200665 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
666 if (ret < 0)
667 return ret;
668 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
669 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400670}
671
672int PageSet::Update(void)
673{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200674 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400675
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200676 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
677 if (ret < 0 || ret > 1)
678 return ret;
679 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
680 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400681}
682
683int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
684{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200685 if (mOverlayPage)
686 return (mOverlayPage->NotifyTouch(state, x, y));
687
688 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400689}
690
691int PageSet::NotifyKey(int key)
692{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200693 if (mOverlayPage)
694 return (mOverlayPage->NotifyKey(key));
695
696 return (mCurrentPage ? mCurrentPage->NotifyKey(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400697}
698
699int PageSet::NotifyKeyboard(int key)
700{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200701 if (mOverlayPage)
702 return (mOverlayPage->NotifyKeyboard(key));
703
704 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400705}
706
707int PageSet::SetKeyBoardFocus(int inFocus)
708{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200709 if (mOverlayPage)
710 return (mOverlayPage->SetKeyBoardFocus(inFocus));
711
712 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400713}
714
715int PageSet::NotifyVarChange(std::string varName, std::string value)
716{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200717 if (mOverlayPage)
718 mOverlayPage->NotifyVarChange(varName, value);
719
720 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400721}
722
723int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
724{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200725 int fd;
726 ZipArchive zip, *pZip = NULL;
727 long len;
728 char* xmlFile = NULL;
729 PageSet* pageSet = NULL;
730 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400731
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200732 // Open the XML file
733 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
734 if (mzOpenZipArchive(package.c_str(), &zip))
735 {
736 // We can try to load the XML directly...
737 struct stat st;
738 if(stat(package.c_str(),&st) != 0)
739 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400740
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200741 len = st.st_size;
742 xmlFile = (char*) malloc(len + 1);
743 if (!xmlFile)
744 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400745
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200746 fd = open(package.c_str(), O_RDONLY);
747 if (fd == -1)
748 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400749
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200750 read(fd, xmlFile, len);
751 close(fd);
752 }
753 else
754 {
755 pZip = &zip;
756 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
757 if (ui_xml == NULL)
758 {
759 LOGERR("Unable to locate ui.xml in zip file\n");
760 goto error;
761 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400762
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200763 // Allocate the buffer for the file
764 len = mzGetZipEntryUncompLen(ui_xml);
765 xmlFile = (char*) malloc(len + 1);
766 if (!xmlFile)
767 goto error;
768
769 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
770 {
771 LOGERR("Unable to extract ui.xml\n");
772 goto error;
773 }
774 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400775
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200776 // NULL-terminate the string
777 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -0400778
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200779 // Before loading, mCurrentSet must be the loading package so we can find resources
780 pageSet = mCurrentSet;
781 mCurrentSet = new PageSet(xmlFile);
782
783 ret = mCurrentSet->Load(pZip);
784 if (ret == 0)
785 {
786 mCurrentSet->SetPage(startpage);
787 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
788 }
789 else
790 {
791 LOGERR("Package %s failed to load.\n", name.c_str());
792 }
793
794 // The first successful package we loaded is the base
795 if (mBaseSet == NULL)
796 mBaseSet = mCurrentSet;
797
798 mCurrentSet = pageSet;
799
800 if (pZip)
801 mzCloseZipArchive(pZip);
802 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400803
804error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200805 LOGERR("An internal error has occurred.\n");
806 if (pZip)
807 mzCloseZipArchive(pZip);
808 if (xmlFile)
809 free(xmlFile);
810 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400811}
812
813PageSet* PageManager::FindPackage(std::string name)
814{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200815 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400816
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200817 iter = mPageSets.find(name);
818 if (iter != mPageSets.end())
819 return (*iter).second;
820
821 LOGERR("Unable to locate package %s\n", name.c_str());
822 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400823}
824
825PageSet* PageManager::SelectPackage(std::string name)
826{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200827 LOGINFO("Switching packages (%s)\n", name.c_str());
828 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -0400829
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200830 tmp = FindPackage(name);
831 if (tmp)
832 mCurrentSet = tmp;
833 else
834 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400835
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200836 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -0400837}
838
839int PageManager::ReloadPackage(std::string name, std::string package)
840{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200841 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400842
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200843 iter = mPageSets.find(name);
844 if (iter == mPageSets.end())
845 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400846
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200847 PageSet* set = (*iter).second;
848 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -0400849
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200850 if (LoadPackage(name, package, "main") != 0)
851 {
852 LOGERR("Failed to load package.\n");
853 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
854 return -1;
855 }
856 if (mCurrentSet == set)
857 SelectPackage(name);
858 delete set;
859 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400860}
861
862void PageManager::ReleasePackage(std::string name)
863{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200864 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400865
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200866 iter = mPageSets.find(name);
867 if (iter == mPageSets.end())
868 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400869
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200870 PageSet* set = (*iter).second;
871 mPageSets.erase(iter);
872 delete set;
873 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400874}
875
876int PageManager::ChangePage(std::string name)
877{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200878 DataManager::SetValue("tw_operation_state", 0);
879 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
880 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400881}
882
883int PageManager::ChangeOverlay(std::string name)
884{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200885 if (name.empty())
886 return mCurrentSet->SetOverlay(NULL);
887 else
888 {
889 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
890 return mCurrentSet->SetOverlay(page);
891 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400892}
893
894Resource* PageManager::FindResource(std::string name)
895{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200896 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400897}
898
899Resource* PageManager::FindResource(std::string package, std::string name)
900{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200901 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -0400902
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200903 tmp = FindPackage(name);
904 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400905}
906
907int PageManager::SwitchToConsole(void)
908{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200909 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400910
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200911 mCurrentSet = console;
912 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400913}
914
915int PageManager::IsCurrentPage(Page* page)
916{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200917 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400918}
919
920int PageManager::Render(void)
921{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200922 return (mCurrentSet ? mCurrentSet->Render() : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400923}
924
925int PageManager::Update(void)
926{
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700927#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200928 if(blankTimer.IsScreenOff())
929 return 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700930#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200931 return (mCurrentSet ? mCurrentSet->Update() : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400932}
933
934int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
935{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200936 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400937}
938
939int PageManager::NotifyKey(int key)
940{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200941 return (mCurrentSet ? mCurrentSet->NotifyKey(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400942}
943
944int PageManager::NotifyKeyboard(int key)
945{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200946 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400947}
948
949int PageManager::SetKeyBoardFocus(int inFocus)
950{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200951 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400952}
953
954int PageManager::NotifyVarChange(std::string varName, std::string value)
955{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200956 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400957}
958
959extern "C" void gui_notifyVarChange(const char *name, const char* value)
960{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200961 if (!gGuiRunning)
962 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400963
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200964 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400965}