From fd686eadf81e85bd4993a483adcefd6a153d259f Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 7 Nov 2023 22:18:08 +0000 Subject: GUI and GFX file loading --- src/openvic-simulation/GameManager.hpp | 3 + src/openvic-simulation/dataloader/Dataloader.cpp | 47 +++++ src/openvic-simulation/dataloader/Dataloader.hpp | 4 + src/openvic-simulation/dataloader/NodeTools.cpp | 22 ++- src/openvic-simulation/dataloader/NodeTools.hpp | 13 +- src/openvic-simulation/interface/GFX.cpp | 98 ++++++++++ src/openvic-simulation/interface/GFX.hpp | 138 +++++++++++++ src/openvic-simulation/interface/GUI.cpp | 182 ++++++++++++++++++ src/openvic-simulation/interface/GUI.hpp | 235 +++++++++++++++++++++++ src/openvic-simulation/interface/LoadBase.hpp | 82 ++++++++ src/openvic-simulation/interface/UI.cpp | 92 +++++++++ src/openvic-simulation/interface/UI.hpp | 27 +++ src/openvic-simulation/map/TerrainType.cpp | 4 +- src/openvic-simulation/utility/Getters.hpp | 32 +++ 14 files changed, 965 insertions(+), 14 deletions(-) create mode 100644 src/openvic-simulation/interface/GFX.cpp create mode 100644 src/openvic-simulation/interface/GFX.hpp create mode 100644 src/openvic-simulation/interface/GUI.cpp create mode 100644 src/openvic-simulation/interface/GUI.hpp create mode 100644 src/openvic-simulation/interface/LoadBase.hpp create mode 100644 src/openvic-simulation/interface/UI.cpp create mode 100644 src/openvic-simulation/interface/UI.hpp (limited to 'src/openvic-simulation') diff --git a/src/openvic-simulation/GameManager.hpp b/src/openvic-simulation/GameManager.hpp index 9ee3442..6be2938 100644 --- a/src/openvic-simulation/GameManager.hpp +++ b/src/openvic-simulation/GameManager.hpp @@ -5,6 +5,7 @@ #include "openvic-simulation/country/Country.hpp" #include "openvic-simulation/economy/EconomyManager.hpp" #include "openvic-simulation/history/HistoryManager.hpp" +#include "openvic-simulation/interface/UI.hpp" #include "openvic-simulation/map/Map.hpp" #include "openvic-simulation/military/MilitaryManager.hpp" #include "openvic-simulation/misc/Define.hpp" @@ -24,6 +25,7 @@ namespace OpenVic { HistoryManager history_manager; PopManager pop_manager; CountryManager country_manager; + UIManager ui_manager; GameAdvancementHook clock; time_t session_start; /* SS-54, as well as allowing time-tracking */ @@ -47,6 +49,7 @@ namespace OpenVic { REF_GETTERS(history_manager) REF_GETTERS(pop_manager) REF_GETTERS(country_manager) + REF_GETTERS(ui_manager) REF_GETTERS(clock) bool setup(); diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp index aefb6fc..f50aa39 100644 --- a/src/openvic-simulation/dataloader/Dataloader.cpp +++ b/src/openvic-simulation/dataloader/Dataloader.cpp @@ -411,6 +411,19 @@ fs::path Dataloader::lookup_file(std::string_view path, bool print_error) const return {}; } +fs::path Dataloader::lookup_image_file(std::string_view path) const { + fs::path ret = lookup_file(path, false); + if (ret.empty()) { + // TODO - change search order so root order takes priority over extension replacement order + ret = lookup_file(append_string_views(StringUtils::remove_extension(path), ".dds"), false); + if (!ret.empty()) { + return ret; + } + Logger::error("Image lookup for ", path, " failed!"); + } + return ret; +} + template _Equiv> Dataloader::path_vector_t Dataloader::_lookup_files_in_dir(std::string_view path, fs::path const& extension) const { #if FILESYSTEM_NEEDS_FORWARD_SLASHES @@ -555,6 +568,36 @@ csv::Windows1252Parser Dataloader::parse_csv(fs::path const& path) { return _run_ovdl_parser(path); } +bool Dataloader::_load_interface_files(UIManager& ui_manager) const { + static constexpr std::string_view interface_directory = "interface/"; + + bool ret = apply_to_files( + lookup_files_in_dir(interface_directory, ".gfx"), + [&ui_manager](fs::path const& file) -> bool { + return ui_manager.load_gfx_file(parse_defines(file).get_file_node()); + } + ); + ui_manager.lock_sprites(); + ui_manager.lock_fonts(); + + // Hard-coded example until the mechanism for requesting them from GDScript is fleshed out + static const std::vector gui_files { + "province_interface.gui", "topbar.gui" + }; + for (std::string_view const& gui_file : gui_files) { + if (!ui_manager.load_gui_file( + gui_file, + parse_defines(lookup_file(append_string_views(interface_directory, gui_file))).get_file_node() + )) { + Logger::error("Failed to load interface gui file: ", gui_file); + ret = false; + } + } + ui_manager.lock_scenes(); + + return ret; +} + bool Dataloader::_load_pop_types( PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager ) const { @@ -798,6 +841,10 @@ bool Dataloader::load_defines(GameManager& game_manager) const { bool ret = true; + if (!_load_interface_files(game_manager.get_ui_manager())) { + Logger::error("Failed to load interface files!"); + ret = false; + } if (!game_manager.get_modifier_manager().setup_modifier_effects()) { Logger::error("Failed to set up modifier effects!"); ret = false; diff --git a/src/openvic-simulation/dataloader/Dataloader.hpp b/src/openvic-simulation/dataloader/Dataloader.hpp index 2123469..7c71763 100644 --- a/src/openvic-simulation/dataloader/Dataloader.hpp +++ b/src/openvic-simulation/dataloader/Dataloader.hpp @@ -12,6 +12,7 @@ namespace OpenVic { namespace fs = std::filesystem; struct GameManager; + class UIManager; struct PopManager; struct UnitManager; struct GoodManager; @@ -23,6 +24,7 @@ namespace OpenVic { private: path_vector_t roots; + bool _load_interface_files(UIManager& ui_manager) const; bool _load_pop_types(PopManager& pop_manager, UnitManager const& unit_manager, GoodManager const& good_manager) const; bool _load_units(UnitManager& unit_manager, GoodManager const& good_manager) const; bool _load_map_dir(GameManager& game_manager) const; @@ -70,6 +72,8 @@ namespace OpenVic { * DAT-24 */ fs::path lookup_file(std::string_view path, bool print_error = true) const; + /* Checks alternate file endings, e.g. if "*.tga" doesn't exist then try "*.dds" */ + fs::path lookup_image_file(std::string_view path) const; path_vector_t lookup_files_in_dir(std::string_view path, fs::path const& extension) const; path_vector_t lookup_files_in_dir_recursive(std::string_view path, fs::path const& extension) const; path_vector_t lookup_basic_indentifier_prefixed_files_in_dir(std::string_view path, fs::path const& extension) const; diff --git a/src/openvic-simulation/dataloader/NodeTools.cpp b/src/openvic-simulation/dataloader/NodeTools.cpp index 27d0f95..c412f33 100644 --- a/src/openvic-simulation/dataloader/NodeTools.cpp +++ b/src/openvic-simulation/dataloader/NodeTools.cpp @@ -76,10 +76,10 @@ node_callback_t NodeTools::expect_int_bool(callback_t callback) { return expect_identifier(expect_mapped_string(bool_map, callback)); } -node_callback_t NodeTools::expect_int64(callback_t callback) { - return expect_identifier([callback](std::string_view identifier) -> bool { +node_callback_t NodeTools::expect_int64(callback_t callback, int base) { + return expect_identifier([callback, base](std::string_view identifier) -> bool { bool successful = false; - const int64_t val = StringUtils::string_to_int64(identifier, &successful, 10); + const int64_t val = StringUtils::string_to_int64(identifier, &successful, base); if (successful) { return callback(val); } @@ -88,10 +88,10 @@ node_callback_t NodeTools::expect_int64(callback_t callback) { }); } -node_callback_t NodeTools::expect_uint64(callback_t callback) { - return expect_identifier([callback](std::string_view identifier) -> bool { +node_callback_t NodeTools::expect_uint64(callback_t callback, int base) { + return expect_identifier([callback, base](std::string_view identifier) -> bool { bool successful = false; - const uint64_t val = StringUtils::string_to_uint64(identifier, &successful, 10); + const uint64_t val = StringUtils::string_to_uint64(identifier, &successful, base); if (successful) { return callback(val); } @@ -141,6 +141,10 @@ node_callback_t NodeTools::expect_colour(callback_t callback) { }; } +node_callback_t NodeTools::expect_colour_hex(callback_t callback) { + return expect_uint(callback, 16); +} + callback_t NodeTools::expect_date_str(callback_t callback) { return [callback](std::string_view identifier) -> bool { bool successful = false; @@ -188,8 +192,12 @@ NodeCallback auto _expect_vec2(Callback> auto callback) { }; } +static node_callback_t _expect_int(callback_t callback) { + return expect_int(callback); +} + node_callback_t NodeTools::expect_ivec2(callback_t callback) { - return _expect_vec2(callback); + return _expect_vec2(callback); } node_callback_t NodeTools::expect_fvec2(callback_t callback) { diff --git a/src/openvic-simulation/dataloader/NodeTools.hpp b/src/openvic-simulation/dataloader/NodeTools.hpp index a23fb4f..1ca6cf0 100644 --- a/src/openvic-simulation/dataloader/NodeTools.hpp +++ b/src/openvic-simulation/dataloader/NodeTools.hpp @@ -73,11 +73,11 @@ namespace OpenVic { node_callback_t expect_bool(callback_t callback); node_callback_t expect_int_bool(callback_t callback); - node_callback_t expect_int64(callback_t callback); - node_callback_t expect_uint64(callback_t callback); + node_callback_t expect_int64(callback_t callback, int base = 10); + node_callback_t expect_uint64(callback_t callback, int base = 10); template - NodeCallback auto expect_int(callback_t callback) { + NodeCallback auto expect_int(callback_t callback, int base = 10) { return expect_int64([callback](int64_t val) -> bool { if (static_cast(std::numeric_limits::lowest()) <= val && val <= static_cast(std::numeric_limits::max())) { @@ -88,11 +88,11 @@ namespace OpenVic { static_cast(std::numeric_limits::max()), "])" ); return false; - }); + }, base); } template - NodeCallback auto expect_uint(callback_t callback) { + NodeCallback auto expect_uint(callback_t callback, int base = 10) { return expect_uint64([callback](uint64_t val) -> bool { if (val <= static_cast(std::numeric_limits::max())) { return callback(val); @@ -101,12 +101,13 @@ namespace OpenVic { "Invalid uint: ", val, " (valid range: [0, ", static_cast(std::numeric_limits::max()), "])" ); return false; - }); + }, base); } callback_t expect_fixed_point_str(callback_t callback); node_callback_t expect_fixed_point(callback_t callback); node_callback_t expect_colour(callback_t callback); + node_callback_t expect_colour_hex(callback_t callback); callback_t expect_date_str(callback_t callback); node_callback_t expect_date(callback_t callback); 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&&> callback) { + return expect_dictionary_keys( + "spriteType", ZERO_OR_MORE, _expect_instance(callback), + "progressbartype", ZERO_OR_MORE, _expect_instance(callback), + "PieChartType", ZERO_OR_MORE, _expect_instance(callback), + "LineChartType", ZERO_OR_MORE, _expect_instance(callback), + "textSpriteType", ZERO_OR_MORE, _expect_instance(callback), + "maskedShieldType", ZERO_OR_MORE, _expect_instance(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&&> callback); + }; + + class TextureSprite final : public Sprite { + friend std::unique_ptr std::make_unique(); + + 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 std::make_unique(); + + 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 std::make_unique(); + + 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 std::make_unique(); + + 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 std::make_unique(); + + 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_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&&> callback, UIManager const& ui_manager +) { + bool ret = true; + ret &= add_key_map_entries(key_map, + "iconType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "guiButtonType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "checkboxType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "textBoxType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "instantTextBoxType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "OverlappingElementsBoxType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "listboxType", ZERO_OR_MORE, _expect_instance(callback, ui_manager), + "windowType", ZERO_OR_MORE, _expect_instance(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) -> bool { + return elements.add_item(std::move(element)); + }, ui_manager); +} + +node_callback_t Scene::expect_scene( + std::string_view scene_name, callback_t&&> callback, UIManager const& ui_manager +) { + return _expect_instance([scene_name, callback](std::unique_ptr&& 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) -> 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_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 { + 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&&> 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 { + friend std::unique_ptr std::make_unique(); + + NamedInstanceRegistry 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&&> callback, UIManager const& ui_manager + ); + + IDENTIFIER_REGISTRY_ACCESSORS(element) + }; + + class Window final : public Element { + friend std::unique_ptr std::make_unique(); + + NamedInstanceRegistry 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 std::make_unique(); + + 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