blob: d662f18f8efa230eca4d2a53527963f95775e3a0 [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;
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100614 xml_attribute<> *name, *value, *persist;
615 int p;
Dees_Troy51a0e822012-09-05 15:24:24 -0400616
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200617 child = vars->first_node("variable");
618 while (child)
619 {
Vojtech Bocek81c29dc2013-12-07 23:02:09 +0100620 name = child->first_attribute("name");
621 value = child->first_attribute("value");
622 persist = child->first_attribute("persist");
623 if(name && value)
624 {
625 p = persist ? atoi(persist->value()) : 0;
626 DataManager::SetValue(name->value(), value->value(), p);
627 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400628
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200629 child = child->next_sibling("variable");
630 }
631 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400632}
633
634int PageSet::LoadPages(xml_node<>* pages, xml_node<>* templates /* = NULL */)
635{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200636 xml_node<>* child;
Dees_Troy51a0e822012-09-05 15:24:24 -0400637
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200638 if (!pages)
639 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400640
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200641 child = pages->first_node("page");
642 while (child != NULL)
643 {
644 Page* page = new Page(child, templates);
645 if (page->GetName().empty())
646 {
647 LOGERR("Unable to process load page\n");
648 delete page;
649 }
650 else
651 {
652 mPages.push_back(page);
653 }
654 child = child->next_sibling("page");
655 }
656 if (mPages.size() > 0)
657 return 0;
658 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400659}
660
661int PageSet::IsCurrentPage(Page* page)
662{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200663 return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400664}
665
666int PageSet::Render(void)
667{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200668 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400669
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200670 ret = (mCurrentPage ? mCurrentPage->Render() : -1);
671 if (ret < 0)
672 return ret;
673 ret = (mOverlayPage ? mOverlayPage->Render() : -1);
674 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400675}
676
677int PageSet::Update(void)
678{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200679 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400680
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200681 ret = (mCurrentPage ? mCurrentPage->Update() : -1);
682 if (ret < 0 || ret > 1)
683 return ret;
684 ret = (mOverlayPage ? mOverlayPage->Update() : -1);
685 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400686}
687
688int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
689{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200690 if (mOverlayPage)
691 return (mOverlayPage->NotifyTouch(state, x, y));
692
693 return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400694}
695
696int PageSet::NotifyKey(int key)
697{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200698 if (mOverlayPage)
699 return (mOverlayPage->NotifyKey(key));
700
701 return (mCurrentPage ? mCurrentPage->NotifyKey(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400702}
703
704int PageSet::NotifyKeyboard(int key)
705{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200706 if (mOverlayPage)
707 return (mOverlayPage->NotifyKeyboard(key));
708
709 return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400710}
711
712int PageSet::SetKeyBoardFocus(int inFocus)
713{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200714 if (mOverlayPage)
715 return (mOverlayPage->SetKeyBoardFocus(inFocus));
716
717 return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400718}
719
720int PageSet::NotifyVarChange(std::string varName, std::string value)
721{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200722 if (mOverlayPage)
723 mOverlayPage->NotifyVarChange(varName, value);
724
725 return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400726}
727
728int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
729{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200730 int fd;
731 ZipArchive zip, *pZip = NULL;
732 long len;
733 char* xmlFile = NULL;
734 PageSet* pageSet = NULL;
735 int ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400736
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200737 // Open the XML file
738 LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
739 if (mzOpenZipArchive(package.c_str(), &zip))
740 {
741 // We can try to load the XML directly...
742 struct stat st;
743 if(stat(package.c_str(),&st) != 0)
744 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400745
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200746 len = st.st_size;
747 xmlFile = (char*) malloc(len + 1);
748 if (!xmlFile)
749 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400750
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200751 fd = open(package.c_str(), O_RDONLY);
752 if (fd == -1)
753 goto error;
Dees_Troy51a0e822012-09-05 15:24:24 -0400754
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200755 read(fd, xmlFile, len);
756 close(fd);
757 }
758 else
759 {
760 pZip = &zip;
761 const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
762 if (ui_xml == NULL)
763 {
764 LOGERR("Unable to locate ui.xml in zip file\n");
765 goto error;
766 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400767
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200768 // Allocate the buffer for the file
769 len = mzGetZipEntryUncompLen(ui_xml);
770 xmlFile = (char*) malloc(len + 1);
771 if (!xmlFile)
772 goto error;
773
774 if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
775 {
776 LOGERR("Unable to extract ui.xml\n");
777 goto error;
778 }
779 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400780
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200781 // NULL-terminate the string
782 xmlFile[len] = 0x00;
Dees_Troy51a0e822012-09-05 15:24:24 -0400783
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200784 // Before loading, mCurrentSet must be the loading package so we can find resources
785 pageSet = mCurrentSet;
786 mCurrentSet = new PageSet(xmlFile);
787
788 ret = mCurrentSet->Load(pZip);
789 if (ret == 0)
790 {
791 mCurrentSet->SetPage(startpage);
792 mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
793 }
794 else
795 {
796 LOGERR("Package %s failed to load.\n", name.c_str());
797 }
798
799 // The first successful package we loaded is the base
800 if (mBaseSet == NULL)
801 mBaseSet = mCurrentSet;
802
803 mCurrentSet = pageSet;
804
805 if (pZip)
806 mzCloseZipArchive(pZip);
807 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400808
809error:
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200810 LOGERR("An internal error has occurred.\n");
811 if (pZip)
812 mzCloseZipArchive(pZip);
813 if (xmlFile)
814 free(xmlFile);
815 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400816}
817
818PageSet* PageManager::FindPackage(std::string name)
819{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200820 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400821
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200822 iter = mPageSets.find(name);
823 if (iter != mPageSets.end())
824 return (*iter).second;
825
826 LOGERR("Unable to locate package %s\n", name.c_str());
827 return NULL;
Dees_Troy51a0e822012-09-05 15:24:24 -0400828}
829
830PageSet* PageManager::SelectPackage(std::string name)
831{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200832 LOGINFO("Switching packages (%s)\n", name.c_str());
833 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -0400834
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200835 tmp = FindPackage(name);
836 if (tmp)
837 mCurrentSet = tmp;
838 else
839 LOGERR("Unable to find package.\n");
Dees_Troy51a0e822012-09-05 15:24:24 -0400840
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200841 return mCurrentSet;
Dees_Troy51a0e822012-09-05 15:24:24 -0400842}
843
844int PageManager::ReloadPackage(std::string name, std::string package)
845{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200846 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400847
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200848 iter = mPageSets.find(name);
849 if (iter == mPageSets.end())
850 return -1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400851
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200852 PageSet* set = (*iter).second;
853 mPageSets.erase(iter);
Dees_Troy51a0e822012-09-05 15:24:24 -0400854
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200855 if (LoadPackage(name, package, "main") != 0)
856 {
857 LOGERR("Failed to load package.\n");
858 mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
859 return -1;
860 }
861 if (mCurrentSet == set)
862 SelectPackage(name);
863 delete set;
864 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400865}
866
867void PageManager::ReleasePackage(std::string name)
868{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200869 std::map<std::string, PageSet*>::iterator iter;
Dees_Troy51a0e822012-09-05 15:24:24 -0400870
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200871 iter = mPageSets.find(name);
872 if (iter == mPageSets.end())
873 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400874
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200875 PageSet* set = (*iter).second;
876 mPageSets.erase(iter);
877 delete set;
878 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400879}
880
881int PageManager::ChangePage(std::string name)
882{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200883 DataManager::SetValue("tw_operation_state", 0);
884 int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
885 return ret;
Dees_Troy51a0e822012-09-05 15:24:24 -0400886}
887
888int PageManager::ChangeOverlay(std::string name)
889{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200890 if (name.empty())
891 return mCurrentSet->SetOverlay(NULL);
892 else
893 {
894 Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
895 return mCurrentSet->SetOverlay(page);
896 }
Dees_Troy51a0e822012-09-05 15:24:24 -0400897}
898
899Resource* PageManager::FindResource(std::string name)
900{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200901 return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400902}
903
904Resource* PageManager::FindResource(std::string package, std::string name)
905{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200906 PageSet* tmp;
Dees_Troy51a0e822012-09-05 15:24:24 -0400907
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200908 tmp = FindPackage(name);
909 return (tmp ? tmp->FindResource(name) : NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400910}
911
912int PageManager::SwitchToConsole(void)
913{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200914 PageSet* console = new PageSet(NULL);
Dees_Troy51a0e822012-09-05 15:24:24 -0400915
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200916 mCurrentSet = console;
917 return 0;
Dees_Troy51a0e822012-09-05 15:24:24 -0400918}
919
920int PageManager::IsCurrentPage(Page* page)
921{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200922 return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
Dees_Troy51a0e822012-09-05 15:24:24 -0400923}
924
925int PageManager::Render(void)
926{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200927 return (mCurrentSet ? mCurrentSet->Render() : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400928}
929
930int PageManager::Update(void)
931{
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700932#ifndef TW_NO_SCREEN_TIMEOUT
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200933 if(blankTimer.IsScreenOff())
934 return 0;
Ricardo Gomezc9ecd442013-07-05 16:13:52 -0700935#endif
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200936 return (mCurrentSet ? mCurrentSet->Update() : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400937}
938
939int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
940{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200941 return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400942}
943
944int PageManager::NotifyKey(int key)
945{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200946 return (mCurrentSet ? mCurrentSet->NotifyKey(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400947}
948
949int PageManager::NotifyKeyboard(int key)
950{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200951 return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400952}
953
954int PageManager::SetKeyBoardFocus(int inFocus)
955{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200956 return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400957}
958
959int PageManager::NotifyVarChange(std::string varName, std::string value)
960{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200961 return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
Dees_Troy51a0e822012-09-05 15:24:24 -0400962}
963
964extern "C" void gui_notifyVarChange(const char *name, const char* value)
965{
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200966 if (!gGuiRunning)
967 return;
Dees_Troy51a0e822012-09-05 15:24:24 -0400968
Vojtech Bocekfafb0c52013-07-25 22:53:02 +0200969 PageManager::NotifyVarChange(name, value);
Dees_Troy51a0e822012-09-05 15:24:24 -0400970}