ADD: Configurable UITheme, closes #14
All checks were successful
Tests / test (push) Successful in 2m36s

This commit is contained in:
Sebastian Böckelmann 2026-04-20 12:39:31 +02:00
parent f6cada3cf8
commit 0894c5615e
12 changed files with 88 additions and 23 deletions

View File

@ -291,6 +291,7 @@ if(BUILD_GAME)
src/engine/core/gui/uiComponent/layout/LayoutEngine.h src/engine/core/gui/uiComponent/layout/LayoutEngine.h
src/engine/renderer/config/MinimapConfig.h src/engine/renderer/config/MinimapConfig.h
src/engine/core/Types.h src/engine/core/Types.h
src/engine/core/gui/text/UiTheme.h
) )
target_compile_options(Dicewars_Siedler PRIVATE target_compile_options(Dicewars_Siedler PRIVATE
-Wall -Wall

10
assets/ui/uiTheme.json Normal file
View File

@ -0,0 +1,10 @@
{
"font": {
"path": "/usr/share/fonts/TTF/DejaVuSans.ttf",
"sizes": {
"small": 18,
"medium": 28,
"large": 48
}
}
}

View File

@ -0,0 +1,16 @@
//
// Created by sebastian on 20.04.26.
//
#ifndef UITHEME_H
#define UITHEME_H
#include <memory>
#include "Font.h"
struct UiTheme {
std::unique_ptr<Font> small;
std::unique_ptr<Font> medium;
std::unique_ptr<Font> large;
};
#endif //UITHEME_H

View File

@ -84,6 +84,45 @@ std::shared_ptr<ModelTexture> AssetManager::getTexture(const std::string &name)
return textures.at(name); return textures.at(name);
} }
std::shared_ptr<UiTheme> AssetManager::getUiTheme(const std::string &themeName) {
assert(uiThemes.contains(themeName) && "Theme not found!");
return uiThemes.at(themeName);
}
std::shared_ptr<UiTheme> AssetManager::loadUiTheme(const std::string &themeName, const std::string &themePath) {
if (!uiThemes.contains(themeName)) {
json themeConfiguration = readJsonFile(themePath);
if (themeConfiguration.contains("font")) {
auto fontData = themeConfiguration["font"];
if (fontData.contains("path") && fontData.contains("sizes")) {
auto fontSizes = fontData["sizes"];
if (fontSizes.contains("small") && fontSizes.contains("medium") && fontSizes.contains("large")) {
std::string fontPath = fontData["path"].get<std::string>();
auto theme = std::make_shared<UiTheme>(
std::make_unique<Font>(fontPath, fontSizes["small"]),
std::make_unique<Font>(fontPath, fontSizes["medium"]),
std::make_unique<Font>(fontPath, fontSizes["large"])
);
uiThemes[themeName] = theme;
return theme;
} else {
std::cerr << "Required Font sizes not found in theme configuration!" << std::endl;
return nullptr;
}
} else {
std::cerr << "Required Font path not found in theme configuration!" << std::endl;
return nullptr;
}
} else {
std::cerr << "Required Font configuration not found in theme configuration!" << std::endl;
return nullptr;
}
} else {
return uiThemes[themeName];
}
}
json AssetManager::readJsonFile(const std::string &path) { json AssetManager::readJsonFile(const std::string &path) {
if (fs::exists(path)) { if (fs::exists(path)) {

View File

@ -10,9 +10,12 @@
#include "json.hpp" #include "json.hpp"
#include "../model/TexturedModel.h" #include "../model/TexturedModel.h"
#include "Loader.h" #include "Loader.h"
#include "../../core/gui/text/UiTheme.h"
#include "../model/ModelStages.h" #include "../model/ModelStages.h"
class Font;
class AssetManager { class AssetManager {
public: public:
static std::shared_ptr<TexturedModel> loadModel(const std::string& name, const std::string& objPath, const std::string& texturePath, Loader& loader); static std::shared_ptr<TexturedModel> loadModel(const std::string& name, const std::string& objPath, const std::string& texturePath, Loader& loader);
@ -23,10 +26,13 @@ public:
static std::shared_ptr<ModelStageConfiguration> getModelStageConfiguration(const std::string& modelName, const std::string& stageName); static std::shared_ptr<ModelStageConfiguration> getModelStageConfiguration(const std::string& modelName, const std::string& stageName);
static std::shared_ptr<ModelTexture> loadTexture(const std::string &name, const std::string &texturePath, Loader &loader); static std::shared_ptr<ModelTexture> loadTexture(const std::string &name, const std::string &texturePath, Loader &loader);
static std::shared_ptr<ModelTexture> getTexture(const std::string& texturePath); static std::shared_ptr<ModelTexture> getTexture(const std::string& texturePath);
static std::shared_ptr<UiTheme> getUiTheme(const std::string& themeName);
static std::shared_ptr<UiTheme> loadUiTheme(const std::string& themeName, const std::string& themePath);
private: private:
static inline std::unordered_map<std::string, std::shared_ptr<TexturedModel>> models; static inline std::unordered_map<std::string, std::shared_ptr<TexturedModel>> models;
static inline std::unordered_map<std::string, std::shared_ptr<ModelStages>> modelsWithStages; static inline std::unordered_map<std::string, std::shared_ptr<ModelStages>> modelsWithStages;
static inline std::unordered_map<std::string, std::shared_ptr<ModelTexture>> textures; static inline std::unordered_map<std::string, std::shared_ptr<ModelTexture>> textures;
static inline std::unordered_map<std::string, std::shared_ptr<UiTheme>> uiThemes;
static nlohmann::json readJsonFile(const std::string &path); static nlohmann::json readJsonFile(const std::string &path);
}; };

View File

@ -9,6 +9,7 @@
#include "../engine/core/Application.h" #include "../engine/core/Application.h"
#include "../engine/core/gui/text/Font.h" #include "../engine/core/gui/text/Font.h"
#include "../engine/core/gui/text/UiTheme.h"
#include "../engine/core/gui/uiComponent/UiButton.h" #include "../engine/core/gui/uiComponent/UiButton.h"
#include "../engine/core/gui/uiComponent/UiImage.h" #include "../engine/core/gui/uiComponent/UiImage.h"
#include "../engine/core/gui/uiComponent/UiText.h" #include "../engine/core/gui/uiComponent/UiText.h"
@ -49,15 +50,10 @@ void UILayer::onAttach() {
rootContainer->getLayoutStyle().flexDirection = FlexDirection::Column; rootContainer->getLayoutStyle().flexDirection = FlexDirection::Column;
rootContainer->getLayoutStyle().justifyContent = JustifyContent::SpaceBetween; rootContainer->getLayoutStyle().justifyContent = JustifyContent::SpaceBetween;
Font myFont("/usr/share/fonts/TTF/DejaVuSans.ttf", 48); AssetManager::loadUiTheme("default", "assets/ui/uiTheme.json");
font = std::make_unique<Font>(myFont);
//rootContainer->addChild(std::move(button)); auto inventoryContainer = std::make_unique<UiInventoryContainer>();
smallFont =std::make_unique<Font>("/usr/share/fonts/TTF/DejaVuSans.ttf", 18);
mediumFont = std::make_unique<Font>("/usr/share/fonts/TTF/DejaVuSans.ttf", 28);
auto inventoryContainer = std::make_unique<UiInventoryContainer>(*smallFont);
inventoryContainer->addRessource("wood_icon", "background", 0, RessourceType::WOOD); inventoryContainer->addRessource("wood_icon", "background", 0, RessourceType::WOOD);
inventoryContainer->addRessource("stone_icon","background", 0, RessourceType::STONE); inventoryContainer->addRessource("stone_icon","background", 0, RessourceType::STONE);
@ -81,7 +77,7 @@ void UILayer::onAttach() {
turnStyle.margin.left = {20.f, SizeUnit::Pixels}; // Abstand zum Inventory turnStyle.margin.left = {20.f, SizeUnit::Pixels}; // Abstand zum Inventory
turnStyle.margin.top = {10.f, SizeUnit::Pixels}; turnStyle.margin.top = {10.f, SizeUnit::Pixels};
auto turnLabel = std::make_unique<UiText>(*mediumFont, "Runde: 1", turnStyle, glm::vec3(1,1,1)); auto turnLabel = std::make_unique<UiText>(*AssetManager::getUiTheme("default")->medium, "Runde: 1", turnStyle, glm::vec3(1,1,1));
turnText = rootContainer->addChild<UiText>(std::move(turnLabel)); // NOLINT turnText = rootContainer->addChild<UiText>(std::move(turnLabel)); // NOLINT
EventBus::getInstance().subscribe<TurnChangedEvent>([this](const TurnChangedEvent& event) { EventBus::getInstance().subscribe<TurnChangedEvent>([this](const TurnChangedEvent& event) {
@ -104,7 +100,7 @@ void UILayer::onAttach() {
style.margin.top = {10.f, SizeUnit::Pixels}; style.margin.top = {10.f, SizeUnit::Pixels};
style.margin.left = {20.f, SizeUnit::Pixels}; style.margin.left = {20.f, SizeUnit::Pixels};
auto buildingMenuContainer = std::make_unique<UiBuildingMenuContainer>(*smallFont); auto buildingMenuContainer = std::make_unique<UiBuildingMenuContainer>(*AssetManager::getUiTheme("default")->small);
buildingMenuContainer->addBuildingMenuBtnCallback([](UiBuildingMenuButtonClickEvent e) { buildingMenuContainer->addBuildingMenuBtnCallback([](UiBuildingMenuButtonClickEvent e) {
if (e.originalEventData.isClick(MouseButton::LEFT)) { if (e.originalEventData.isClick(MouseButton::LEFT)) {
EventBus::getInstance().emit(BuildingTypeSelectEvent{e.buildingType}); EventBus::getInstance().emit(BuildingTypeSelectEvent{e.buildingType});

View File

@ -13,7 +13,7 @@
// UiInventoryContainer.h // UiInventoryContainer.h
class UiInventoryContainer : public UiComponent { class UiInventoryContainer : public UiComponent {
public: public:
UiInventoryContainer(Font& font) : font(font) { UiInventoryContainer() {
LayoutStyle containerStyle; LayoutStyle containerStyle;
containerStyle.width = SizeValue(0.3f, SizeUnit::Percent); containerStyle.width = SizeValue(0.3f, SizeUnit::Percent);
containerStyle.height = SizeValue(80.f, SizeUnit::Pixels); containerStyle.height = SizeValue(80.f, SizeUnit::Pixels);
@ -26,7 +26,7 @@ public:
void addRessource(const std::string& iconName, const std::string& textureName, int amount, RessourceType widgetID) { void addRessource(const std::string& iconName, const std::string& textureName, int amount, RessourceType widgetID) {
float marginLeft = (widgets.empty()) ? 0.0f : 10.0f; float marginLeft = (widgets.empty()) ? 0.0f : 10.0f;
auto widget = RessourceWidgetFactory::create(iconName, textureName, amount, font, marginLeft); auto widget = RessourceWidgetFactory::create(iconName, textureName, amount, marginLeft);
widgets.emplace(widgetID, widget.get()); widgets.emplace(widgetID, widget.get());
addChild<UiRessourceWidget>(std::move(widget)); addChild<UiRessourceWidget>(std::move(widget));
} }
@ -41,7 +41,6 @@ protected:
void onCollectRenderData(UiRenderBundle &uiRenderBundle) override; void onCollectRenderData(UiRenderBundle &uiRenderBundle) override;
private: private:
Font& font;
std::unordered_map<RessourceType, UiRessourceWidget*> widgets; std::unordered_map<RessourceType, UiRessourceWidget*> widgets;
}; };

View File

@ -4,13 +4,15 @@
#include "UiRessourceWidget.h" #include "UiRessourceWidget.h"
#include "../../../engine/core/gui/text/UiTheme.h"
#include "../../../engine/core/gui/uiComponent/UiText.h" #include "../../../engine/core/gui/uiComponent/UiText.h"
#include "../../../engine/renderer/loader/AssetManager.h"
UiRessourceWidget::UiRessourceWidget(GLuint iconTextureID, GLuint backgroundID, int amount, Font &font, const LayoutStyle &containerStyle, UiRessourceWidget::UiRessourceWidget(GLuint iconTextureID, GLuint backgroundID, int amount, const LayoutStyle &containerStyle,
LayoutStyle &iconStyle, LayoutStyle &textStyle) : UiComponent(containerStyle) { LayoutStyle &iconStyle, LayoutStyle &textStyle) : UiComponent(containerStyle) {
icon = addChild<UiImage>(std::make_unique<UiImage>(iconTextureID, backgroundID, iconStyle)); //NOLINT icon = addChild<UiImage>(std::make_unique<UiImage>(iconTextureID, backgroundID, iconStyle)); //NOLINT
text = addChild<UiText>(std::make_unique<UiText>(font, std::to_string(amount), textStyle)); //NOLINT text = addChild<UiText>(std::make_unique<UiText>(*AssetManager::getUiTheme("default")->small, std::to_string(amount), textStyle)); //NOLINT
} }
void UiRessourceWidget::setAmount(int newAmount) { void UiRessourceWidget::setAmount(int newAmount) {

View File

@ -13,7 +13,7 @@
class UiRessourceWidget : public UiComponent { class UiRessourceWidget : public UiComponent {
public: public:
UiRessourceWidget(GLuint iconTextureID, GLuint backgroundID, int amount, Font &font, UiRessourceWidget(GLuint iconTextureID, GLuint backgroundID, int amount,
const LayoutStyle &containerStyle, const LayoutStyle &containerStyle,
LayoutStyle &iconStyle, LayoutStyle &textStyle); LayoutStyle &iconStyle, LayoutStyle &textStyle);

View File

@ -39,8 +39,6 @@ public:
if (buildingType == BuildingType::FOREST_HUT) { if (buildingType == BuildingType::FOREST_HUT) {
BuildingDefinition def = BuildingConfig::get(BuildingType::FOREST_HUT); BuildingDefinition def = BuildingConfig::get(BuildingType::FOREST_HUT);
} }
for (const auto& [resourceTye, costs] : BuildingConfig::get(buildingType).resourceCosts) { for (const auto& [resourceTye, costs] : BuildingConfig::get(buildingType).resourceCosts) {
@ -52,8 +50,6 @@ public:
addChild<UiBuildingMenuCostContainer>(std::move(costContainer)); addChild<UiBuildingMenuCostContainer>(std::move(costContainer));
} }
visualStyles[UiEventType::NONE] = {1.0f, glm::vec3(0.0f), 0.0f}; visualStyles[UiEventType::NONE] = {1.0f, glm::vec3(0.0f), 0.0f};
visualStyles[UiEventType::MOUSE_OVER] = {1.15f, glm::vec3(0.0f), 0.0f}; visualStyles[UiEventType::MOUSE_OVER] = {1.15f, glm::vec3(0.0f), 0.0f};
visualStyles[UiEventType::MOUSE_CLICK] = {1.0f, glm::vec3(0.3f, 0.6f, 1.0f), 0.15f}; visualStyles[UiEventType::MOUSE_CLICK] = {1.0f, glm::vec3(0.3f, 0.6f, 1.0f), 0.15f};

View File

@ -7,7 +7,7 @@
#include "../../../../engine/renderer/loader/AssetManager.h" #include "../../../../engine/renderer/loader/AssetManager.h"
#include "../../../../engine/renderer/loader/Loader.h" #include "../../../../engine/renderer/loader/Loader.h"
std::unique_ptr<UiRessourceWidget> RessourceWidgetFactory::create(const std::string &iconName, const std::string& textureName, int amount, Font &font, float marginLeft) { std::unique_ptr<UiRessourceWidget> RessourceWidgetFactory::create(const std::string &iconName, const std::string& textureName, int amount, float marginLeft) {
LayoutStyle iconStyle; LayoutStyle iconStyle;
iconStyle.width = SizeValue(40.f, SizeUnit::Pixels); iconStyle.width = SizeValue(40.f, SizeUnit::Pixels);
iconStyle.height = SizeValue(40.f,SizeUnit::Pixels); iconStyle.height = SizeValue(40.f,SizeUnit::Pixels);
@ -30,7 +30,7 @@ std::unique_ptr<UiRessourceWidget> RessourceWidgetFactory::create(const std::str
GLuint textureID =AssetManager::getTexture(iconName)->getTextureID();; GLuint textureID =AssetManager::getTexture(iconName)->getTextureID();;
GLuint backgroundTextureID = AssetManager::getTexture(textureName)->getTextureID(); GLuint backgroundTextureID = AssetManager::getTexture(textureName)->getTextureID();
return std::make_unique<UiRessourceWidget>(textureID, backgroundTextureID, return std::make_unique<UiRessourceWidget>(textureID, backgroundTextureID,
amount, font, containerStyle, iconStyle, textStyle amount, containerStyle, iconStyle, textStyle
); );
} }

View File

@ -12,7 +12,7 @@ class Font;
class RessourceWidgetFactory { class RessourceWidgetFactory {
public: public:
static std::unique_ptr<UiRessourceWidget> create(const std::string &iconName, const std::string &textureName, int amount, Font &font, float marginLeft = 0.0); static std::unique_ptr<UiRessourceWidget> create(const std::string &iconName, const std::string &textureName, int amount, float marginLeft = 0.0);
}; };