Added support for theme "extras".

Fixed a few crashes (e.g. TextListComponent::applyTheme).
This commit is contained in:
Aloshi 2014-01-03 08:26:39 -06:00
parent e6d0da998b
commit 8a52866ca6
12 changed files with 108 additions and 25 deletions

View file

@ -155,6 +155,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeDumper.h
${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.h
@ -233,6 +234,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeDumper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/VolumeControl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp

View file

@ -232,6 +232,8 @@ void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std
Eigen::Vector2f scale = getParent() ? getParent()->getSize() : Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
if(!elem)
return;
using namespace ThemeFlags;
if(properties & POSITION && elem->has("pos"))

View file

@ -7,6 +7,9 @@
#include "pugiXML/pugixml.hpp"
#include <boost/assign.hpp>
#include "components/ImageComponent.h"
#include "components/TextComponent.h"
std::map< std::string, std::map<std::string, ThemeData::ElementPropertyType> > ThemeData::sElementMap = boost::assign::map_list_of
("image", boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
@ -31,6 +34,9 @@ std::map< std::string, std::map<std::string, ThemeData::ElementPropertyType> > T
("secondaryColor", COLOR)
("fontPath", PATH)
("fontSize", FLOAT))
("container", boost::assign::map_list_of
("pos", NORMALIZED_PAIR)
("size", NORMALIZED_PAIR))
("sound", boost::assign::map_list_of
("path", PATH));
@ -211,7 +217,7 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
element.type = root.name();
element.extra = root.attribute("extra").as_bool(false);
for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
{
auto typeIt = typeMap.find(node.name());
@ -269,12 +275,6 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
}
}
ThemeData::ThemeView::~ThemeView()
{
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
delete *it;
}
const ThemeData::ThemeElement* ThemeData::getElement(const std::string& view, const std::string& element, const std::string& expectedType) const
{
@ -321,3 +321,48 @@ void ThemeData::playSound(const std::string& elementName)
mSoundCache[path] = sound;
}
}
std::vector<GuiComponent*> ThemeData::makeExtras(const std::shared_ptr<ThemeData>& theme, const std::string& view, Window* window)
{
std::vector<GuiComponent*> comps;
auto viewIt = theme->mViews.find(view);
if(viewIt == theme->mViews.end())
return comps;
for(auto it = viewIt->second.elements.begin(); it != viewIt->second.elements.end(); it++)
{
if(it->second.extra)
{
GuiComponent* comp = NULL;
const std::string& t = it->second.type;
if(t == "image")
comp = new ImageComponent(window);
else if(t == "text")
comp = new TextComponent(window);
comp->applyTheme(theme, view, it->first, ThemeFlags::ALL);
comps.push_back(comp);
}
}
return comps;
}
void ThemeExtras::setExtras(const std::vector<GuiComponent*>& extras)
{
// delete old extras (if any)
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
delete *it;
mExtras = extras;
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
addChild(*it);
}
ThemeExtras::~ThemeExtras()
{
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
delete *it;
}

View file

@ -35,7 +35,9 @@ namespace ThemeFlags
TILING = 128,
SOUND = 256,
CENTER = 512,
TEXT = 1024
TEXT = 1024,
ALL = 0xFFFFFFFF
};
}
@ -67,6 +69,20 @@ ThemeException& operator<<(ThemeException& e, T appendMsg)
return e;
}
class ThemeExtras : public GuiComponent
{
public:
ThemeExtras(Window* window) : GuiComponent(window) {};
// will take ownership of the components within extras (delete them in destructor or when setExtras is called again)
void setExtras(const std::vector<GuiComponent*>& extras);
virtual ~ThemeExtras();
private:
std::vector<GuiComponent*> mExtras;
};
class ThemeData
{
public:
@ -88,17 +104,8 @@ public:
private:
class ThemeView
{
private:
bool mExtrasDirty;
std::vector<GuiComponent*> mExtras;
public:
ThemeView() : mExtrasDirty(true) {}
virtual ~ThemeView();
std::map<std::string, ThemeElement> elements;
const std::vector<GuiComponent*>& getExtras(Window* window);
};
public:
@ -125,6 +132,8 @@ public:
// If expectedType is an empty string, will do no type checking.
const ThemeElement* getElement(const std::string& view, const std::string& element, const std::string& expectedType) const;
static std::vector<GuiComponent*> makeExtras(const std::shared_ptr<ThemeData>& theme, const std::string& view, Window* window);
private:
static std::map< std::string, std::map<std::string, ElementPropertyType> > sElementMap;
@ -141,7 +150,6 @@ private:
std::map< std::string, std::shared_ptr<Sound> > mSoundCache;
};
// okay ideas for applying themes to GuiComponents:
// 1. ThemeData::applyToImage(component, args)
// NO, BECAUSE:

2
src/ThemeDumper.cpp Normal file
View file

@ -0,0 +1,2 @@
#include "ThemeDumper.h"

13
src/ThemeDumper.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "ThemeData.h"
// Should be able to:
// 1. Take a list of "tests" to run.
// a. Each test works by calling setTheme on a theme with a "fake" theme that records all getElement() access.
// 2. Results can be output to a text file, OR compared with a loaded theme to create warnings about potentially unused elements.
class ThemeDumper
{
};

View file

@ -35,16 +35,18 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mBackground(window, ":/
mList.setPosition(mSize.x() * 0.175f, mSize.y() * 0.05f);
mList.setSize(mSize.x() * 0.65f, mSize.y() * 0.9f);
using namespace ThemeFlags;
mBackground.applyTheme(mTheme, "menu", "background", PATH);
mBackground.fitTo(Eigen::Vector2f(mList.getSize().x(), mSize.y()), Eigen::Vector3f(mList.getPosition().x(), 0, 0));
addChild(&mBackground);
mTheme = std::make_shared<ThemeData>();
using namespace ThemeFlags;
mList.applyTheme(mTheme, "common", "menu", FONT_PATH | COLOR);
mList.setFont(Font::get((int)(0.09f * Renderer::getScreenHeight())));
mList.applyTheme(mTheme, "menu", "menulist", FONT_PATH | COLOR);
mList.setSelectorColor(0xBBBBBBFF);
mList.setColor(0, 0x0000FFFF);
mList.setColor(1, 0xFF0000FF);
// TODO - set font size to 0.09f
addChild(&mList);
}

View file

@ -269,7 +269,8 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const s
if(properties & ThemeFlags::SIZE && elem->has("size"))
setResize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale), true);
if(properties & ORIGIN && elem->has("origin"))
// position + size also implies origin
if((properties & ORIGIN || (properties & POSITION && properties & ThemeFlags::SIZE)) && elem->has("origin"))
setOrigin(elem->get<Eigen::Vector2f>("origin"));
if(properties & PATH && elem->has("path"))

View file

@ -412,6 +412,8 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, c
GuiComponent::applyTheme(theme, view, element, properties);
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist");
if(!elem)
return;
using namespace ThemeFlags;
if(properties & COLOR)

View file

@ -42,6 +42,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
mHeaderImage.setResize(0, mSize.y() * 0.185f, true);
using namespace ThemeFlags;
mImage.applyTheme(theme, getName(), "gameimage", POSITION | ThemeFlags::SIZE);
mDescContainer.applyTheme(theme, getName(), "infoPanel", POSITION | ThemeFlags::SIZE);
mDescription.applyTheme(theme, getName(), "description", POSITION | FONT_PATH | FONT_SIZE | COLOR);
}

View file

@ -4,7 +4,7 @@
#include "../ViewController.h"
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGameListView(window, root),
mHeaderText(window), mHeaderImage(window), mBackground(window)
mHeaderText(window), mHeaderImage(window), mBackground(window), mThemeExtras(window)
{
mHeaderText.setText("Header");
mHeaderText.setSize(mSize.x(), 0);
@ -19,14 +19,16 @@ ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGame
addChild(&mHeaderText);
addChild(&mBackground);
addChild(&mThemeExtras);
}
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
using namespace ThemeFlags;
mBackground.applyTheme(theme, getName(), "background", PATH | TILING);
mHeaderImage.applyTheme(theme, getName(), "header", PATH);
mHeaderImage.applyTheme(theme, getName(), "header", POSITION | ThemeFlags::SIZE | PATH);
mThemeExtras.setExtras(ThemeData::makeExtras(theme, getName(), mWindow));
if(mHeaderImage.hasImage())
{
removeChild(&mHeaderText);

View file

@ -32,5 +32,7 @@ protected:
ImageComponent mHeaderImage;
ImageComponent mBackground;
ThemeExtras mThemeExtras;
std::stack<FileData*> mCursorStack;
};