The new minzip did not compile in older trees due to needing mmap64. For older trees we will just use mmap instead. Remove all files and code pertaining to minzipold. Updater should now build properly in older trees as well. Eliminate use of PLATFORM_VERSION in favor of PLATFORM_SDK_VERSION which should be more consistent and reliable. Change-Id: I38d2b604a73d1b17a2072c7d60e990b81ece0c10
1229 lines
28 KiB
C++
1229 lines
28 KiB
C++
/*
|
|
Copyright 2013 bigbiff/Dees_Troy TeamWin
|
|
This file is part of TWRP/TeamWin Recovery Project.
|
|
|
|
TWRP is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TWRP is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with TWRP. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// pages.cpp - Source to manage GUI base objects
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/reboot.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include "../twrp-functions.hpp"
|
|
|
|
#include <string>
|
|
|
|
extern "C" {
|
|
#include "../twcommon.h"
|
|
#include "../minuitwrp/minui.h"
|
|
#include "../minzip/SysUtil.h"
|
|
#include "../minzip/Zip.h"
|
|
}
|
|
|
|
#include "rapidxml.hpp"
|
|
#include "objects.hpp"
|
|
#ifndef TW_NO_SCREEN_TIMEOUT
|
|
#include "blanktimer.hpp"
|
|
#endif
|
|
|
|
extern int gGuiRunning;
|
|
#ifndef TW_NO_SCREEN_TIMEOUT
|
|
extern blanktimer blankTimer;
|
|
#endif
|
|
|
|
std::map<std::string, PageSet*> PageManager::mPageSets;
|
|
PageSet* PageManager::mCurrentSet;
|
|
PageSet* PageManager::mBaseSet = NULL;
|
|
MouseCursor *PageManager::mMouseCursor = NULL;
|
|
HardwareKeyboard *PageManager::mHardwareKeyboard = NULL;
|
|
|
|
// Helper routine to convert a string to a color declaration
|
|
int ConvertStrToColor(std::string str, COLOR* color)
|
|
{
|
|
// Set the default, solid black
|
|
memset(color, 0, sizeof(COLOR));
|
|
color->alpha = 255;
|
|
|
|
// Translate variables
|
|
DataManager::GetValue(str, str);
|
|
|
|
// Look for some defaults
|
|
if (str == "black") return 0;
|
|
else if (str == "white") { color->red = color->green = color->blue = 255; return 0; }
|
|
else if (str == "red") { color->red = 255; return 0; }
|
|
else if (str == "green") { color->green = 255; return 0; }
|
|
else if (str == "blue") { color->blue = 255; return 0; }
|
|
|
|
// At this point, we require an RGB(A) color
|
|
if (str[0] != '#')
|
|
return -1;
|
|
|
|
str.erase(0, 1);
|
|
|
|
int result;
|
|
if (str.size() >= 8) {
|
|
// We have alpha channel
|
|
string alpha = str.substr(6, 2);
|
|
result = strtol(alpha.c_str(), NULL, 16);
|
|
color->alpha = result & 0x000000FF;
|
|
str.resize(6);
|
|
result = strtol(str.c_str(), NULL, 16);
|
|
color->red = (result >> 16) & 0x000000FF;
|
|
color->green = (result >> 8) & 0x000000FF;
|
|
color->blue = result & 0x000000FF;
|
|
} else {
|
|
result = strtol(str.c_str(), NULL, 16);
|
|
color->red = (result >> 16) & 0x000000FF;
|
|
color->green = (result >> 8) & 0x000000FF;
|
|
color->blue = result & 0x000000FF;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Helper APIs
|
|
bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
|
|
{
|
|
if (!node)
|
|
return false;
|
|
|
|
std::string value;
|
|
if (node->first_attribute("x"))
|
|
{
|
|
value = node->first_attribute("x")->value();
|
|
DataManager::GetValue(value, value);
|
|
*x = atol(value.c_str());
|
|
}
|
|
|
|
if (node->first_attribute("y"))
|
|
{
|
|
value = node->first_attribute("y")->value();
|
|
DataManager::GetValue(value, value);
|
|
*y = atol(value.c_str());
|
|
}
|
|
|
|
if (w && node->first_attribute("w"))
|
|
{
|
|
value = node->first_attribute("w")->value();
|
|
DataManager::GetValue(value, value);
|
|
*w = atol(value.c_str());
|
|
}
|
|
|
|
if (h && node->first_attribute("h"))
|
|
{
|
|
value = node->first_attribute("h")->value();
|
|
DataManager::GetValue(value, value);
|
|
*h = atol(value.c_str());
|
|
}
|
|
|
|
if (placement && node->first_attribute("placement"))
|
|
{
|
|
value = node->first_attribute("placement")->value();
|
|
DataManager::GetValue(value, value);
|
|
*placement = (RenderObject::Placement) atol(value.c_str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int ActionObject::SetActionPos(int x, int y, int w, int h)
|
|
{
|
|
if (x < 0 || y < 0)
|
|
return -1;
|
|
|
|
mActionX = x;
|
|
mActionY = y;
|
|
if (w || h)
|
|
{
|
|
mActionW = w;
|
|
mActionH = h;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Page::Page(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */)
|
|
{
|
|
mTouchStart = NULL;
|
|
|
|
// We can memset the whole structure, because the alpha channel is ignored
|
|
memset(&mBackground, 0, sizeof(COLOR));
|
|
|
|
// With NULL, we make a console-only display
|
|
if (!page)
|
|
{
|
|
mName = "console";
|
|
|
|
GUIConsole* element = new GUIConsole(NULL);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
return;
|
|
}
|
|
|
|
if (page->first_attribute("name"))
|
|
mName = page->first_attribute("name")->value();
|
|
else
|
|
{
|
|
LOGERR("No page name attribute found!\n");
|
|
return;
|
|
}
|
|
|
|
LOGINFO("Loading page %s\n", mName.c_str());
|
|
|
|
// This is a recursive routine for template handling
|
|
ProcessNode(page, templates);
|
|
|
|
return;
|
|
}
|
|
|
|
Page::~Page()
|
|
{
|
|
for (std::vector<GUIObject*>::iterator itr = mObjects.begin(); itr != mObjects.end(); ++itr)
|
|
delete *itr;
|
|
}
|
|
|
|
bool Page::ProcessNode(xml_node<>* page, std::vector<xml_node<>*> *templates /* = NULL */, int depth /* = 0 */)
|
|
{
|
|
if (depth == 10)
|
|
{
|
|
LOGERR("Page processing depth has exceeded 10. Failing out. This is likely a recursive template.\n");
|
|
return false;
|
|
}
|
|
|
|
// Let's retrieve the background value, if any
|
|
xml_node<>* bg = page->first_node("background");
|
|
if (bg)
|
|
{
|
|
xml_attribute<>* attr = bg->first_attribute("color");
|
|
if (attr)
|
|
{
|
|
std::string color = attr->value();
|
|
ConvertStrToColor(color, &mBackground);
|
|
}
|
|
}
|
|
|
|
xml_node<>* child;
|
|
child = page->first_node("object");
|
|
while (child)
|
|
{
|
|
if (!child->first_attribute("type"))
|
|
break;
|
|
|
|
std::string type = child->first_attribute("type")->value();
|
|
|
|
if (type == "text")
|
|
{
|
|
GUIText* element = new GUIText(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "image")
|
|
{
|
|
GUIImage* element = new GUIImage(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
}
|
|
else if (type == "fill")
|
|
{
|
|
GUIFill* element = new GUIFill(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
}
|
|
else if (type == "action")
|
|
{
|
|
GUIAction* element = new GUIAction(child);
|
|
mObjects.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "console")
|
|
{
|
|
GUIConsole* element = new GUIConsole(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "button")
|
|
{
|
|
GUIButton* element = new GUIButton(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "checkbox")
|
|
{
|
|
GUICheckbox* element = new GUICheckbox(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "fileselector")
|
|
{
|
|
GUIFileSelector* element = new GUIFileSelector(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "animation")
|
|
{
|
|
GUIAnimation* element = new GUIAnimation(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
}
|
|
else if (type == "progressbar")
|
|
{
|
|
GUIProgressBar* element = new GUIProgressBar(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "slider")
|
|
{
|
|
GUISlider* element = new GUISlider(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "slidervalue")
|
|
{
|
|
GUISliderValue *element = new GUISliderValue(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "listbox")
|
|
{
|
|
GUIListBox* element = new GUIListBox(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "keyboard")
|
|
{
|
|
GUIKeyboard* element = new GUIKeyboard(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "input")
|
|
{
|
|
GUIInput* element = new GUIInput(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
mInputs.push_back(element);
|
|
}
|
|
else if (type == "partitionlist")
|
|
{
|
|
GUIPartitionList* element = new GUIPartitionList(child);
|
|
mObjects.push_back(element);
|
|
mRenders.push_back(element);
|
|
mActions.push_back(element);
|
|
}
|
|
else if (type == "template")
|
|
{
|
|
if (!templates || !child->first_attribute("name"))
|
|
{
|
|
LOGERR("Invalid template request.\n");
|
|
}
|
|
else
|
|
{
|
|
std::string name = child->first_attribute("name")->value();
|
|
xml_node<>* node;
|
|
bool node_found = false;
|
|
|
|
// We need to find the correct template
|
|
for (std::vector<xml_node<>*>::iterator itr = templates->begin(); itr != templates->end(); itr++) {
|
|
node = (*itr)->first_node("template");
|
|
|
|
while (node)
|
|
{
|
|
if (!node->first_attribute("name"))
|
|
continue;
|
|
|
|
if (name == node->first_attribute("name")->value())
|
|
{
|
|
if (!ProcessNode(node, templates, depth + 1))
|
|
return false;
|
|
else {
|
|
node_found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (node_found)
|
|
break;
|
|
node = node->next_sibling("template");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGERR("Unknown object type.\n");
|
|
}
|
|
child = child->next_sibling("object");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int Page::Render(void)
|
|
{
|
|
// Render background
|
|
gr_color(mBackground.red, mBackground.green, mBackground.blue, mBackground.alpha);
|
|
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
|
|
|
|
// Render remaining objects
|
|
std::vector<RenderObject*>::iterator iter;
|
|
for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
|
|
{
|
|
if ((*iter)->Render())
|
|
LOGERR("A render request has failed.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Page::Update(void)
|
|
{
|
|
int retCode = 0;
|
|
|
|
std::vector<RenderObject*>::iterator iter;
|
|
for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
|
|
{
|
|
int ret = (*iter)->Update();
|
|
if (ret < 0)
|
|
LOGERR("An update request has failed.\n");
|
|
else if (ret > retCode)
|
|
retCode = ret;
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
int Page::NotifyTouch(TOUCH_STATE state, int x, int y)
|
|
{
|
|
// By default, return 1 to ignore further touches if nobody is listening
|
|
int ret = 1;
|
|
|
|
// Don't try to handle a lack of handlers
|
|
if (mActions.size() == 0)
|
|
return ret;
|
|
|
|
// We record mTouchStart so we can pass all the touch stream to the same handler
|
|
if (state == TOUCH_START)
|
|
{
|
|
std::vector<ActionObject*>::reverse_iterator iter;
|
|
// We work backwards, from top-most element to bottom-most element
|
|
for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
|
|
{
|
|
if ((*iter)->IsInRegion(x, y))
|
|
{
|
|
mTouchStart = (*iter);
|
|
ret = mTouchStart->NotifyTouch(state, x, y);
|
|
if (ret >= 0)
|
|
break;
|
|
mTouchStart = NULL;
|
|
}
|
|
}
|
|
}
|
|
else if (state == TOUCH_RELEASE && mTouchStart != NULL)
|
|
{
|
|
ret = mTouchStart->NotifyTouch(state, x, y);
|
|
mTouchStart = NULL;
|
|
}
|
|
else if ((state == TOUCH_DRAG || state == TOUCH_HOLD || state == TOUCH_REPEAT) && mTouchStart != NULL)
|
|
{
|
|
ret = mTouchStart->NotifyTouch(state, x, y);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int Page::NotifyKey(int key, bool down)
|
|
{
|
|
std::vector<ActionObject*>::reverse_iterator iter;
|
|
|
|
// Don't try to handle a lack of handlers
|
|
if (mActions.size() == 0)
|
|
return 1;
|
|
|
|
int ret = 1;
|
|
// We work backwards, from top-most element to bottom-most element
|
|
for (iter = mActions.rbegin(); iter != mActions.rend(); iter++)
|
|
{
|
|
ret = (*iter)->NotifyKey(key, down);
|
|
if (ret < 0) {
|
|
LOGERR("An action handler has returned an error\n");
|
|
ret = 1;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int Page::NotifyKeyboard(int key)
|
|
{
|
|
std::vector<InputObject*>::reverse_iterator iter;
|
|
|
|
// Don't try to handle a lack of handlers
|
|
if (mInputs.size() == 0)
|
|
return 1;
|
|
|
|
// We work backwards, from top-most element to bottom-most element
|
|
for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
|
|
{
|
|
int ret = (*iter)->NotifyKeyboard(key);
|
|
if (ret == 0)
|
|
return 0;
|
|
else if (ret < 0)
|
|
LOGERR("A keyboard handler has returned an error");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int Page::SetKeyBoardFocus(int inFocus)
|
|
{
|
|
std::vector<InputObject*>::reverse_iterator iter;
|
|
|
|
// Don't try to handle a lack of handlers
|
|
if (mInputs.size() == 0)
|
|
return 1;
|
|
|
|
// We work backwards, from top-most element to bottom-most element
|
|
for (iter = mInputs.rbegin(); iter != mInputs.rend(); iter++)
|
|
{
|
|
int ret = (*iter)->SetInputFocus(inFocus);
|
|
if (ret == 0)
|
|
return 0;
|
|
else if (ret < 0)
|
|
LOGERR("An input focus handler has returned an error");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void Page::SetPageFocus(int inFocus)
|
|
{
|
|
// Render remaining objects
|
|
std::vector<RenderObject*>::iterator iter;
|
|
for (iter = mRenders.begin(); iter != mRenders.end(); iter++)
|
|
(*iter)->SetPageFocus(inFocus);
|
|
|
|
return;
|
|
}
|
|
|
|
int Page::NotifyVarChange(std::string varName, std::string value)
|
|
{
|
|
std::vector<GUIObject*>::iterator iter;
|
|
for (iter = mObjects.begin(); iter != mObjects.end(); ++iter)
|
|
{
|
|
if ((*iter)->NotifyVarChange(varName, value))
|
|
LOGERR("An action handler errored on NotifyVarChange.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PageSet::PageSet(char* xmlFile)
|
|
{
|
|
mResources = NULL;
|
|
mCurrentPage = NULL;
|
|
mOverlayPage = NULL;
|
|
|
|
mXmlFile = xmlFile;
|
|
if (xmlFile)
|
|
mDoc.parse<0>(mXmlFile);
|
|
else
|
|
mCurrentPage = new Page(NULL);
|
|
}
|
|
|
|
PageSet::~PageSet()
|
|
{
|
|
for (std::vector<Page*>::iterator itr = mPages.begin(); itr != mPages.end(); ++itr)
|
|
delete *itr;
|
|
for (std::vector<xml_node<>*>::iterator itr2 = templates.begin(); itr2 != templates.end(); ++itr2)
|
|
delete *itr2;
|
|
|
|
delete mResources;
|
|
free(mXmlFile);
|
|
}
|
|
|
|
int PageSet::Load(ZipArchive* package)
|
|
{
|
|
xml_node<>* parent;
|
|
xml_node<>* child;
|
|
xml_node<>* xmltemplate;
|
|
xml_node<>* blank_templates;
|
|
int pages_loaded = -1, ret;
|
|
|
|
parent = mDoc.first_node("recovery");
|
|
if (!parent)
|
|
parent = mDoc.first_node("install");
|
|
|
|
// Now, let's parse the XML
|
|
LOGINFO("Loading resources...\n");
|
|
child = parent->first_node("resources");
|
|
if (child)
|
|
mResources = new ResourceManager(child, package);
|
|
|
|
LOGINFO("Loading variables...\n");
|
|
child = parent->first_node("variables");
|
|
if (child)
|
|
LoadVariables(child);
|
|
|
|
LOGINFO("Loading mouse cursor...\n");
|
|
child = parent->first_node("mousecursor");
|
|
if(child)
|
|
PageManager::LoadCursorData(child);
|
|
|
|
LOGINFO("Loading pages...\n");
|
|
// This may be NULL if no templates are present
|
|
xmltemplate = parent->first_node("templates");
|
|
if (xmltemplate)
|
|
templates.push_back(xmltemplate);
|
|
|
|
child = parent->first_node("pages");
|
|
if (child) {
|
|
if (LoadPages(child)) {
|
|
LOGERR("PageSet::Load returning -1\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return CheckInclude(package, &mDoc);
|
|
}
|
|
|
|
int PageSet::CheckInclude(ZipArchive* package, xml_document<> *parentDoc)
|
|
{
|
|
xml_node<>* par;
|
|
xml_node<>* par2;
|
|
xml_node<>* chld;
|
|
xml_node<>* parent;
|
|
xml_node<>* child;
|
|
xml_node<>* xmltemplate;
|
|
long len;
|
|
char* xmlFile = NULL;
|
|
string filename;
|
|
xml_document<> doc;
|
|
|
|
par = parentDoc->first_node("recovery");
|
|
if (!par) {
|
|
par = parentDoc->first_node("install");
|
|
}
|
|
if (!par) {
|
|
return 0;
|
|
}
|
|
|
|
par2 = par->first_node("include");
|
|
if (!par2)
|
|
return 0;
|
|
chld = par2->first_node("xmlfile");
|
|
while (chld != NULL) {
|
|
xml_attribute<>* attr = chld->first_attribute("name");
|
|
if (!attr)
|
|
break;
|
|
|
|
LOGINFO("PageSet::CheckInclude loading filename: '%s'\n", filename.c_str());
|
|
if (!package) {
|
|
// We can try to load the XML directly...
|
|
filename = "/res/";
|
|
filename += attr->value();
|
|
struct stat st;
|
|
if(stat(filename.c_str(),&st) != 0) {
|
|
LOGERR("Unable to locate '%s'\n", filename.c_str());
|
|
return -1;
|
|
}
|
|
|
|
len = st.st_size;
|
|
xmlFile = (char*) malloc(len + 1);
|
|
if (!xmlFile)
|
|
return -1;
|
|
|
|
int fd = open(filename.c_str(), O_RDONLY);
|
|
if (fd == -1)
|
|
return -1;
|
|
|
|
read(fd, xmlFile, len);
|
|
close(fd);
|
|
} else {
|
|
filename += attr->value();
|
|
const ZipEntry* ui_xml = mzFindZipEntry(package, filename.c_str());
|
|
if (ui_xml == NULL)
|
|
{
|
|
LOGERR("Unable to locate '%s' in zip file\n", filename.c_str());
|
|
return -1;
|
|
}
|
|
|
|
// Allocate the buffer for the file
|
|
len = mzGetZipEntryUncompLen(ui_xml);
|
|
xmlFile = (char*) malloc(len + 1);
|
|
if (!xmlFile)
|
|
return -1;
|
|
|
|
if (!mzExtractZipEntryToBuffer(package, ui_xml, (unsigned char*) xmlFile))
|
|
{
|
|
LOGERR("Unable to extract '%s'\n", filename.c_str());
|
|
return -1;
|
|
}
|
|
}
|
|
doc.parse<0>(xmlFile);
|
|
|
|
parent = doc.first_node("recovery");
|
|
if (!parent)
|
|
parent = doc.first_node("install");
|
|
|
|
// Now, let's parse the XML
|
|
LOGINFO("Loading included resources...\n");
|
|
child = parent->first_node("resources");
|
|
if (child)
|
|
mResources->LoadResources(child, package);
|
|
|
|
LOGINFO("Loading included variables...\n");
|
|
child = parent->first_node("variables");
|
|
if (child)
|
|
LoadVariables(child);
|
|
|
|
LOGINFO("Loading mouse cursor...\n");
|
|
child = parent->first_node("mousecursor");
|
|
if(child)
|
|
PageManager::LoadCursorData(child);
|
|
|
|
LOGINFO("Loading included pages...\n");
|
|
// This may be NULL if no templates are present
|
|
xmltemplate = parent->first_node("templates");
|
|
if (xmltemplate)
|
|
templates.push_back(xmltemplate);
|
|
|
|
child = parent->first_node("pages");
|
|
if (child)
|
|
if (LoadPages(child))
|
|
return -1;
|
|
|
|
if (CheckInclude(package, &doc))
|
|
return -1;
|
|
|
|
chld = chld->next_sibling("xmlfile");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PageSet::SetPage(std::string page)
|
|
{
|
|
Page* tmp = FindPage(page);
|
|
if (tmp)
|
|
{
|
|
if (mCurrentPage) mCurrentPage->SetPageFocus(0);
|
|
mCurrentPage = tmp;
|
|
mCurrentPage->SetPageFocus(1);
|
|
mCurrentPage->NotifyVarChange("", "");
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
LOGERR("Unable to locate page (%s)\n", page.c_str());
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int PageSet::SetOverlay(Page* page)
|
|
{
|
|
if (mOverlayPage) mOverlayPage->SetPageFocus(0);
|
|
mOverlayPage = page;
|
|
if (mOverlayPage)
|
|
{
|
|
mOverlayPage->SetPageFocus(1);
|
|
mOverlayPage->NotifyVarChange("", "");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Resource* PageSet::FindResource(std::string name)
|
|
{
|
|
return mResources ? mResources->FindResource(name) : NULL;
|
|
}
|
|
|
|
Page* PageSet::FindPage(std::string name)
|
|
{
|
|
std::vector<Page*>::iterator iter;
|
|
|
|
for (iter = mPages.begin(); iter != mPages.end(); iter++)
|
|
{
|
|
if (name == (*iter)->GetName())
|
|
return (*iter);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int PageSet::LoadVariables(xml_node<>* vars)
|
|
{
|
|
xml_node<>* child;
|
|
xml_attribute<> *name, *value, *persist;
|
|
int p;
|
|
|
|
child = vars->first_node("variable");
|
|
while (child)
|
|
{
|
|
name = child->first_attribute("name");
|
|
value = child->first_attribute("value");
|
|
persist = child->first_attribute("persist");
|
|
if(name && value)
|
|
{
|
|
p = persist ? atoi(persist->value()) : 0;
|
|
string temp = value->value();
|
|
string valstr = gui_parse_text(temp);
|
|
|
|
if (valstr.find("+") != string::npos) {
|
|
string val1str = valstr;
|
|
val1str = val1str.substr(0, val1str.find('+'));
|
|
string val2str = valstr;
|
|
val2str = val2str.substr(val2str.find('+') + 1, string::npos);
|
|
int val1 = atoi(val1str.c_str());
|
|
int val2 = atoi(val2str.c_str());
|
|
int val = val1 + val2;
|
|
|
|
DataManager::SetValue(name->value(), val, p);
|
|
} else if (valstr.find("-") != string::npos) {
|
|
string val1str = valstr;
|
|
val1str = val1str.substr(0, val1str.find('-'));
|
|
string val2str = valstr;
|
|
val2str = val2str.substr(val2str.find('-') + 1, string::npos);
|
|
int val1 = atoi(val1str.c_str());
|
|
int val2 = atoi(val2str.c_str());
|
|
int val = val1 - val2;
|
|
|
|
DataManager::SetValue(name->value(), val, p);
|
|
} else {
|
|
DataManager::SetValue(name->value(), valstr, p);
|
|
}
|
|
}
|
|
|
|
child = child->next_sibling("variable");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int PageSet::LoadPages(xml_node<>* pages)
|
|
{
|
|
xml_node<>* child;
|
|
|
|
if (!pages)
|
|
return -1;
|
|
|
|
child = pages->first_node("page");
|
|
while (child != NULL)
|
|
{
|
|
Page* page = new Page(child, &templates);
|
|
if (page->GetName().empty())
|
|
{
|
|
LOGERR("Unable to process load page\n");
|
|
delete page;
|
|
}
|
|
else
|
|
{
|
|
mPages.push_back(page);
|
|
}
|
|
child = child->next_sibling("page");
|
|
}
|
|
if (mPages.size() > 0)
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
int PageSet::IsCurrentPage(Page* page)
|
|
{
|
|
return ((mCurrentPage && mCurrentPage == page) ? 1 : 0);
|
|
}
|
|
|
|
int PageSet::Render(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = (mCurrentPage ? mCurrentPage->Render() : -1);
|
|
if (ret < 0)
|
|
return ret;
|
|
ret = (mOverlayPage ? mOverlayPage->Render() : -1);
|
|
return ret;
|
|
}
|
|
|
|
int PageSet::Update(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = (mCurrentPage ? mCurrentPage->Update() : -1);
|
|
if (ret < 0 || ret > 1)
|
|
return ret;
|
|
ret = (mOverlayPage ? mOverlayPage->Update() : -1);
|
|
return ret;
|
|
}
|
|
|
|
int PageSet::NotifyTouch(TOUCH_STATE state, int x, int y)
|
|
{
|
|
if (mOverlayPage)
|
|
return (mOverlayPage->NotifyTouch(state, x, y));
|
|
|
|
return (mCurrentPage ? mCurrentPage->NotifyTouch(state, x, y) : -1);
|
|
}
|
|
|
|
int PageSet::NotifyKey(int key, bool down)
|
|
{
|
|
if (mOverlayPage)
|
|
return (mOverlayPage->NotifyKey(key, down));
|
|
|
|
return (mCurrentPage ? mCurrentPage->NotifyKey(key, down) : -1);
|
|
}
|
|
|
|
int PageSet::NotifyKeyboard(int key)
|
|
{
|
|
if (mOverlayPage)
|
|
return (mOverlayPage->NotifyKeyboard(key));
|
|
|
|
return (mCurrentPage ? mCurrentPage->NotifyKeyboard(key) : -1);
|
|
}
|
|
|
|
int PageSet::SetKeyBoardFocus(int inFocus)
|
|
{
|
|
if (mOverlayPage)
|
|
return (mOverlayPage->SetKeyBoardFocus(inFocus));
|
|
|
|
return (mCurrentPage ? mCurrentPage->SetKeyBoardFocus(inFocus) : -1);
|
|
}
|
|
|
|
int PageSet::NotifyVarChange(std::string varName, std::string value)
|
|
{
|
|
if (mOverlayPage)
|
|
mOverlayPage->NotifyVarChange(varName, value);
|
|
|
|
return (mCurrentPage ? mCurrentPage->NotifyVarChange(varName, value) : -1);
|
|
}
|
|
|
|
int PageManager::LoadPackage(std::string name, std::string package, std::string startpage)
|
|
{
|
|
int fd;
|
|
ZipArchive zip, *pZip = NULL;
|
|
long len;
|
|
char* xmlFile = NULL;
|
|
PageSet* pageSet = NULL;
|
|
int ret;
|
|
MemMapping map;
|
|
|
|
// Open the XML file
|
|
LOGINFO("Loading package: %s (%s)\n", name.c_str(), package.c_str());
|
|
if (package.size() > 4 && package.substr(package.size() - 4) != ".zip")
|
|
{
|
|
LOGINFO("Load XML directly\n");
|
|
// We can try to load the XML directly...
|
|
struct stat st;
|
|
if(stat(package.c_str(),&st) != 0)
|
|
return -1;
|
|
|
|
len = st.st_size;
|
|
xmlFile = (char*) malloc(len + 1);
|
|
if (!xmlFile)
|
|
return -1;
|
|
|
|
fd = open(package.c_str(), O_RDONLY);
|
|
if (fd == -1)
|
|
goto error;
|
|
|
|
read(fd, xmlFile, len);
|
|
close(fd);
|
|
}
|
|
else
|
|
{
|
|
LOGINFO("Loading zip theme\n");
|
|
if (!TWFunc::Path_Exists(package))
|
|
return -1;
|
|
if (sysMapFile(package.c_str(), &map) != 0) {
|
|
LOGERR("Failed to map '%s'\n", package.c_str());
|
|
return -1;
|
|
}
|
|
if (mzOpenZipArchive(map.addr, map.length, &zip)) {
|
|
LOGERR("Unable to open zip archive '%s'\n", package.c_str());
|
|
sysReleaseMap(&map);
|
|
return -1;
|
|
}
|
|
pZip = &zip;
|
|
const ZipEntry* ui_xml = mzFindZipEntry(&zip, "ui.xml");
|
|
if (ui_xml == NULL)
|
|
{
|
|
LOGERR("Unable to locate ui.xml in zip file\n");
|
|
goto error;
|
|
}
|
|
|
|
// Allocate the buffer for the file
|
|
len = mzGetZipEntryUncompLen(ui_xml);
|
|
xmlFile = (char*) malloc(len + 1);
|
|
if (!xmlFile)
|
|
goto error;
|
|
|
|
if (!mzExtractZipEntryToBuffer(&zip, ui_xml, (unsigned char*) xmlFile))
|
|
{
|
|
LOGERR("Unable to extract ui.xml\n");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
// NULL-terminate the string
|
|
xmlFile[len] = 0x00;
|
|
|
|
// Before loading, mCurrentSet must be the loading package so we can find resources
|
|
pageSet = mCurrentSet;
|
|
mCurrentSet = new PageSet(xmlFile);
|
|
|
|
ret = mCurrentSet->Load(pZip);
|
|
if (ret == 0)
|
|
{
|
|
mCurrentSet->SetPage(startpage);
|
|
mPageSets.insert(std::pair<std::string, PageSet*>(name, mCurrentSet));
|
|
}
|
|
else
|
|
{
|
|
LOGERR("Package %s failed to load.\n", name.c_str());
|
|
}
|
|
|
|
// The first successful package we loaded is the base
|
|
if (mBaseSet == NULL)
|
|
mBaseSet = mCurrentSet;
|
|
|
|
mCurrentSet = pageSet;
|
|
|
|
if (pZip) {
|
|
mzCloseZipArchive(pZip);
|
|
sysReleaseMap(&map);
|
|
}
|
|
return ret;
|
|
|
|
error:
|
|
LOGERR("An internal error has occurred.\n");
|
|
if (pZip) {
|
|
mzCloseZipArchive(pZip);
|
|
sysReleaseMap(&map);
|
|
}
|
|
if (xmlFile)
|
|
free(xmlFile);
|
|
return -1;
|
|
}
|
|
|
|
PageSet* PageManager::FindPackage(std::string name)
|
|
{
|
|
std::map<std::string, PageSet*>::iterator iter;
|
|
|
|
iter = mPageSets.find(name);
|
|
if (iter != mPageSets.end())
|
|
return (*iter).second;
|
|
|
|
LOGERR("Unable to locate package %s\n", name.c_str());
|
|
return NULL;
|
|
}
|
|
|
|
PageSet* PageManager::SelectPackage(std::string name)
|
|
{
|
|
LOGINFO("Switching packages (%s)\n", name.c_str());
|
|
PageSet* tmp;
|
|
|
|
tmp = FindPackage(name);
|
|
if (tmp)
|
|
{
|
|
mCurrentSet = tmp;
|
|
mCurrentSet->NotifyVarChange("", "");
|
|
}
|
|
else
|
|
LOGERR("Unable to find package.\n");
|
|
|
|
return mCurrentSet;
|
|
}
|
|
|
|
int PageManager::ReloadPackage(std::string name, std::string package)
|
|
{
|
|
std::map<std::string, PageSet*>::iterator iter;
|
|
|
|
iter = mPageSets.find(name);
|
|
if (iter == mPageSets.end())
|
|
return -1;
|
|
|
|
if(mMouseCursor)
|
|
mMouseCursor->ResetData(gr_fb_width(), gr_fb_height());
|
|
|
|
PageSet* set = (*iter).second;
|
|
mPageSets.erase(iter);
|
|
|
|
if (LoadPackage(name, package, "main") != 0)
|
|
{
|
|
LOGERR("Failed to load package.\n");
|
|
mPageSets.insert(std::pair<std::string, PageSet*>(name, set));
|
|
return -1;
|
|
}
|
|
if (mCurrentSet == set)
|
|
SelectPackage(name);
|
|
if (mBaseSet == set)
|
|
mBaseSet = mCurrentSet;
|
|
delete set;
|
|
return 0;
|
|
}
|
|
|
|
void PageManager::ReleasePackage(std::string name)
|
|
{
|
|
std::map<std::string, PageSet*>::iterator iter;
|
|
|
|
iter = mPageSets.find(name);
|
|
if (iter == mPageSets.end())
|
|
return;
|
|
|
|
PageSet* set = (*iter).second;
|
|
mPageSets.erase(iter);
|
|
delete set;
|
|
return;
|
|
}
|
|
|
|
int PageManager::ChangePage(std::string name)
|
|
{
|
|
DataManager::SetValue("tw_operation_state", 0);
|
|
int ret = (mCurrentSet ? mCurrentSet->SetPage(name) : -1);
|
|
return ret;
|
|
}
|
|
|
|
int PageManager::ChangeOverlay(std::string name)
|
|
{
|
|
if (name.empty())
|
|
return mCurrentSet->SetOverlay(NULL);
|
|
else
|
|
{
|
|
Page* page = mBaseSet ? mBaseSet->FindPage(name) : NULL;
|
|
return mCurrentSet->SetOverlay(page);
|
|
}
|
|
}
|
|
|
|
Resource* PageManager::FindResource(std::string name)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->FindResource(name) : NULL);
|
|
}
|
|
|
|
Resource* PageManager::FindResource(std::string package, std::string name)
|
|
{
|
|
PageSet* tmp;
|
|
|
|
tmp = FindPackage(name);
|
|
return (tmp ? tmp->FindResource(name) : NULL);
|
|
}
|
|
|
|
int PageManager::SwitchToConsole(void)
|
|
{
|
|
PageSet* console = new PageSet(NULL);
|
|
|
|
mCurrentSet = console;
|
|
return 0;
|
|
}
|
|
|
|
int PageManager::EndConsole(void)
|
|
{
|
|
if (mCurrentSet && mBaseSet) {
|
|
delete mCurrentSet;
|
|
mCurrentSet = mBaseSet;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int PageManager::IsCurrentPage(Page* page)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->IsCurrentPage(page) : 0);
|
|
}
|
|
|
|
int PageManager::Render(void)
|
|
{
|
|
int res = (mCurrentSet ? mCurrentSet->Render() : -1);
|
|
if(mMouseCursor)
|
|
mMouseCursor->Render();
|
|
return res;
|
|
}
|
|
|
|
HardwareKeyboard *PageManager::GetHardwareKeyboard()
|
|
{
|
|
if(!mHardwareKeyboard)
|
|
mHardwareKeyboard = new HardwareKeyboard();
|
|
return mHardwareKeyboard;
|
|
}
|
|
|
|
MouseCursor *PageManager::GetMouseCursor()
|
|
{
|
|
if(!mMouseCursor)
|
|
mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
|
|
return mMouseCursor;
|
|
}
|
|
|
|
void PageManager::LoadCursorData(xml_node<>* node)
|
|
{
|
|
if(!mMouseCursor)
|
|
mMouseCursor = new MouseCursor(gr_fb_width(), gr_fb_height());
|
|
|
|
mMouseCursor->LoadData(node);
|
|
}
|
|
|
|
int PageManager::Update(void)
|
|
{
|
|
#ifndef TW_NO_SCREEN_TIMEOUT
|
|
if(blankTimer.IsScreenOff())
|
|
return 0;
|
|
#endif
|
|
|
|
int res = (mCurrentSet ? mCurrentSet->Update() : -1);
|
|
|
|
if(mMouseCursor)
|
|
{
|
|
int c_res = mMouseCursor->Update();
|
|
if(c_res > res)
|
|
res = c_res;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int PageManager::NotifyTouch(TOUCH_STATE state, int x, int y)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->NotifyTouch(state, x, y) : -1);
|
|
}
|
|
|
|
int PageManager::NotifyKey(int key, bool down)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->NotifyKey(key, down) : -1);
|
|
}
|
|
|
|
int PageManager::NotifyKeyboard(int key)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->NotifyKeyboard(key) : -1);
|
|
}
|
|
|
|
int PageManager::SetKeyBoardFocus(int inFocus)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->SetKeyBoardFocus(inFocus) : -1);
|
|
}
|
|
|
|
int PageManager::NotifyVarChange(std::string varName, std::string value)
|
|
{
|
|
return (mCurrentSet ? mCurrentSet->NotifyVarChange(varName, value) : -1);
|
|
}
|
|
|
|
extern "C" void gui_notifyVarChange(const char *name, const char* value)
|
|
{
|
|
if (!gGuiRunning)
|
|
return;
|
|
|
|
PageManager::NotifyVarChange(name, value);
|
|
}
|