2012-08-10 19:28:34 +00:00
|
|
|
#include "GuiTheme.h"
|
|
|
|
#include "../MathExp.h"
|
|
|
|
#include <iostream>
|
2012-08-14 01:27:39 +00:00
|
|
|
#include "GuiGameList.h"
|
2012-08-10 19:28:34 +00:00
|
|
|
#include "GuiImage.h"
|
2012-08-11 04:17:52 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
2012-08-13 18:32:53 +00:00
|
|
|
#include <sstream>
|
2012-09-15 21:24:33 +00:00
|
|
|
#include "../Renderer.h"
|
2012-08-13 18:32:53 +00:00
|
|
|
|
|
|
|
int GuiTheme::getPrimaryColor() { return mListPrimaryColor; }
|
|
|
|
int GuiTheme::getSecondaryColor() { return mListSecondaryColor; }
|
|
|
|
int GuiTheme::getSelectorColor() { return mListSelectorColor; }
|
|
|
|
int GuiTheme::getDescColor() { return mDescColor; }
|
2012-10-10 13:51:48 +00:00
|
|
|
int GuiTheme::getFastSelectColor() { return mFastSelectColor; }
|
2012-08-13 18:32:53 +00:00
|
|
|
bool GuiTheme::getHeaderHidden() { return mHideHeader; }
|
|
|
|
bool GuiTheme::getDividersHidden() { return mHideDividers; }
|
2012-08-14 01:27:39 +00:00
|
|
|
bool GuiTheme::getListCentered() { return mListCentered; }
|
2012-08-10 19:28:34 +00:00
|
|
|
|
2012-09-15 21:24:33 +00:00
|
|
|
float GuiTheme::getListOffsetX() { return mListOffsetX; }
|
|
|
|
float GuiTheme::getGameImageOffsetY() { return mGameImageOffsetY; }
|
|
|
|
float GuiTheme::getListTextOffsetX() { return mListTextOffsetX; }
|
|
|
|
|
2012-10-01 03:29:55 +00:00
|
|
|
int GuiTheme::getSelectedTextColor() { return mListSelectedColor; }
|
|
|
|
|
2012-10-07 22:59:20 +00:00
|
|
|
GuiBoxData GuiTheme::getBoxData() { return mBoxData; }
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
GuiTheme::GuiTheme(std::string path)
|
|
|
|
{
|
2012-08-14 01:27:39 +00:00
|
|
|
setDefaults();
|
2012-08-13 18:32:53 +00:00
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
if(!path.empty())
|
|
|
|
readXML(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
GuiTheme::~GuiTheme()
|
|
|
|
{
|
|
|
|
deleteComponents();
|
|
|
|
}
|
|
|
|
|
2012-08-14 01:27:39 +00:00
|
|
|
void GuiTheme::setDefaults()
|
|
|
|
{
|
|
|
|
mListPrimaryColor = 0x0000FF;
|
|
|
|
mListSecondaryColor = 0x00FF00;
|
|
|
|
mListSelectorColor = 0x000000;
|
2012-10-01 03:29:55 +00:00
|
|
|
mListSelectedColor = -1; //-1 = use original list color when selected
|
2012-08-14 01:27:39 +00:00
|
|
|
mDescColor = 0x0000FF;
|
2012-10-10 13:51:48 +00:00
|
|
|
mFastSelectColor = 0xFF0000;
|
2012-08-14 01:27:39 +00:00
|
|
|
mHideHeader = false;
|
|
|
|
mHideDividers = false;
|
|
|
|
mListCentered = true;
|
2012-09-15 21:24:33 +00:00
|
|
|
|
|
|
|
mListOffsetX = 0.5;
|
|
|
|
mListTextOffsetX = 0.005;
|
|
|
|
mGameImageOffsetY = (float)Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight();
|
2012-10-07 22:59:20 +00:00
|
|
|
|
|
|
|
mBoxData.backgroundPath = "";
|
|
|
|
mBoxData.backgroundTiled = false;
|
|
|
|
mBoxData.horizontalPath = "";
|
|
|
|
mBoxData.horizontalTiled = false;
|
|
|
|
mBoxData.verticalPath = "";
|
|
|
|
mBoxData.verticalTiled = false;
|
|
|
|
mBoxData.cornerPath = "";
|
2012-08-14 01:27:39 +00:00
|
|
|
}
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
void GuiTheme::deleteComponents()
|
|
|
|
{
|
|
|
|
for(unsigned int i = 0; i < mComponentVector.size(); i++)
|
|
|
|
{
|
|
|
|
delete mComponentVector.at(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
mComponentVector.clear();
|
2012-08-11 04:17:52 +00:00
|
|
|
|
|
|
|
clearChildren();
|
2012-08-10 19:28:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GuiTheme::readXML(std::string path)
|
|
|
|
{
|
2012-08-12 14:43:09 +00:00
|
|
|
if(mPath == path)
|
|
|
|
return;
|
|
|
|
|
2012-08-14 01:27:39 +00:00
|
|
|
setDefaults();
|
2012-08-10 19:28:34 +00:00
|
|
|
deleteComponents();
|
|
|
|
|
2012-08-11 04:17:52 +00:00
|
|
|
mPath = path;
|
|
|
|
|
|
|
|
if(path.empty())
|
|
|
|
return;
|
|
|
|
|
2012-10-05 13:44:18 +00:00
|
|
|
//std::cout << "Loading theme \"" << path << "\"...\n";
|
2012-08-10 19:28:34 +00:00
|
|
|
|
|
|
|
pugi::xml_document doc;
|
|
|
|
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
|
|
|
|
|
|
|
if(!result)
|
|
|
|
{
|
|
|
|
std::cerr << "Error parsing theme \"" << path << "\"!\n";
|
|
|
|
std::cerr << " " << result.description() << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pugi::xml_node root = doc.child("theme");
|
|
|
|
|
2012-08-13 18:32:53 +00:00
|
|
|
//load non-component theme stuff
|
2012-09-15 21:24:33 +00:00
|
|
|
mListPrimaryColor = resolveColor(root.child("listPrimaryColor").text().get(), mListPrimaryColor);
|
|
|
|
mListSecondaryColor = resolveColor(root.child("listSecondaryColor").text().get(), mListSecondaryColor);
|
|
|
|
mListSelectorColor = resolveColor(root.child("listSelectorColor").text().get(), mListSelectorColor);
|
2012-10-01 03:29:55 +00:00
|
|
|
mListSelectedColor = resolveColor(root.child("listSelectedColor").text().get(), mListSelectedColor);
|
2012-09-15 21:24:33 +00:00
|
|
|
mDescColor = resolveColor(root.child("descColor").text().get(), mDescColor);
|
2012-10-10 13:51:48 +00:00
|
|
|
mFastSelectColor = resolveColor(root.child("fastSelectColor").text().get(), mFastSelectColor);
|
2012-08-13 18:32:53 +00:00
|
|
|
mHideHeader = root.child("hideHeader");
|
|
|
|
mHideDividers = root.child("hideDividers");
|
2012-08-14 01:27:39 +00:00
|
|
|
mListCentered = !root.child("listLeftAlign");
|
2012-08-13 18:32:53 +00:00
|
|
|
|
2012-10-07 22:59:20 +00:00
|
|
|
//GuiBox theming data
|
|
|
|
mBoxData.backgroundPath = expandPath(root.child("boxBackground").text().get());
|
|
|
|
mBoxData.backgroundTiled = root.child("boxBackgroundTiled");
|
|
|
|
mBoxData.horizontalPath = expandPath(root.child("boxHorizontal").text().get());
|
|
|
|
mBoxData.horizontalTiled = root.child("boxHorizontalTiled");
|
|
|
|
mBoxData.verticalPath = expandPath(root.child("boxVertical").text().get());
|
|
|
|
mBoxData.verticalTiled = root.child("boxVerticalTiled");
|
|
|
|
mBoxData.cornerPath = expandPath(root.child("boxCorner").text().get());
|
|
|
|
|
2012-09-15 21:24:33 +00:00
|
|
|
mListOffsetX = strToFloat(root.child("listOffsetX").text().get(), mListOffsetX);
|
|
|
|
mGameImageOffsetY = strToFloat(root.child("gameImageOffsetY").text().get(), mGameImageOffsetY);
|
|
|
|
mListTextOffsetX = strToFloat(root.child("listTextOffsetX").text().get(), mListTextOffsetX);
|
|
|
|
|
|
|
|
//recursively create children for all <components> with proper parenting
|
|
|
|
createComponentChildren(root, this);
|
2012-08-10 19:28:34 +00:00
|
|
|
|
2012-10-05 13:44:18 +00:00
|
|
|
//std::cout << "Finished parsing theme.\n";
|
2012-08-10 19:28:34 +00:00
|
|
|
}
|
|
|
|
|
2012-09-15 21:24:33 +00:00
|
|
|
void GuiTheme::createComponentChildren(pugi::xml_node node, GuiComponent* parent)
|
|
|
|
{
|
|
|
|
for(pugi::xml_node data = node.child("component"); data; data = data.next_sibling("component"))
|
|
|
|
{
|
|
|
|
GuiComponent* nextComp = createElement(data, parent);
|
|
|
|
|
|
|
|
if(nextComp)
|
|
|
|
createComponentChildren(data, nextComp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
GuiComponent* GuiTheme::createElement(pugi::xml_node data, GuiComponent* parent)
|
|
|
|
{
|
|
|
|
std::string type = data.child("type").text().get();
|
|
|
|
|
|
|
|
if(type == "image")
|
|
|
|
{
|
2012-08-11 04:17:52 +00:00
|
|
|
std::string path = expandPath(data.child("path").text().get());
|
|
|
|
|
|
|
|
if(!boost::filesystem::exists(path))
|
|
|
|
{
|
|
|
|
std::cerr << "Error - theme image \"" << path << "\" does not exist.\n";
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
std::string pos = data.child("pos").text().get();
|
|
|
|
std::string dim = data.child("dim").text().get();
|
2012-08-13 18:32:53 +00:00
|
|
|
std::string origin = data.child("origin").text().get();
|
|
|
|
|
|
|
|
bool tiled = data.child("tiled");
|
2012-08-10 19:28:34 +00:00
|
|
|
|
|
|
|
//split position and dimension information
|
2012-08-13 18:32:53 +00:00
|
|
|
std::string posX, posY;
|
|
|
|
splitString(pos, ' ', &posX, &posY);
|
|
|
|
|
|
|
|
std::string dimW, dimH;
|
|
|
|
splitString(dim, ' ', &dimW, &dimH);
|
2012-08-10 19:28:34 +00:00
|
|
|
|
2012-08-13 18:32:53 +00:00
|
|
|
std::string originX, originY;
|
|
|
|
splitString(origin, ' ', &originX, &originY);
|
2012-08-10 19:28:34 +00:00
|
|
|
|
2012-10-05 13:44:18 +00:00
|
|
|
//std::cout << "image, x: " << posX << " y: " << posY << " w: " << dimW << " h: " << dimH << " ox: " << originX << " oy: " << originY << " tiled: " << tiled << "\n";
|
2012-08-10 19:28:34 +00:00
|
|
|
|
|
|
|
//resolve to pixels from percentages/variables
|
|
|
|
int x = resolveExp(posX) * Renderer::getScreenWidth();
|
|
|
|
int y = resolveExp(posY) * Renderer::getScreenHeight();
|
|
|
|
int w = resolveExp(dimW) * Renderer::getScreenWidth();
|
|
|
|
int h = resolveExp(dimH) * Renderer::getScreenHeight();
|
|
|
|
|
2012-08-15 06:18:06 +00:00
|
|
|
float ox = strToFloat(originX);
|
|
|
|
float oy = strToFloat(originY);
|
2012-08-13 18:32:53 +00:00
|
|
|
|
|
|
|
GuiImage* comp = new GuiImage(x, y, "", w, h, true);
|
|
|
|
comp->setOrigin(ox, oy);
|
|
|
|
comp->setTiling(tiled);
|
|
|
|
comp->setImage(path);
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
parent->addChild(comp);
|
|
|
|
mComponentVector.push_back(comp);
|
|
|
|
return comp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cerr << "Type \"" << type << "\" unknown!\n";
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-11 04:17:52 +00:00
|
|
|
std::string GuiTheme::expandPath(std::string path)
|
|
|
|
{
|
|
|
|
if(path[0] == '~')
|
|
|
|
path = getenv("HOME") + path.substr(1, path.length() - 1);
|
|
|
|
else if(path[0] == '.')
|
|
|
|
path = boost::filesystem::path(mPath).parent_path().string() + path.substr(1, path.length() - 1);
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
float GuiTheme::resolveExp(std::string str)
|
2012-08-10 19:28:34 +00:00
|
|
|
{
|
|
|
|
MathExp exp;
|
|
|
|
exp.setExpression(str);
|
|
|
|
|
|
|
|
//set variables
|
|
|
|
exp.setVariable("headerHeight", Renderer::getFontHeight(Renderer::LARGE) / Renderer::getScreenHeight());
|
2012-08-14 01:27:39 +00:00
|
|
|
exp.setVariable("infoWidth", GuiGameList::sInfoWidth);
|
2012-08-10 19:28:34 +00:00
|
|
|
|
2012-08-11 04:17:52 +00:00
|
|
|
return exp.eval();
|
2012-08-10 19:28:34 +00:00
|
|
|
}
|
2012-08-13 18:32:53 +00:00
|
|
|
|
|
|
|
int GuiTheme::resolveColor(std::string str, int defaultColor)
|
|
|
|
{
|
|
|
|
if(str.empty())
|
|
|
|
return defaultColor;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << std::hex << str;
|
|
|
|
ss >> ret;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GuiTheme::splitString(std::string str, char delim, std::string* before, std::string* after)
|
|
|
|
{
|
|
|
|
if(str.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t split = str.find(delim);
|
|
|
|
*before = str.substr(0, split);
|
|
|
|
*after = str.substr(split + 1, str.length() - split - 1);
|
|
|
|
}
|
|
|
|
|
2012-09-15 21:24:33 +00:00
|
|
|
float GuiTheme::strToFloat(std::string str, float defaultVal)
|
2012-08-13 18:32:53 +00:00
|
|
|
{
|
|
|
|
if(str.empty())
|
2012-09-15 21:24:33 +00:00
|
|
|
return defaultVal;
|
2012-08-13 18:32:53 +00:00
|
|
|
|
2012-08-15 06:18:06 +00:00
|
|
|
float ret;
|
2012-08-13 18:32:53 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
ss << str;
|
|
|
|
ss >> ret;
|
|
|
|
return ret;
|
|
|
|
}
|