mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-02-18 04:45:39 +00:00
Theme applicators have become the virtual method
GuiComponent::applyTheme(theme, view, element, properties). Applying fonts works now.
This commit is contained in:
parent
8bc33ce309
commit
e6d0da998b
|
@ -233,7 +233,6 @@ 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/ThemeData_applicators.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
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "animations/AnimationController.h"
|
#include "animations/AnimationController.h"
|
||||||
|
#include "ThemeData.h"
|
||||||
|
|
||||||
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
|
GuiComponent::GuiComponent(Window* window) : mWindow(window), mParent(NULL), mOpacity(255),
|
||||||
mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity())
|
mPosition(Eigen::Vector3f::Zero()), mSize(Eigen::Vector2f::Zero()), mTransform(Eigen::Affine3f::Identity())
|
||||||
|
@ -225,3 +226,20 @@ void GuiComponent::stopAnimation(unsigned char slot)
|
||||||
mAnimationMap[slot] = NULL;
|
mAnimationMap[slot] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||||
|
{
|
||||||
|
Eigen::Vector2f scale = getParent() ? getParent()->getSize() : Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "");
|
||||||
|
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
if(properties & POSITION && elem->has("pos"))
|
||||||
|
{
|
||||||
|
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
||||||
|
setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
||||||
|
setSize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale));
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
class Window;
|
class Window;
|
||||||
class Animation;
|
class Animation;
|
||||||
class AnimationController;
|
class AnimationController;
|
||||||
|
class ThemeData;
|
||||||
|
|
||||||
class GuiComponent
|
class GuiComponent
|
||||||
{
|
{
|
||||||
|
@ -66,6 +67,10 @@ public:
|
||||||
virtual void onFocusGained() {};
|
virtual void onFocusGained() {};
|
||||||
virtual void onFocusLost() {};
|
virtual void onFocusLost() {};
|
||||||
|
|
||||||
|
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
||||||
|
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||||
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void renderChildren(const Eigen::Affine3f& transform) const;
|
void renderChildren(const Eigen::Affine3f& transform) const;
|
||||||
|
|
||||||
|
|
|
@ -209,6 +209,7 @@ void ThemeData::parseElement(const pugi::xml_node& root, const std::map<std::str
|
||||||
ThemeException error;
|
ThemeException error;
|
||||||
error.setFiles(mPaths);
|
error.setFiles(mPaths);
|
||||||
|
|
||||||
|
element.type = root.name();
|
||||||
element.extra = root.attribute("extra").as_bool(false);
|
element.extra = root.attribute("extra").as_bool(false);
|
||||||
|
|
||||||
for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
|
for(pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
|
||||||
|
@ -273,3 +274,50 @@ ThemeData::ThemeView::~ThemeView()
|
||||||
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
|
for(auto it = mExtras.begin(); it != mExtras.end(); it++)
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* ThemeData::getElement(const std::string& view, const std::string& element, const std::string& expectedType) const
|
||||||
|
{
|
||||||
|
auto viewIt = mViews.find(view);
|
||||||
|
if(viewIt == mViews.end())
|
||||||
|
{
|
||||||
|
// also check common if the view never existed to begin with
|
||||||
|
viewIt = mViews.find("common");
|
||||||
|
if(viewIt == mViews.end())
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto elemIt = viewIt->second.elements.find(element);
|
||||||
|
if(elemIt == viewIt->second.elements.end()) return NULL;
|
||||||
|
|
||||||
|
if(elemIt->second.type != expectedType && !expectedType.empty())
|
||||||
|
{
|
||||||
|
LOG(LogWarning) << " requested mismatched theme type for [" << view << "." << element << "] - expected \""
|
||||||
|
<< expectedType << "\", got \"" << elemIt->second.type << "\"";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &elemIt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThemeData::playSound(const std::string& elementName)
|
||||||
|
{
|
||||||
|
const ThemeElement* elem = getElement("common", elementName, "sound");
|
||||||
|
if(!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(elem->has("path"))
|
||||||
|
{
|
||||||
|
const std::string path = elem->get<std::string>("path");
|
||||||
|
auto cacheIt = mSoundCache.find(path);
|
||||||
|
if(cacheIt != mSoundCache.end())
|
||||||
|
{
|
||||||
|
cacheIt->second->play();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Sound> sound = std::shared_ptr<Sound>(new Sound(path));
|
||||||
|
sound->play();
|
||||||
|
mSoundCache[path] = sound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ ThemeException& operator<<(ThemeException& e, T appendMsg)
|
||||||
|
|
||||||
class ThemeData
|
class ThemeData
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
|
|
||||||
class ThemeElement
|
class ThemeElement
|
||||||
{
|
{
|
||||||
|
@ -80,11 +80,12 @@ private:
|
||||||
std::map< std::string, boost::variant<Eigen::Vector2f, std::string, unsigned int, float, bool> > properties;
|
std::map< std::string, boost::variant<Eigen::Vector2f, std::string, unsigned int, float, bool> > properties;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T get(const std::string& prop) { return boost::get<T>(properties.at(prop)); }
|
T get(const std::string& prop) const { return boost::get<T>(properties.at(prop)); }
|
||||||
|
|
||||||
inline bool has(const std::string& prop) { return (properties.find(prop) != properties.end()); }
|
inline bool has(const std::string& prop) const { return (properties.find(prop) != properties.end()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
class ThemeView
|
class ThemeView
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -119,17 +120,10 @@ public:
|
||||||
|
|
||||||
void renderExtras(const std::string& view, Window* window, const Eigen::Affine3f& transform);
|
void renderExtras(const std::string& view, Window* window, const Eigen::Affine3f& transform);
|
||||||
|
|
||||||
void applyToImage(const std::string& view, const std::string& element, ImageComponent* image, unsigned int properties);
|
|
||||||
void applyToNinePatch(const std::string& view, const std::string& element, NinePatchComponent* patch, unsigned int properties);
|
|
||||||
void applyToText(const std::string& view, const std::string& element, TextComponent* text, unsigned int properties);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void applyToTextList(const std::string& view, const std::string& element, TextListComponent<T>* list, unsigned int properties);
|
|
||||||
|
|
||||||
void playSound(const std::string& name);
|
void playSound(const std::string& name);
|
||||||
|
|
||||||
private:
|
// If expectedType is an empty string, will do no type checking.
|
||||||
void applyPosAndSize(ThemeElement* elem, GuiComponent* comp, unsigned int properties);
|
const ThemeElement* getElement(const std::string& view, const std::string& element, const std::string& expectedType) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map< std::string, std::map<std::string, ElementPropertyType> > sElementMap;
|
static std::map< std::string, std::map<std::string, ElementPropertyType> > sElementMap;
|
||||||
|
@ -142,16 +136,24 @@ private:
|
||||||
void parseView(const pugi::xml_node& viewNode, ThemeView& view);
|
void parseView(const pugi::xml_node& viewNode, ThemeView& view);
|
||||||
void parseElement(const pugi::xml_node& elementNode, const std::map<std::string, ElementPropertyType>& typeMap, ThemeElement& element);
|
void parseElement(const pugi::xml_node& elementNode, const std::map<std::string, ElementPropertyType>& typeMap, ThemeElement& element);
|
||||||
|
|
||||||
ThemeElement* getElement(const std::string& viewName, const std::string& elementName);
|
|
||||||
|
|
||||||
std::map<std::string, ThemeView> mViews;
|
std::map<std::string, ThemeView> mViews;
|
||||||
|
|
||||||
std::map< std::string, std::shared_ptr<Sound> > mSoundCache;
|
std::map< std::string, std::shared_ptr<Sound> > mSoundCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
// okay ideas for applying themes to GuiComponents:
|
||||||
void ThemeData::applyToTextList(const std::string& view, const std::string& element, TextListComponent<T>* list, unsigned int properties)
|
// 1. ThemeData::applyToImage(component, args)
|
||||||
{
|
// NO, BECAUSE:
|
||||||
|
// - for templated types (TextListComponent) have to include the whole template in a header
|
||||||
}
|
// - inconsistent definitions if mixing templated types (some in a .cpp, some in a .h/.inl)
|
||||||
|
// 2. template<typename T> ThemeData::apply(component, args) with specialized templates
|
||||||
|
// NO, BECAUSE:
|
||||||
|
// - doesn't solve the first drawback
|
||||||
|
// - can't customize arguments for specific types
|
||||||
|
// 3. GuiComponent::applyTheme(theme, args) - WINNER
|
||||||
|
// NO, BECAUSE:
|
||||||
|
// - can't access private members of ThemeData
|
||||||
|
// - can't this be solved with enough getters?
|
||||||
|
// - theme->hasElement and theme->getProperty will require 2x as many map lookups (4 vs 2)
|
||||||
|
// - why not just return a const ThemeElement...
|
|
@ -1,146 +0,0 @@
|
||||||
#include "ThemeData.h"
|
|
||||||
|
|
||||||
#include "Renderer.h"
|
|
||||||
#include "components/ImageComponent.h"
|
|
||||||
#include "components/NinePatchComponent.h"
|
|
||||||
#include "components/TextComponent.h"
|
|
||||||
#include "Sound.h"
|
|
||||||
#include "Log.h"
|
|
||||||
|
|
||||||
using namespace ThemeFlags;
|
|
||||||
|
|
||||||
|
|
||||||
Eigen::Vector2f getScale(GuiComponent* comp)
|
|
||||||
{
|
|
||||||
if(comp && comp->getParent())
|
|
||||||
return comp->getParent()->getSize();
|
|
||||||
|
|
||||||
return Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeData::applyPosAndSize(ThemeElement* elem, GuiComponent* comp, unsigned int properties)
|
|
||||||
{
|
|
||||||
Eigen::Vector2f scale = getScale(comp);
|
|
||||||
|
|
||||||
if(properties & POSITION && elem->has("pos"))
|
|
||||||
{
|
|
||||||
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
|
||||||
comp->setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
|
||||||
comp->setSize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeData::ThemeElement* ThemeData::getElement(const std::string& viewName, const std::string& elementName)
|
|
||||||
{
|
|
||||||
auto viewIt = mViews.find(viewName);
|
|
||||||
if(viewIt == mViews.end())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
auto elemIt = viewIt->second.elements.find(elementName);
|
|
||||||
if(elemIt == viewIt->second.elements.end())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return &elemIt->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeData::applyToImage(const std::string& viewName, const std::string& elementName, ImageComponent* image, unsigned int properties)
|
|
||||||
{
|
|
||||||
LOG(LogInfo) << " req image [" << viewName << "." << elementName << "] (flags: " << properties << ")";
|
|
||||||
|
|
||||||
ThemeElement* elem = getElement(viewName, elementName);
|
|
||||||
if(!elem)
|
|
||||||
{
|
|
||||||
LOG(LogInfo) << " (missing)";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Eigen::Vector2f scale = getScale(image);
|
|
||||||
|
|
||||||
if(properties & POSITION && elem->has("pos"))
|
|
||||||
{
|
|
||||||
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
|
||||||
image->setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
|
||||||
image->setResize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale), true);
|
|
||||||
|
|
||||||
if(properties & ORIGIN && elem->has("origin"))
|
|
||||||
image->setOrigin(elem->get<Eigen::Vector2f>("origin"));
|
|
||||||
|
|
||||||
if(properties & PATH && elem->has("path"))
|
|
||||||
image->setImage(elem->get<std::string>("path"));
|
|
||||||
|
|
||||||
if(properties & TILING && elem->has("tile"))
|
|
||||||
image->setTiling(elem->get<bool>("tile"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeData::applyToNinePatch(const std::string& viewName, const std::string& elementName, NinePatchComponent* patch, unsigned int properties)
|
|
||||||
{
|
|
||||||
ThemeElement* elem = getElement(viewName, elementName);
|
|
||||||
if(!elem)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Eigen::Vector2f scale = getScale(patch);
|
|
||||||
|
|
||||||
if(properties & POSITION && elem->has("pos"))
|
|
||||||
{
|
|
||||||
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
|
||||||
patch->setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
applyPosAndSize(elem, patch, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeData::applyToText(const std::string& viewName, const std::string& elementName, TextComponent* text, unsigned int properties)
|
|
||||||
{
|
|
||||||
ThemeElement* elem = getElement(viewName, elementName);
|
|
||||||
if(!elem)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Eigen::Vector2f scale = getScale(text);
|
|
||||||
|
|
||||||
if(properties & POSITION && elem->has("pos"))
|
|
||||||
{
|
|
||||||
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
|
||||||
text->setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
|
||||||
text->setSize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale));
|
|
||||||
|
|
||||||
if(properties & COLOR && elem->has("color"))
|
|
||||||
text->setColor(elem->get<unsigned int>("color"));
|
|
||||||
|
|
||||||
if(properties & CENTER && elem->has("center"))
|
|
||||||
text->setCentered(elem->get<bool>("center"));
|
|
||||||
|
|
||||||
if(properties & TEXT && elem->has("text"))
|
|
||||||
text->setText(elem->get<std::string>("text"));
|
|
||||||
|
|
||||||
// TODO - fonts
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeData::playSound(const std::string& elementName)
|
|
||||||
{
|
|
||||||
ThemeElement* elem = getElement("common", elementName);
|
|
||||||
if(!elem)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(elem->has("path"))
|
|
||||||
{
|
|
||||||
const std::string path = elem->get<std::string>("path");
|
|
||||||
auto cacheIt = mSoundCache.find(path);
|
|
||||||
if(cacheIt != mSoundCache.end())
|
|
||||||
{
|
|
||||||
cacheIt->second->play();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Sound> sound = std::shared_ptr<Sound>(new Sound(path));
|
|
||||||
sound->play();
|
|
||||||
mSoundCache[path] = sound;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,20 +14,20 @@ GuiFastSelect::GuiFastSelect(Window* window, IGameListView* gamelist) : GuiCompo
|
||||||
const std::shared_ptr<ThemeData>& theme = mGameList->getTheme();
|
const std::shared_ptr<ThemeData>& theme = mGameList->getTheme();
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
theme->applyToNinePatch("fastSelect", "background", &mBackground, PATH);
|
mBackground.applyTheme(theme, "fastSelect", "background", PATH);
|
||||||
mBackground.fitTo(mSize);
|
mBackground.fitTo(mSize);
|
||||||
addChild(&mBackground);
|
addChild(&mBackground);
|
||||||
|
|
||||||
mLetterText.setSize(mSize.x(), mSize.y() * 0.75f);
|
mLetterText.setSize(mSize.x(), mSize.y() * 0.75f);
|
||||||
mLetterText.setCentered(true);
|
mLetterText.setCentered(true);
|
||||||
theme->applyToText("fastSelect", "letter", &mLetterText, FONT_PATH | COLOR);
|
mLetterText.applyTheme(theme, "fastSelect", "letter", FONT_PATH | COLOR);
|
||||||
// TODO - set font size
|
// TODO - set font size
|
||||||
addChild(&mLetterText);
|
addChild(&mLetterText);
|
||||||
|
|
||||||
mSortText.setPosition(0, mSize.y() * 0.75f);
|
mSortText.setPosition(0, mSize.y() * 0.75f);
|
||||||
mSortText.setSize(mSize.x(), mSize.y() * 0.25f);
|
mSortText.setSize(mSize.x(), mSize.y() * 0.25f);
|
||||||
mSortText.setCentered(true);
|
mSortText.setCentered(true);
|
||||||
theme->applyToText("fastSelect", "subtext", &mSortText, FONT_PATH | COLOR);
|
mSortText.applyTheme(theme, "fastSelect", "subtext", FONT_PATH | COLOR);
|
||||||
// TODO - set font size
|
// TODO - set font size
|
||||||
addChild(&mSortText);
|
addChild(&mSortText);
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mBackground(window, ":/
|
||||||
|
|
||||||
mTheme = std::make_shared<ThemeData>();
|
mTheme = std::make_shared<ThemeData>();
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
mTheme->applyToTextList< std::function<void()> >("common", "menu", &mList, FONT_PATH | COLOR);
|
mList.applyTheme(mTheme, "common", "menu", 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);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "../Log.h"
|
#include "../Log.h"
|
||||||
#include "../Renderer.h"
|
#include "../Renderer.h"
|
||||||
|
#include "../ThemeData.h"
|
||||||
|
|
||||||
Eigen::Vector2i ImageComponent::getTextureSize() const
|
Eigen::Vector2i ImageComponent::getTextureSize() const
|
||||||
{
|
{
|
||||||
|
@ -243,3 +244,37 @@ void ImageComponent::copyScreen()
|
||||||
|
|
||||||
resize();
|
resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||||
|
{
|
||||||
|
LOG(LogInfo) << " req image [" << view << "." << element << "] (flags: " << properties << ")";
|
||||||
|
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "image");
|
||||||
|
if(!elem)
|
||||||
|
{
|
||||||
|
LOG(LogInfo) << " (missing)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eigen::Vector2f scale = getParent() ? getParent()->getSize() : Eigen::Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||||
|
|
||||||
|
if(properties & POSITION && elem->has("pos"))
|
||||||
|
{
|
||||||
|
Eigen::Vector2f denormalized = elem->get<Eigen::Vector2f>("pos").cwiseProduct(scale);
|
||||||
|
setPosition(Eigen::Vector3f(denormalized.x(), denormalized.y(), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(properties & ThemeFlags::SIZE && elem->has("size"))
|
||||||
|
setResize(elem->get<Eigen::Vector2f>("size").cwiseProduct(scale), true);
|
||||||
|
|
||||||
|
if(properties & ORIGIN && elem->has("origin"))
|
||||||
|
setOrigin(elem->get<Eigen::Vector2f>("origin"));
|
||||||
|
|
||||||
|
if(properties & PATH && elem->has("path"))
|
||||||
|
setImage(elem->get<std::string>("path"));
|
||||||
|
|
||||||
|
if(properties & TILING && elem->has("tile"))
|
||||||
|
setTiling(elem->get<bool>("tile"));
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
|
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
|
||||||
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Eigen::Vector2f mTargetSize;
|
Eigen::Vector2f mTargetSize;
|
||||||
Eigen::Vector2f mOrigin;
|
Eigen::Vector2f mOrigin;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "../Window.h"
|
#include "../Window.h"
|
||||||
#include "../Log.h"
|
#include "../Log.h"
|
||||||
#include "../Renderer.h"
|
#include "../Renderer.h"
|
||||||
|
#include "../ThemeData.h"
|
||||||
|
|
||||||
NinePatchComponent::NinePatchComponent(Window* window, const std::string& path, unsigned int edgeColor, unsigned int centerColor) : GuiComponent(window),
|
NinePatchComponent::NinePatchComponent(Window* window, const std::string& path, unsigned int edgeColor, unsigned int centerColor) : GuiComponent(window),
|
||||||
mEdgeColor(edgeColor), mCenterColor(centerColor),
|
mEdgeColor(edgeColor), mCenterColor(centerColor),
|
||||||
|
@ -193,3 +194,17 @@ void NinePatchComponent::setCenterColor(unsigned int centerColor)
|
||||||
mCenterColor = centerColor;
|
mCenterColor = centerColor;
|
||||||
updateColors();
|
updateColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NinePatchComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||||
|
{
|
||||||
|
GuiComponent::applyTheme(theme, view, element, properties);
|
||||||
|
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "ninepatch");
|
||||||
|
if(!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(properties & PATH && elem->has("path"))
|
||||||
|
setImagePath(elem->get<std::string>("path"));
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ public:
|
||||||
void setEdgeColor(unsigned int edgeColor);
|
void setEdgeColor(unsigned int edgeColor);
|
||||||
void setCenterColor(unsigned int centerColor);
|
void setCenterColor(unsigned int centerColor);
|
||||||
|
|
||||||
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Eigen::Vector2f getCornerSize() const;
|
Eigen::Vector2f getCornerSize() const;
|
||||||
|
|
||||||
|
|
|
@ -138,3 +138,25 @@ std::string TextComponent::getValue() const
|
||||||
{
|
{
|
||||||
return mText;
|
return mText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||||
|
{
|
||||||
|
GuiComponent::applyTheme(theme, view, element, properties);
|
||||||
|
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "text");
|
||||||
|
if(!elem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(properties & COLOR && elem->has("color"))
|
||||||
|
setColor(elem->get<unsigned int>("color"));
|
||||||
|
|
||||||
|
if(properties & CENTER && elem->has("center"))
|
||||||
|
setCentered(elem->get<bool>("center"));
|
||||||
|
|
||||||
|
if(properties & TEXT && elem->has("text"))
|
||||||
|
setText(elem->get<std::string>("text"));
|
||||||
|
|
||||||
|
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
|
|
||||||
std::shared_ptr<Font> getFont() const;
|
std::shared_ptr<Font> getFont() const;
|
||||||
|
|
||||||
|
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calculateExtent();
|
void calculateExtent();
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
bool input(InputConfig* config, Input input) override;
|
bool input(InputConfig* config, Input input) override;
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
void render(const Eigen::Affine3f& parentTrans) override;
|
void render(const Eigen::Affine3f& parentTrans) override;
|
||||||
|
void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||||
|
|
||||||
struct ListRow
|
struct ListRow
|
||||||
{
|
{
|
||||||
|
@ -405,4 +406,27 @@ void TextListComponent<T>::onCursorChanged(CursorState state)
|
||||||
mCursorChangedCallback(state);
|
mCursorChangedCallback(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties)
|
||||||
|
{
|
||||||
|
GuiComponent::applyTheme(theme, view, element, properties);
|
||||||
|
|
||||||
|
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "textlist");
|
||||||
|
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
if(properties & COLOR)
|
||||||
|
{
|
||||||
|
if(elem->has("selectorColor"))
|
||||||
|
setSelectorColor(elem->get<unsigned int>("selectorColor"));
|
||||||
|
if(elem->has("selectedColor"))
|
||||||
|
setSelectedColor(elem->get<unsigned int>("selectedColor"));
|
||||||
|
if(elem->has("primaryColor"))
|
||||||
|
setColor(0, elem->get<unsigned int>("primaryColor"));
|
||||||
|
if(elem->has("secondaryColor"))
|
||||||
|
setColor(1, elem->get<unsigned int>("secondaryColor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
setFont(Font::getFromTheme(elem, properties, mFont));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -553,3 +553,22 @@ void TextCache::setColor(unsigned int color)
|
||||||
{
|
{
|
||||||
Renderer::buildGLColorArray(const_cast<GLubyte*>(colors), color, vertCount);
|
Renderer::buildGLColorArray(const_cast<GLubyte*>(colors), color, vertCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Font> Font::getFromTheme(const ThemeData::ThemeElement* elem, unsigned int properties, const std::shared_ptr<Font>& orig)
|
||||||
|
{
|
||||||
|
using namespace ThemeFlags;
|
||||||
|
if(!(properties & FONT_PATH) && !(properties & FONT_SIZE))
|
||||||
|
return orig;
|
||||||
|
|
||||||
|
std::shared_ptr<Font> font;
|
||||||
|
int size = (orig ? orig->mSize : FONT_SIZE_MEDIUM);
|
||||||
|
std::string path = (orig ? orig->mPath : getDefaultPath());
|
||||||
|
|
||||||
|
float sh = (float)Renderer::getScreenHeight();
|
||||||
|
if(properties & FONT_SIZE && elem->has("fontSize"))
|
||||||
|
size = (int)(sh * elem->get<float>("fontSize"));
|
||||||
|
if(properties & FONT_PATH && elem->has("fontPath"))
|
||||||
|
path = elem->get<std::string>("fontPath");
|
||||||
|
|
||||||
|
return get(size, path);
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Dense>
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
#include "../ThemeData.h"
|
||||||
|
|
||||||
class TextCache;
|
class TextCache;
|
||||||
|
|
||||||
|
@ -69,6 +70,9 @@ public:
|
||||||
int getSize() const;
|
int getSize() const;
|
||||||
|
|
||||||
static std::string getDefaultPath();
|
static std::string getDefaultPath();
|
||||||
|
|
||||||
|
static std::shared_ptr<Font> getFromTheme(const ThemeData::ThemeElement* elem, unsigned int properties, const std::shared_ptr<Font>& orig);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int getDpiX();
|
static int getDpiX();
|
||||||
static int getDpiY();
|
static int getDpiY();
|
||||||
|
|
|
@ -38,7 +38,7 @@ void SystemView::updateData()
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
|
|
||||||
mHeaderImage.setImage("");
|
mHeaderImage.setImage("");
|
||||||
mSystem->getTheme()->applyToImage("common", "header", &mHeaderImage, PATH);
|
mHeaderImage.applyTheme(mSystem->getTheme(), "system", "header", PATH);
|
||||||
|
|
||||||
// header
|
// header
|
||||||
if(mHeaderImage.hasImage())
|
if(mHeaderImage.hasImage())
|
||||||
|
@ -51,7 +51,7 @@ void SystemView::updateData()
|
||||||
mHeaderText.setText(mSystem->getFullName());
|
mHeaderText.setText(mSystem->getFullName());
|
||||||
}
|
}
|
||||||
|
|
||||||
mSystem->getTheme()->applyToImage("common", "system", &mImage, PATH);
|
mImage.applyTheme(mSystem->getTheme(), "system", "system", PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemView::input(InputConfig* config, Input input)
|
bool SystemView::input(InputConfig* config, Input input)
|
||||||
|
|
|
@ -19,7 +19,7 @@ void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
{
|
{
|
||||||
ISimpleGameListView::onThemeChanged(theme);
|
ISimpleGameListView::onThemeChanged(theme);
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
theme->applyToTextList(getName(), "gamelist", &mList, POSITION | ThemeFlags::SIZE | COLOR | SOUND);
|
mList.applyTheme(theme, getName(), "gamelist", POSITION | ThemeFlags::SIZE | COLOR | SOUND | FONT_PATH | FONT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
|
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
|
||||||
|
|
|
@ -26,6 +26,7 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
|
||||||
mDescContainer.setAutoScroll((int)(1600 + mDescContainer.getSize().x()), 0.025f);
|
mDescContainer.setAutoScroll((int)(1600 + mDescContainer.getSize().x()), 0.025f);
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
|
||||||
|
mDescription.setFont(Font::get(FONT_SIZE_SMALL));
|
||||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||||
mDescContainer.addChild(&mDescription);
|
mDescContainer.addChild(&mDescription);
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ 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;
|
||||||
theme->applyToText("detailed", "description", &mDescription, POSITION | FONT_PATH | FONT_SIZE);
|
mDescription.applyTheme(theme, getName(), "description", POSITION | FONT_PATH | FONT_SIZE | COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DetailedGameListView::updateInfoPanel()
|
void DetailedGameListView::updateInfoPanel()
|
||||||
|
|
|
@ -24,8 +24,8 @@ ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGame
|
||||||
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||||
{
|
{
|
||||||
using namespace ThemeFlags;
|
using namespace ThemeFlags;
|
||||||
theme->applyToImage(getName(), "background", &mBackground, PATH | TILING);
|
mBackground.applyTheme(theme, getName(), "background", PATH | TILING);
|
||||||
theme->applyToImage(getName(), "header", &mHeaderImage, PATH);
|
mHeaderImage.applyTheme(theme, getName(), "header", PATH);
|
||||||
|
|
||||||
if(mHeaderImage.hasImage())
|
if(mHeaderImage.hasImage())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue