diff options
author | hop311 <hop3114@gmail.com> | 2023-11-07 23:18:08 +0100 |
---|---|---|
committer | hop311 <hop3114@gmail.com> | 2023-11-12 17:55:39 +0100 |
commit | fd686eadf81e85bd4993a483adcefd6a153d259f (patch) | |
tree | e59e8a1531d96a37872373f6262eff8ed45da1ff /src/openvic-simulation/interface | |
parent | c8983f5cda0b396b76c9d1491cf4c8ff5997d420 (diff) |
GUI and GFX file loading
Diffstat (limited to 'src/openvic-simulation/interface')
-rw-r--r-- | src/openvic-simulation/interface/GFX.cpp | 98 | ||||
-rw-r--r-- | src/openvic-simulation/interface/GFX.hpp | 138 | ||||
-rw-r--r-- | src/openvic-simulation/interface/GUI.cpp | 182 | ||||
-rw-r--r-- | src/openvic-simulation/interface/GUI.hpp | 235 | ||||
-rw-r--r-- | src/openvic-simulation/interface/LoadBase.hpp | 82 | ||||
-rw-r--r-- | src/openvic-simulation/interface/UI.cpp | 92 | ||||
-rw-r--r-- | src/openvic-simulation/interface/UI.hpp | 27 |
7 files changed, 854 insertions, 0 deletions
diff --git a/src/openvic-simulation/interface/GFX.cpp b/src/openvic-simulation/interface/GFX.cpp new file mode 100644 index 0000000..24f4b21 --- /dev/null +++ b/src/openvic-simulation/interface/GFX.cpp @@ -0,0 +1,98 @@ +#include "GFX.hpp" + +using namespace OpenVic; +using namespace OpenVic::GFX; +using namespace OpenVic::NodeTools; + +Font::Font(std::string_view new_identifier, colour_t new_colour, std::string_view new_fontname) + : HasIdentifierAndColour { new_identifier, new_colour, false, true }, fontname { new_fontname } {} + +node_callback_t Sprite::expect_sprite(callback_t<std::unique_ptr<Sprite>&&> callback) { + return expect_dictionary_keys( + "spriteType", ZERO_OR_MORE, _expect_instance<Sprite, TextureSprite>(callback), + "progressbartype", ZERO_OR_MORE, _expect_instance<Sprite, ProgressBar>(callback), + "PieChartType", ZERO_OR_MORE, _expect_instance<Sprite, PieChart>(callback), + "LineChartType", ZERO_OR_MORE, _expect_instance<Sprite, LineChart>(callback), + "textSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, TextureSprite>(callback), + "maskedShieldType", ZERO_OR_MORE, _expect_instance<Sprite, MaskedFlag>(callback), + "corneredTileSpriteType", ZERO_OR_MORE, success_callback, + "tileSpriteType", ZERO_OR_MORE, success_callback, + "BarChartType", ZERO_OR_MORE, success_callback, + "scrollingSprite", ZERO_OR_MORE, success_callback + ); +} + +TextureSprite::TextureSprite() : texture_file {}, no_of_frames { NO_FRAMES } {} + +bool TextureSprite::_fill_key_map(key_map_t& key_map) { + bool ret = Sprite::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, + "texturefile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)), + "textureFile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file)), + "noOfFrames", ZERO_OR_ONE, expect_uint(assign_variable_callback(no_of_frames)), + + "norefcount", ZERO_OR_ONE, success_callback, + "effectFile", ZERO_OR_ONE, success_callback, + "allwaystransparent", ZERO_OR_ONE, success_callback, + "transparencecheck", ZERO_OR_ONE, success_callback, + "loadType", ZERO_OR_ONE, success_callback, + "clicksound", ZERO_OR_ONE, success_callback + ); + return ret; +} + +ProgressBar::ProgressBar() +: back_colour {}, back_texture_file {}, + progress_colour {}, progress_texture_file {}, + size {} {} + +bool ProgressBar::_fill_key_map(key_map_t& key_map) { + bool ret = Sprite::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, + "color", ONE_EXACTLY, expect_colour(assign_variable_callback(back_colour)), + "colortwo", ONE_EXACTLY, expect_colour(assign_variable_callback(progress_colour)), + "textureFile1", ZERO_OR_ONE, expect_string(assign_variable_callback_string(back_texture_file)), + "textureFile2", ZERO_OR_ONE, expect_string(assign_variable_callback_string(progress_texture_file)), + "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + + "effectFile", ONE_EXACTLY, success_callback, + "allwaystransparent", ZERO_OR_ONE, success_callback, + "loadType", ZERO_OR_ONE, success_callback, + "horizontal", ZERO_OR_ONE, success_callback + ); + return ret; +} + +PieChart::PieChart() : size {} {} + +bool PieChart::_fill_key_map(key_map_t& key_map) { + bool ret = Sprite::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, "size", ONE_EXACTLY, expect_uint(assign_variable_callback(size))); + return ret; +} + +LineChart::LineChart() : size {}, linewidth {} {} + +bool LineChart::_fill_key_map(key_map_t& key_map) { + bool ret = Sprite::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, + "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "linewidth", ONE_EXACTLY, expect_uint(assign_variable_callback(linewidth)), + "allwaystransparent", ZERO_OR_ONE, success_callback + ); + return ret; +} + +MaskedFlag::MaskedFlag() : texture_file {}, mask_file {} {} + +bool MaskedFlag::_fill_key_map(key_map_t& key_map) { + bool ret = Sprite::_fill_key_map(key_map); + ret &= add_key_map_entries(key_map, + "textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(texture_file)), + "textureFile2", ONE_EXACTLY, expect_string(assign_variable_callback_string(mask_file)), + "effectFile", ONE_EXACTLY, success_callback, + "allwaystransparent", ZERO_OR_ONE, success_callback, + "flipv", ZERO_OR_ONE, success_callback + ); + return ret; +} diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp new file mode 100644 index 0000000..e155486 --- /dev/null +++ b/src/openvic-simulation/interface/GFX.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include "openvic-simulation/interface/LoadBase.hpp" + +namespace OpenVic { + class UIManager; +} + +namespace OpenVic::GFX { + + struct Font : HasIdentifierAndColour { + friend class OpenVic::UIManager; + + private: + const std::string PROPERTY(fontname); + + // TODO - colorcodes, effect + + Font(std::string_view new_identifier, colour_t new_colour, std::string_view new_fontname); + + public: + Font(Font&&) = default; + }; + + using frame_t = int32_t; + static constexpr frame_t NO_FRAMES = 0; + + class Sprite : public Named<> { + protected: + Sprite() = default; + + public: + Sprite(Sprite&&) = default; + virtual ~Sprite() = default; + + OV_DETAIL_GET_BASE_TYPE(Sprite) + OV_DETAIL_GET_TYPE + + static NodeTools::node_callback_t expect_sprite(NodeTools::callback_t<std::unique_ptr<Sprite>&&> callback); + }; + + class TextureSprite final : public Sprite { + friend std::unique_ptr<TextureSprite> std::make_unique<TextureSprite>(); + + std::string PROPERTY(texture_file); + frame_t PROPERTY(no_of_frames); + + // TODO - norefcount, effectFile, allwaystransparent + + protected: + TextureSprite(); + + bool _fill_key_map(NodeTools::key_map_t& key_map) override; + + public: + TextureSprite(TextureSprite&&) = default; + virtual ~TextureSprite() = default; + + OV_DETAIL_GET_TYPE + }; + + class ProgressBar final : public Sprite { + friend std::unique_ptr<ProgressBar> std::make_unique<ProgressBar>(); + + colour_t PROPERTY(back_colour); + std::string PROPERTY(back_texture_file); + colour_t PROPERTY(progress_colour); + std::string PROPERTY(progress_texture_file); + ivec2_t PROPERTY(size); + + // TODO - effectFile + + protected: + ProgressBar(); + + bool _fill_key_map(NodeTools::key_map_t& key_map) override; + + public: + ProgressBar(ProgressBar&&) = default; + virtual ~ProgressBar() = default; + + OV_DETAIL_GET_TYPE + }; + + class PieChart final : public Sprite { + friend std::unique_ptr<PieChart> std::make_unique<PieChart>(); + + uint32_t PROPERTY(size); + + protected: + PieChart(); + + bool _fill_key_map(NodeTools::key_map_t& key_map) override; + + public: + PieChart(PieChart&&) = default; + virtual ~PieChart() = default; + + OV_DETAIL_GET_TYPE + }; + + class LineChart final : public Sprite { + friend std::unique_ptr<LineChart> std::make_unique<LineChart>(); + + ivec2_t PROPERTY(size); + uint32_t PROPERTY(linewidth); + + protected: + LineChart(); + + bool _fill_key_map(NodeTools::key_map_t& key_map) override; + + public: + LineChart(LineChart&&) = default; + virtual ~LineChart() = default; + + OV_DETAIL_GET_TYPE + }; + + + class MaskedFlag final : public Sprite { + friend std::unique_ptr<MaskedFlag> std::make_unique<MaskedFlag>(); + + std::string PROPERTY(texture_file) + std::string PROPERTY(mask_file); + + protected: + MaskedFlag(); + + bool _fill_key_map(NodeTools::key_map_t& key_map) override; + + public: + MaskedFlag(MaskedFlag&&) = default; + virtual ~MaskedFlag() = default; + + OV_DETAIL_GET_TYPE + }; +} diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp new file mode 100644 index 0000000..534f552 --- /dev/null +++ b/src/openvic-simulation/interface/GUI.cpp @@ -0,0 +1,182 @@ +#include "GUI.hpp" + +#include "openvic-simulation/interface/UI.hpp" + +using namespace OpenVic; +using namespace OpenVic::GUI; +using namespace OpenVic::NodeTools; + +Element::Element() : position {}, orientation { orientation_t::UPPER_LEFT } {} + +bool Element::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Named::_fill_key_map(key_map, ui_manager); + using enum orientation_t; + static const string_map_t<orientation_t> orientation_map = { + { "UPPER_LEFT", UPPER_LEFT }, { "LOWER_LEFT", LOWER_LEFT }, + { "LOWER_RIGHT", LOWER_RIGHT }, { "UPPER_RIGHT", UPPER_RIGHT }, + { "CENTER", CENTER } + }; + ret &= add_key_map_entries(key_map, + "position", ONE_EXACTLY, expect_ivec2(assign_variable_callback(position)), + "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))), + "Orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation))) + ); + return ret; +} + +bool Element::_fill_elements_key_map( + NodeTools::key_map_t& key_map, callback_t<std::unique_ptr<Element>&&> callback, UIManager const& ui_manager +) { + bool ret = true; + ret &= add_key_map_entries(key_map, + "iconType", ZERO_OR_MORE, _expect_instance<Element, Icon>(callback, ui_manager), + "guiButtonType", ZERO_OR_MORE, _expect_instance<Element, Button>(callback, ui_manager), + "checkboxType", ZERO_OR_MORE, _expect_instance<Element, Checkbox>(callback, ui_manager), + "textBoxType", ZERO_OR_MORE, _expect_instance<Element, Text>(callback, ui_manager), + "instantTextBoxType", ZERO_OR_MORE, _expect_instance<Element, Text>(callback, ui_manager), + "OverlappingElementsBoxType", ZERO_OR_MORE, _expect_instance<Element, OverlappingElementsBox>(callback, ui_manager), + "listboxType", ZERO_OR_MORE, _expect_instance<Element, ListBox>(callback, ui_manager), + "windowType", ZERO_OR_MORE, _expect_instance<Element, Window>(callback, ui_manager), + "positionType", ZERO_OR_MORE, success_callback + ); + return ret; +} + +Scene::Scene() : elements { "scene elements" } {} + +bool Scene::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + return Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool { + return elements.add_item(std::move(element)); + }, ui_manager); +} + +node_callback_t Scene::expect_scene( + std::string_view scene_name, callback_t<std::unique_ptr<Scene>&&> callback, UIManager const& ui_manager +) { + return _expect_instance<Scene, Scene>([scene_name, callback](std::unique_ptr<Scene>&& scene) -> bool { + scene->_set_name(scene_name); + return callback(std::move(scene)); + }, ui_manager); +} + +Window::Window() : elements { "window elements" }, size {}, moveable { false }, fullscreen { false } {} + +bool Window::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool { + return elements.add_item(std::move(element)); + }, ui_manager); + ret &= Element::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "backGround", ZERO_OR_ONE, success_callback, + "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "moveable", ONE_EXACTLY, expect_int_bool(assign_variable_callback(moveable)), + "dontRender", ZERO_OR_ONE, success_callback, + "horizontalBorder", ZERO_OR_ONE, success_callback, + "verticalBorder", ZERO_OR_ONE, success_callback, + "fullScreen", ZERO_OR_ONE, expect_bool(assign_variable_callback(fullscreen)) + ); + return ret; +} + +Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES } {} + +bool Icon::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Element::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "spriteType", ONE_EXACTLY, expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite))), + "frame", ZERO_OR_ONE, expect_uint(assign_variable_callback(frame)) + ); + return ret; +} + +BaseButton::BaseButton() : sprite { nullptr } {} + +bool BaseButton::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Element::_fill_key_map(key_map, ui_manager); + // look up sprite registry for texture sprite with name... + ret &= add_key_map_entries(key_map, + "quadTextureSprite", ONE_EXACTLY, + expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite))), + "shortcut", ZERO_OR_ONE, success_callback + ); + return ret; +} + +Button::Button() : text {}, font { nullptr} {} + +bool Button::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = BaseButton::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "buttonText", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true), + "buttonFont", ZERO_OR_ONE, expect_string(ui_manager.expect_font_str(assign_variable_callback_pointer(font))), + "clicksound", ZERO_OR_ONE, success_callback, + /* These are always empty in the base defines */ + "tooltip", ZERO_OR_ONE, success_callback, + "tooltipText", ZERO_OR_ONE, success_callback, + "delayedTooltipText", ZERO_OR_ONE, success_callback + ); + return ret; +} + +bool Checkbox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = BaseButton::_fill_key_map(key_map, ui_manager); + return ret; +} + +AlignedElement::AlignedElement() : format { format_t::left } {} + +bool AlignedElement::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Element::_fill_key_map(key_map, ui_manager); + using enum format_t; + static const string_map_t<format_t> format_map = { + { "left", left }, { "right", right }, { "centre", centre }, { "center", centre } + }; + ret &= add_key_map_entries(key_map, + "format", ZERO_OR_ONE, expect_identifier(expect_mapped_string(format_map, assign_variable_callback(format)) + )); + return ret; +} + +Text::Text() : text {}, font { nullptr } {} + +bool Text::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "text", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true), + "font", ONE_EXACTLY, expect_string(ui_manager.expect_font_str(assign_variable_callback_pointer(font))), + "maxWidth", ONE_EXACTLY, expect_uint(assign_variable_callback(max_size.x)), + "maxHeight", ONE_EXACTLY, expect_uint(assign_variable_callback(max_size.y)), + + "borderSize", ZERO_OR_ONE, success_callback, + "fixedsize", ZERO_OR_ONE, success_callback, + + // Add warning about redundant key? + "textureFile", ZERO_OR_ONE, success_callback + ); + return ret; +} + +OverlappingElementsBox::OverlappingElementsBox() : size {} {} + +bool OverlappingElementsBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = AlignedElement::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "spacing", ONE_EXACTLY, success_callback + ); + return ret; +} + +ListBox::ListBox() : size {} {} + +bool ListBox::_fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) { + bool ret = Element::_fill_key_map(key_map, ui_manager); + ret &= add_key_map_entries(key_map, + "backGround", ZERO_OR_ONE, success_callback, + "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)), + "spacing", ZERO_OR_ONE, success_callback, + "scrollbartype", ZERO_OR_ONE, success_callback, + "borderSize", ZERO_OR_ONE, success_callback + ); + return ret; +} diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp new file mode 100644 index 0000000..1a76ca0 --- /dev/null +++ b/src/openvic-simulation/interface/GUI.hpp @@ -0,0 +1,235 @@ +#pragma once + +#include "openvic-simulation/interface/GFX.hpp" + +namespace OpenVic { + class UIManager; +} +namespace OpenVic::GUI { + class Scene; + + class Element : public Named<UIManager const&> { + friend class Scene; + + public: + enum class orientation_t { + UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, UPPER_RIGHT, CENTER + }; + + private: + ivec2_t PROPERTY(position); + orientation_t PROPERTY(orientation); + + protected: + Element(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + static bool _fill_elements_key_map( + NodeTools::key_map_t& key_map, NodeTools::callback_t<std::unique_ptr<Element>&&> callback, + UIManager const& ui_manager + ); + + public: + Element(Element&&) = default; + virtual ~Element() = default; + + OV_DETAIL_GET_BASE_TYPE(Element) + OV_DETAIL_GET_TYPE + }; + + class Scene : public Named<UIManager const&> { + friend std::unique_ptr<Scene> std::make_unique<Scene>(); + + NamedInstanceRegistry<Element, UIManager const&> elements; + + protected: + Scene(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Scene(Scene&&) = default; + virtual ~Scene() = default; + + OV_DETAIL_GET_TYPE + + static NodeTools::node_callback_t expect_scene( + std::string_view scene_name, NodeTools::callback_t<std::unique_ptr<Scene>&&> callback, UIManager const& ui_manager + ); + + IDENTIFIER_REGISTRY_ACCESSORS(element) + }; + + class Window final : public Element { + friend std::unique_ptr<Window> std::make_unique<Window>(); + + NamedInstanceRegistry<Element, UIManager const&> elements; + + ivec2_t PROPERTY(size); + bool PROPERTY(moveable); + bool PROPERTY(fullscreen); + // TODO - background, dontRender, horizontalBorder, verticalBorder + + protected: + Window(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Window(Window&&) = default; + virtual ~Window() = default; + + OV_DETAIL_GET_TYPE + + IDENTIFIER_REGISTRY_ACCESSORS(element) + }; + + class Icon final : public Element { + friend std::unique_ptr<Icon> std::make_unique<Icon>(); + + GFX::Sprite const* PROPERTY(sprite); + GFX::frame_t PROPERTY(frame); + + protected: + Icon(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Icon(Icon&&) = default; + virtual ~Icon() = default; + + OV_DETAIL_GET_TYPE + }; + + class BaseButton : public Element { + GFX::Sprite const* PROPERTY(sprite); + // TODO - shortcut + + protected: + BaseButton(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + BaseButton(BaseButton&&) = default; + virtual ~BaseButton() = default; + + OV_DETAIL_GET_TYPE + }; + + class Button final : public BaseButton { + friend std::unique_ptr<Button> std::make_unique<Button>(); + + std::string PROPERTY(text); + GFX::Font const* PROPERTY(font); + + // TODO - clicksound + + protected: + Button() ; + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Button(Button&&) = default; + virtual ~Button() = default; + + OV_DETAIL_GET_TYPE + }; + + class Checkbox final : public BaseButton { + friend std::unique_ptr<Checkbox> std::make_unique<Checkbox>(); + + protected: + Checkbox() = default; + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Checkbox(Checkbox&&) = default; + virtual ~Checkbox() = default; + + OV_DETAIL_GET_TYPE + }; + + class AlignedElement : public Element { + public: + enum class format_t { + left, centre, right + }; + + private: + format_t PROPERTY(format); + + protected: + AlignedElement(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + AlignedElement(AlignedElement&&) = default; + virtual ~AlignedElement() = default; + + OV_DETAIL_GET_TYPE + }; + + class Text final : public AlignedElement { + friend std::unique_ptr<Text> std::make_unique<Text>(); + + std::string PROPERTY(text); + GFX::Font const* PROPERTY(font); + ivec2_t PROPERTY(max_size); // maxWidth, maxHeight + + // TODO - borderSize, fixedsize, textureFile + + protected: + Text(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + Text(Text&&) = default; + virtual ~Text() = default; + + OV_DETAIL_GET_TYPE + }; + + class OverlappingElementsBox final : public AlignedElement { + friend std::unique_ptr<OverlappingElementsBox> std::make_unique<OverlappingElementsBox>(); + + ivec2_t PROPERTY(size); + + // TODO - spacing + + protected: + OverlappingElementsBox(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + OverlappingElementsBox(OverlappingElementsBox&&) = default; + virtual ~OverlappingElementsBox() = default; + + OV_DETAIL_GET_TYPE + }; + + class ListBox final : public Element { + friend std::unique_ptr<ListBox> std::make_unique<ListBox>(); + + ivec2_t PROPERTY(size); + + // TODO - backGround, spacing, scrollbartype, borderSize + + protected: + ListBox(); + + bool _fill_key_map(NodeTools::key_map_t& key_map, UIManager const& ui_manager) override; + + public: + ListBox(ListBox&&) = default; + virtual ~ListBox() = default; + + OV_DETAIL_GET_TYPE + }; +} diff --git a/src/openvic-simulation/interface/LoadBase.hpp b/src/openvic-simulation/interface/LoadBase.hpp new file mode 100644 index 0000000..3ee7c83 --- /dev/null +++ b/src/openvic-simulation/interface/LoadBase.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "openvic-simulation/types/IdentifierRegistry.hpp" +#include "openvic-simulation/utility/Getters.hpp" + +namespace OpenVic { + + template<typename... _Context> + class LoadBase { + protected: + LoadBase() = default; + + virtual bool _fill_key_map(NodeTools::key_map_t&, _Context...) = 0; + + public: + LoadBase(LoadBase&&) = default; + virtual ~LoadBase() = default; + + bool load(ast::NodeCPtr node, _Context... context) { + NodeTools::key_map_t key_map; + bool ret = _fill_key_map(key_map, context...); + ret &= NodeTools::expect_dictionary_key_map(std::move(key_map))(node); + return ret; + } + + template<std::derived_from<LoadBase<_Context...>> T, std::derived_from<T> U> + static NodeTools::node_callback_t _expect_instance( + NodeTools::callback_t<std::unique_ptr<T>&&> callback, _Context... context + ) { + return [callback, &context...](ast::NodeCPtr node) -> bool { + std::unique_ptr<T> instance { std::make_unique<U>() }; + bool ret = instance->load(node, context...); + ret &= callback(std::move(instance)); + return ret; + }; + } + + OV_DETAIL_GET_TYPE_BASE_CLASS(LoadBase) + }; + + template<typename... _Context> + class Named : public LoadBase<_Context...> { + std::string PROPERTY(name); + + protected: + Named() = default; + + virtual bool _fill_key_map(NodeTools::key_map_t& key_map, _Context...) override { + using namespace OpenVic::NodeTools; + return add_key_map_entries(key_map, "name", ONE_EXACTLY, expect_string(assign_variable_callback_string(name))); + } + + void _set_name(std::string_view new_name) { + if (!name.empty()) { + Logger::warning("Overriding scene name ", name, " with ", new_name); + } + name = new_name; + } + + public: + Named(Named&&) = default; + virtual ~Named() = default; + + OV_DETAIL_GET_TYPE + }; + + template<typename T, typename... _Context> + requires std::derived_from<T, Named<_Context...>> + struct _get_name { + constexpr std::string_view operator()(T const* item) const { + return item->get_name(); + } + }; + + template<typename T, typename... _Context> + requires std::derived_from<T, Named<_Context...>> + using NamedRegistry = ValueRegistry<T, _get_name<T, _Context...>>; + + template<typename T, typename... _Context> + requires std::derived_from<T, Named<_Context...>> + using NamedInstanceRegistry = InstanceRegistry<T, _get_name<T, _Context...>>; +} diff --git a/src/openvic-simulation/interface/UI.cpp b/src/openvic-simulation/interface/UI.cpp new file mode 100644 index 0000000..4653e5b --- /dev/null +++ b/src/openvic-simulation/interface/UI.cpp @@ -0,0 +1,92 @@ +#include "UI.hpp" + +using namespace OpenVic; +using namespace OpenVic::NodeTools; +using namespace OpenVic::GFX; +using namespace OpenVic::GUI; + +UIManager::UIManager() : sprites { "sprites" }, scenes { "scenes" }, fonts { "fonts" } {} + +bool UIManager::add_font(std::string_view identifier, colour_t colour, std::string_view fontname) { + if (identifier.empty()) { + Logger::error("Invalid font identifier - empty!"); + return false; + } + if (fontname.empty()) { + Logger::error("Invalid culture colour for ", identifier, ": ", colour_to_hex_string(colour)); + return false; + } + return fonts.add_item({ identifier, colour, fontname }, duplicate_warning_callback); +} + +bool UIManager::_load_font(ast::NodeCPtr node) { + std::string_view identifier, fontname; + colour_t colour = NULL_COLOUR; + bool ret = expect_dictionary_keys( + "name", ONE_EXACTLY, expect_string(assign_variable_callback(identifier)), + "fontname", ONE_EXACTLY, expect_string(assign_variable_callback(fontname)), + "color", ONE_EXACTLY, expect_colour_hex(assign_variable_callback(colour)), + "colorcodes", ZERO_OR_ONE, success_callback, + "effect", ZERO_OR_ONE, success_callback + )(node); + ret &= add_font(identifier, colour, fontname); + return ret; +} + +bool UIManager::load_gfx_file(ast::NodeCPtr root) { + return expect_dictionary_keys( + "spriteTypes", ZERO_OR_ONE, Sprite::expect_sprite( + [this](std::unique_ptr<Sprite>&& sprite) -> bool { + /* TODO - more checks on duplicates (the false here reduces them from + * errors to warnings). The repeats in vanilla are identical (simple + * texture sprites with the same name referring to the same asset), + * maybe check if duplicates are equal? (this would require some kind + * of duplicate handling callback for `add_item`) + * + * It's also possible that some of the vanilla duplicates are intentional, + * after all I'm assuming all GFX files are loaded into a global registry + * rather than each GUI file using only the contnts of a few specific, + * maybe even hardcoded GFX files. This can't, however, explain all of the + * vanilla duplicates, as GFX_frontend_tab_button is repeated in the same + * file, albeit in a section marked "OLD STUFF BELOW..". + * + * Vanilla Duplicates: + * - GFX_bp_open_manager and GFX_bp_toggle_visible + * - simple texture sprites appearing identically in menubar.gfx and battleplansinterface.gfx + * - GFX_frontend_tab_button + * - texture sprite appearing twice identically in the same file (temp_frontend.gfx), + * both below a comment saying "OLD STUFF BELOW.." + */ + return sprites.add_item(std::move(sprite), duplicate_warning_callback); + } + ), + "bitmapfonts", ZERO_OR_ONE, expect_dictionary( + [this](std::string_view key, ast::NodeCPtr node) -> bool { + if (key != "bitmapfont") { + Logger::error("Invalid bitmapfonts key: ", key); + return false; + } + return _load_font(node); + } + ), + "objectTypes", ZERO_OR_ONE, success_callback, + "lightTypes", ZERO_OR_ONE, success_callback, + "fonts", ZERO_OR_ONE, success_callback + )(root); +} + +bool UIManager::load_gui_file(std::string_view scene_name, ast::NodeCPtr root) { + if (!sprites_are_locked()) { + Logger::error("Cannot load GUI files until GFX files (i.e. Sprites) are locked!"); + return false; + } + return expect_dictionary_keys( + "guiTypes", ZERO_OR_ONE, Scene::expect_scene( + scene_name, + [this](std::unique_ptr<Scene>&& scene) -> bool { + return scenes.add_item(std::move(scene)); + }, + *this + ) + )(root); +} diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp new file mode 100644 index 0000000..045766b --- /dev/null +++ b/src/openvic-simulation/interface/UI.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "openvic-simulation/interface/GUI.hpp" + +namespace OpenVic { + + class UIManager { + + NamedInstanceRegistry<GFX::Sprite> sprites; + NamedInstanceRegistry<GUI::Scene, UIManager const&> scenes; + IdentifierRegistry<GFX::Font> fonts; + + bool _load_font(ast::NodeCPtr node); + + public: + UIManager(); + + IDENTIFIER_REGISTRY_ACCESSORS(sprite) + IDENTIFIER_REGISTRY_ACCESSORS(scene) + IDENTIFIER_REGISTRY_ACCESSORS(font) + + bool add_font(std::string_view identifier, colour_t colour, std::string_view fontname); + + bool load_gfx_file(ast::NodeCPtr root); + bool load_gui_file(std::string_view scene_name, ast::NodeCPtr root); + }; +} |