diff --git a/CMakeLists.txt b/CMakeLists.txt index dafd0fd26..7e740736c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 8889fc5af..8cea223d5 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -232,6 +232,8 @@ void GuiComponent::applyTheme(const std::shared_ptr& 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")) diff --git a/src/ThemeData.cpp b/src/ThemeData.cpp index 5a7a084e9..9d26d0aed 100644 --- a/src/ThemeData.cpp +++ b/src/ThemeData.cpp @@ -7,6 +7,9 @@ #include "pugiXML/pugixml.hpp" #include +#include "components/ImageComponent.h" +#include "components/TextComponent.h" + std::map< std::string, std::map > 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 > 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 ThemeData::makeExtras(const std::shared_ptr& theme, const std::string& view, Window* window) +{ + std::vector 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& 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; +} diff --git a/src/ThemeData.h b/src/ThemeData.h index cf1e187ec..9f8a24a0f 100644 --- a/src/ThemeData.h +++ b/src/ThemeData.h @@ -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& extras); + + virtual ~ThemeExtras(); + +private: + std::vector mExtras; +}; + class ThemeData { public: @@ -88,17 +104,8 @@ public: private: class ThemeView { - private: - bool mExtrasDirty; - std::vector mExtras; - public: - ThemeView() : mExtrasDirty(true) {} - virtual ~ThemeView(); - std::map elements; - - const std::vector& 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 makeExtras(const std::shared_ptr& theme, const std::string& view, Window* window); + private: static std::map< std::string, std::map > sElementMap; @@ -141,7 +150,6 @@ private: std::map< std::string, std::shared_ptr > mSoundCache; }; - // okay ideas for applying themes to GuiComponents: // 1. ThemeData::applyToImage(component, args) // NO, BECAUSE: diff --git a/src/ThemeDumper.cpp b/src/ThemeDumper.cpp new file mode 100644 index 000000000..e7ec37ad4 --- /dev/null +++ b/src/ThemeDumper.cpp @@ -0,0 +1,2 @@ +#include "ThemeDumper.h" + diff --git a/src/ThemeDumper.h b/src/ThemeDumper.h new file mode 100644 index 000000000..efd7a374b --- /dev/null +++ b/src/ThemeDumper.h @@ -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 +{ + +}; diff --git a/src/components/GuiMenu.cpp b/src/components/GuiMenu.cpp index 396a39b5f..e766c4810 100644 --- a/src/components/GuiMenu.cpp +++ b/src/components/GuiMenu.cpp @@ -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(); - 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); } diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index f28cde28d..972016ff9 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -269,7 +269,8 @@ void ImageComponent::applyTheme(const std::shared_ptr& theme, const s if(properties & ThemeFlags::SIZE && elem->has("size")) setResize(elem->get("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("origin")); if(properties & PATH && elem->has("path")) diff --git a/src/components/TextListComponent.h b/src/components/TextListComponent.h index 00c62ca8f..d074d852b 100644 --- a/src/components/TextListComponent.h +++ b/src/components/TextListComponent.h @@ -412,6 +412,8 @@ void TextListComponent::applyTheme(const std::shared_ptr& 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) diff --git a/src/views/gamelist/DetailedGameListView.cpp b/src/views/gamelist/DetailedGameListView.cpp index adcc47ece..f905fcc00 100644 --- a/src/views/gamelist/DetailedGameListView.cpp +++ b/src/views/gamelist/DetailedGameListView.cpp @@ -42,6 +42,8 @@ void DetailedGameListView::onThemeChanged(const std::shared_ptr& 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); } diff --git a/src/views/gamelist/ISimpleGameListView.cpp b/src/views/gamelist/ISimpleGameListView.cpp index 5b92351f7..448d415f0 100644 --- a/src/views/gamelist/ISimpleGameListView.cpp +++ b/src/views/gamelist/ISimpleGameListView.cpp @@ -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& 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); diff --git a/src/views/gamelist/ISimpleGameListView.h b/src/views/gamelist/ISimpleGameListView.h index 41f269bd2..b4dcf2c8a 100644 --- a/src/views/gamelist/ISimpleGameListView.h +++ b/src/views/gamelist/ISimpleGameListView.h @@ -32,5 +32,7 @@ protected: ImageComponent mHeaderImage; ImageComponent mBackground; + ThemeExtras mThemeExtras; + std::stack mCursorStack; };