mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
Added support for theme "extras".
Fixed a few crashes (e.g. TextListComponent::applyTheme).
This commit is contained in:
parent
e6d0da998b
commit
8a52866ca6
|
@ -155,6 +155,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Sound.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.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/VolumeControl.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.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/Sound.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ThemeData.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/VolumeControl.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Window.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/XMLReader.cpp
|
||||||
|
|
|
@ -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());
|
Eigen::Vector2f scale = getParent() ? getParent()->getSize() : Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
|
|
||||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
|
||||||
|
if(!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
if(properties & POSITION && elem->has("pos"))
|
if(properties & POSITION && elem->has("pos"))
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
#include "pugiXML/pugixml.hpp"
|
#include "pugiXML/pugixml.hpp"
|
||||||
#include <boost/assign.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
|
std::map< std::string, std::map<std::string, ThemeData::ElementPropertyType> > ThemeData::sElementMap = boost::assign::map_list_of
|
||||||
("image", boost::assign::map_list_of
|
("image", boost::assign::map_list_of
|
||||||
("pos", NORMALIZED_PAIR)
|
("pos", NORMALIZED_PAIR)
|
||||||
|
@ -31,6 +34,9 @@ std::map< std::string, std::map<std::string, ThemeData::ElementPropertyType> > T
|
||||||
("secondaryColor", COLOR)
|
("secondaryColor", COLOR)
|
||||||
("fontPath", PATH)
|
("fontPath", PATH)
|
||||||
("fontSize", FLOAT))
|
("fontSize", FLOAT))
|
||||||
|
("container", boost::assign::map_list_of
|
||||||
|
("pos", NORMALIZED_PAIR)
|
||||||
|
("size", NORMALIZED_PAIR))
|
||||||
("sound", boost::assign::map_list_of
|
("sound", boost::assign::map_list_of
|
||||||
("path", PATH));
|
("path", PATH));
|
||||||
|
|
||||||
|
@ -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
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,9 @@ namespace ThemeFlags
|
||||||
TILING = 128,
|
TILING = 128,
|
||||||
SOUND = 256,
|
SOUND = 256,
|
||||||
CENTER = 512,
|
CENTER = 512,
|
||||||
TEXT = 1024
|
TEXT = 1024,
|
||||||
|
|
||||||
|
ALL = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +69,20 @@ ThemeException& operator<<(ThemeException& e, T appendMsg)
|
||||||
return e;
|
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
|
class ThemeData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -88,17 +104,8 @@ public:
|
||||||
private:
|
private:
|
||||||
class ThemeView
|
class ThemeView
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
bool mExtrasDirty;
|
|
||||||
std::vector<GuiComponent*> mExtras;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ThemeView() : mExtrasDirty(true) {}
|
|
||||||
virtual ~ThemeView();
|
|
||||||
|
|
||||||
std::map<std::string, ThemeElement> elements;
|
std::map<std::string, ThemeElement> elements;
|
||||||
|
|
||||||
const std::vector<GuiComponent*>& getExtras(Window* window);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -125,6 +132,8 @@ public:
|
||||||
// If expectedType is an empty string, will do no type checking.
|
// 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;
|
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:
|
private:
|
||||||
static std::map< std::string, std::map<std::string, ElementPropertyType> > sElementMap;
|
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;
|
std::map< std::string, std::shared_ptr<Sound> > mSoundCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// okay ideas for applying themes to GuiComponents:
|
// okay ideas for applying themes to GuiComponents:
|
||||||
// 1. ThemeData::applyToImage(component, args)
|
// 1. ThemeData::applyToImage(component, args)
|
||||||
// NO, BECAUSE:
|
// NO, BECAUSE:
|
||||||
|
|
2
src/ThemeDumper.cpp
Normal file
2
src/ThemeDumper.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#include "ThemeDumper.h"
|
||||||
|
|
13
src/ThemeDumper.h
Normal file
13
src/ThemeDumper.h
Normal 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
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
|
@ -35,16 +35,18 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mBackground(window, ":/
|
||||||
mList.setPosition(mSize.x() * 0.175f, mSize.y() * 0.05f);
|
mList.setPosition(mSize.x() * 0.175f, mSize.y() * 0.05f);
|
||||||
mList.setSize(mSize.x() * 0.65f, mSize.y() * 0.9f);
|
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));
|
mBackground.fitTo(Eigen::Vector2f(mList.getSize().x(), mSize.y()), Eigen::Vector3f(mList.getPosition().x(), 0, 0));
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
|
|
||||||
mTheme = std::make_shared<ThemeData>();
|
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.setSelectorColor(0xBBBBBBFF);
|
||||||
mList.setColor(0, 0x0000FFFF);
|
mList.setColor(0, 0x0000FFFF);
|
||||||
mList.setColor(1, 0xFF0000FF);
|
mList.setColor(1, 0xFF0000FF);
|
||||||
// TODO - set font size to 0.09f
|
|
||||||
|
|
||||||
addChild(&mList);
|
addChild(&mList);
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,8 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const s
|
||||||
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
||||||
setResize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale), true);
|
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"));
|
setOrigin(elem->get<Eigen::Vector2f>("origin"));
|
||||||
|
|
||||||
if(properties & PATH && elem->has("path"))
|
if(properties & PATH && elem->has("path"))
|
||||||
|
|
|
@ -412,6 +412,8 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, c
|
||||||
GuiComponent::applyTheme(theme, view, element, properties);
|
GuiComponent::applyTheme(theme, view, element, properties);
|
||||||
|
|
||||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist");
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist");
|
||||||
|
if(!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
if(properties & COLOR)
|
if(properties & COLOR)
|
||||||
|
|
|
@ -42,6 +42,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& them
|
||||||
mHeaderImage.setResize(0, mSize.y() * 0.185f, true);
|
mHeaderImage.setResize(0, mSize.y() * 0.185f, true);
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
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);
|
mDescription.applyTheme(theme, getName(), "description", POSITION | FONT_PATH | FONT_SIZE | COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "../ViewController.h"
|
#include "../ViewController.h"
|
||||||
|
|
||||||
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGameListView(window, root),
|
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.setText("Header");
|
||||||
mHeaderText.setSize(mSize.x(), 0);
|
mHeaderText.setSize(mSize.x(), 0);
|
||||||
|
@ -19,13 +19,15 @@ ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGame
|
||||||
|
|
||||||
addChild(&mHeaderText);
|
addChild(&mHeaderText);
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
|
addChild(&mThemeExtras);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
{
|
{
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mBackground.applyTheme(theme, getName(), "background", PATH | TILING);
|
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())
|
if(mHeaderImage.hasImage())
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,5 +32,7 @@ protected:
|
||||||
ImageComponent mHeaderImage;
|
ImageComponent mHeaderImage;
|
||||||
ImageComponent mBackground;
|
ImageComponent mBackground;
|
||||||
|
|
||||||
|
ThemeExtras mThemeExtras;
|
||||||
|
|
||||||
std::stack<FileData*> mCursorStack;
|
std::stack<FileData*> mCursorStack;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue