aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author hop311 <hop3114@gmail.com>2024-02-04 15:09:06 +0100
committer hop311 <hop3114@gmail.com>2024-02-04 15:09:06 +0100
commit87fa1c74281a651b23089079c4c1621d4fb66d73 (patch)
tree4e343f81b13f166ad4a478962348d4734ea7e11b
parent3f6d7351816b0e089495b2f15dc1c956f3151f5a (diff)
Added support for loading all gui filesgui-loading
-rw-r--r--src/openvic-simulation/dataloader/Dataloader.cpp19
-rw-r--r--src/openvic-simulation/interface/GFX.cpp35
-rw-r--r--src/openvic-simulation/interface/GFX.hpp28
-rw-r--r--src/openvic-simulation/interface/GUI.cpp208
-rw-r--r--src/openvic-simulation/interface/GUI.hpp114
-rw-r--r--src/openvic-simulation/interface/LoadBase.hpp12
-rw-r--r--src/openvic-simulation/interface/UI.cpp41
-rw-r--r--src/openvic-simulation/interface/UI.hpp6
8 files changed, 391 insertions, 72 deletions
diff --git a/src/openvic-simulation/dataloader/Dataloader.cpp b/src/openvic-simulation/dataloader/Dataloader.cpp
index c6d6281..157ff04 100644
--- a/src/openvic-simulation/dataloader/Dataloader.cpp
+++ b/src/openvic-simulation/dataloader/Dataloader.cpp
@@ -283,21 +283,34 @@ bool Dataloader::_load_interface_files(UIManager& ui_manager) const {
ui_manager.lock_sprites();
ui_manager.lock_fonts();
- // Hard-coded example until the mechanism for requesting them from GDScript is fleshed out
+ /* Hard-coded GUI file names, might be replaced with a dynamic system but everything should still be loaded on startup. */
static const std::vector<std::string_view> gui_files {
- "province_interface.gui", "topbar.gui"
+ /* Contains generic listbox scrollbar */
+ "core",
+
+ /* Over-map menus */
+ "province_interface", "topbar", "menubar", "outliner",
+
+ /* Nation management screens */
+ "country_production", "country_budget", "country_technology", "country_politics", "country_pops", "country_trade",
+ "country_diplomacy", "country_military"
};
+ static constexpr std::string_view gui_file_extension = ".gui";
+
ui_manager.reserve_more_scenes(gui_files.size());
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()
+ gui_file, parse_defines(lookup_file(
+ append_string_views(interface_directory, gui_file, gui_file_extension)
+ )).get_file_node()
)) {
Logger::error("Failed to load interface gui file: ", gui_file);
ret = false;
}
}
+
ui_manager.lock_scenes();
return ret;
diff --git a/src/openvic-simulation/interface/GFX.cpp b/src/openvic-simulation/interface/GFX.cpp
index ca31419..ff2737c 100644
--- a/src/openvic-simulation/interface/GFX.cpp
+++ b/src/openvic-simulation/interface/GFX.cpp
@@ -4,8 +4,11 @@ using namespace OpenVic;
using namespace OpenVic::GFX;
using namespace OpenVic::NodeTools;
-Font::Font(std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname)
- : HasIdentifierAndAlphaColour { new_identifier, new_colour, false }, fontname { new_fontname } {}
+Font::Font(
+ std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname, std::string_view new_charset,
+ uint32_t new_height
+) : HasIdentifierAndAlphaColour { new_identifier, new_colour, false }, fontname { new_fontname }, charset { new_charset },
+ height { new_height } {}
node_callback_t Sprite::expect_sprites(length_callback_t length_callback, callback_t<std::unique_ptr<Sprite>&&> callback) {
return expect_dictionary_keys_and_length(
@@ -17,8 +20,9 @@ node_callback_t Sprite::expect_sprites(length_callback_t length_callback, callba
"textSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, TextureSprite>(callback),
"maskedShieldType", ZERO_OR_MORE, _expect_instance<Sprite, MaskedFlag>(callback),
"tileSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, TileTextureSprite>(callback),
- // TODO - add the rest of the sprite types
- "corneredTileSpriteType", ZERO_OR_MORE, success_callback,
+ "corneredTileSpriteType", ZERO_OR_MORE, _expect_instance<Sprite, CorneredTileTextureSprite>(callback),
+
+ /* Each only has one vanilla instance which isn't used anywhere. */
"BarChartType", ZERO_OR_MORE, success_callback,
"scrollingSprite", ZERO_OR_MORE, success_callback
);
@@ -47,8 +51,8 @@ TileTextureSprite::TileTextureSprite() : texture_file {}, size {} {}
bool TileTextureSprite::_fill_key_map(case_insensitive_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)),
- "size", ZERO_OR_ONE, expect_ivec2(assign_variable_callback(size)),
+ "texturefile", ONE_EXACTLY, expect_string(assign_variable_callback_string(texture_file)),
+ "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)),
"norefcount", ZERO_OR_ONE, success_callback,
"loadType", ZERO_OR_ONE, success_callback
@@ -56,7 +60,22 @@ bool TileTextureSprite::_fill_key_map(case_insensitive_key_map_t& key_map) {
return ret;
}
-ProgressBar::ProgressBar() : back_colour {}, progress_colour {} {}
+CorneredTileTextureSprite::CorneredTileTextureSprite() : texture_file {}, size {}, border_size {} {}
+
+bool CorneredTileTextureSprite::_fill_key_map(case_insensitive_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)),
+ "size", ONE_EXACTLY, expect_ivec2(assign_variable_callback(size)),
+ "borderSize", ONE_EXACTLY, expect_ivec2(assign_variable_callback(border_size)),
+
+ "allwaystransparent", ZERO_OR_ONE, success_callback,
+ "loadType", 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(case_insensitive_key_map_t& key_map) {
bool ret = Sprite::_fill_key_map(key_map);
@@ -90,6 +109,7 @@ bool LineChart::_fill_key_map(case_insensitive_key_map_t& 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;
@@ -102,6 +122,7 @@ bool MaskedFlag::_fill_key_map(case_insensitive_key_map_t& key_map) {
ret &= add_key_map_entries(key_map,
"textureFile1", ONE_EXACTLY, expect_string(assign_variable_callback_string(overlay_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
diff --git a/src/openvic-simulation/interface/GFX.hpp b/src/openvic-simulation/interface/GFX.hpp
index 21baa85..108ecb6 100644
--- a/src/openvic-simulation/interface/GFX.hpp
+++ b/src/openvic-simulation/interface/GFX.hpp
@@ -12,11 +12,16 @@ namespace OpenVic::GFX {
friend class OpenVic::UIManager;
private:
- const std::string PROPERTY(fontname);
+ std::string PROPERTY(fontname);
+ std::string PROPERTY(charset);
+ uint32_t PROPERTY(height);
// TODO - colorcodes, effect
- Font(std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname);
+ Font(
+ std::string_view new_identifier, colour_argb_t new_colour, std::string_view new_fontname,
+ std::string_view new_charset, uint32_t new_height
+ );
public:
Font(Font&&) = default;
@@ -79,6 +84,25 @@ namespace OpenVic::GFX {
OV_DETAIL_GET_TYPE
};
+ class CorneredTileTextureSprite final : public Sprite {
+ friend std::unique_ptr<CorneredTileTextureSprite> std::make_unique<CorneredTileTextureSprite>();
+
+ std::string PROPERTY(texture_file);
+ ivec2_t PROPERTY(size);
+ ivec2_t PROPERTY(border_size);
+
+ protected:
+ CorneredTileTextureSprite();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override;
+
+ public:
+ CorneredTileTextureSprite(CorneredTileTextureSprite&&) = default;
+ virtual ~CorneredTileTextureSprite() = default;
+
+ OV_DETAIL_GET_TYPE
+ };
+
class ProgressBar final : public Sprite {
friend std::unique_ptr<ProgressBar> std::make_unique<ProgressBar>();
diff --git a/src/openvic-simulation/interface/GUI.cpp b/src/openvic-simulation/interface/GUI.cpp
index 7aebfe8..94e1fe3 100644
--- a/src/openvic-simulation/interface/GUI.cpp
+++ b/src/openvic-simulation/interface/GUI.cpp
@@ -6,6 +6,16 @@ using namespace OpenVic;
using namespace OpenVic::GUI;
using namespace OpenVic::NodeTools;
+Position::Position() : position {} {}
+
+bool Position::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) {
+ bool ret = Named::_fill_key_map(key_map);
+ ret &= add_key_map_entry(key_map,
+ "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position))
+ );
+ return ret;
+}
+
Element::Element() : position {}, orientation { orientation_t::UPPER_LEFT } {}
bool Element::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
@@ -14,11 +24,14 @@ bool Element::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIMa
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 }
+ { "CENTER", CENTER }, { "CENTER_UP", CENTER_UP }, { "CENTER_DOWN", CENTER_DOWN }
};
ret &= add_key_map_entries(key_map,
- "position", ONE_EXACTLY, expect_fvec2(assign_variable_callback(position)),
- "orientation", ZERO_OR_ONE, expect_string(expect_mapped_string(orientation_map, assign_variable_callback(orientation)))
+ "position", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(position)),
+ "orientation", ZERO_OR_ONE, expect_identifier_or_string(expect_mapped_string(
+ orientation_map, assign_variable_callback(orientation),
+ true /* Warn if the key here is invalid, leaving the default orientation UPPER_LEFT unchanged. */
+ ))
);
return ret;
}
@@ -29,22 +42,31 @@ bool Element::_fill_elements_key_map(
bool ret = true;
ret &= add_key_map_entries(key_map,
"iconType", ZERO_OR_MORE, _expect_instance<Element, Icon>(callback, ui_manager),
+ "shieldtype", 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),
+ "editBoxType", ZERO_OR_MORE, _expect_instance<Element, TextEditBox>(callback, ui_manager),
+ "scrollbarType", ZERO_OR_MORE, _expect_instance<Element, Scrollbar>(callback, ui_manager),
"windowType", ZERO_OR_MORE, _expect_instance<Element, Window>(callback, ui_manager),
- "positionType", ZERO_OR_MORE, success_callback // TODO - load this as a marker for placing sub-scenes
+ "eu3dialogtype", ZERO_OR_MORE, _expect_instance<Element, Window>(callback, ui_manager)
);
return ret;
}
bool Scene::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
- return Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool {
+ bool ret = Element::_fill_elements_key_map(key_map, [this](std::unique_ptr<Element>&& element) -> bool {
return scene_elements.add_item(std::move(element));
}, ui_manager);
+ ret &= add_key_map_entry(key_map,
+ "positionType", ZERO_OR_MORE, Position::_expect_value<Position>([this](Position&& position) -> bool {
+ return scene_positions.add_item(std::move(position));
+ })
+ );
+ return ret;
}
node_callback_t Scene::expect_scene(
@@ -56,7 +78,7 @@ node_callback_t Scene::expect_scene(
}, ui_manager);
}
-Window::Window() : moveable { false }, fullscreen { false } {}
+Window::Window() : background {}, size {}, moveable { false }, fullscreen { false } {}
bool Window::_fill_key_map(NodeTools::case_insensitive_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 {
@@ -64,55 +86,71 @@ bool Window::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIMan
}, ui_manager);
ret &= Element::_fill_key_map(key_map, ui_manager);
ret &= add_key_map_entries(key_map,
- "backGround", ZERO_OR_ONE, success_callback, // TODO - load as potential panel texture (almost always empty)
"size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
- "moveable", ONE_EXACTLY, expect_int_bool(assign_variable_callback(moveable)),
+ "moveable", ZERO_OR_ONE, expect_int_bool(assign_variable_callback(moveable)),
+ "fullScreen", ZERO_OR_ONE, expect_bool(assign_variable_callback(fullscreen)),
+ "backGround", ZERO_OR_ONE, expect_string(assign_variable_callback_string(background), true),
+
"dontRender", ZERO_OR_ONE, success_callback, // always empty string?
"horizontalBorder", ZERO_OR_ONE, success_callback,
"verticalBorder", ZERO_OR_ONE, success_callback,
- "fullScreen", ZERO_OR_ONE, expect_bool(assign_variable_callback(fullscreen))
+ "upsound", ZERO_OR_ONE, success_callback,
+ "downsound", ZERO_OR_ONE, success_callback
);
return ret;
}
-Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES } {}
+Icon::Icon() : sprite { nullptr }, frame { GFX::NO_FRAMES }, scale { 1 }, rotation { 0 } {}
bool Icon::_fill_key_map(NodeTools::case_insensitive_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))
+ // TODO - make these share a ONE_EXACTLY count
+ "spriteType", ZERO_OR_ONE, ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+ "buttonMesh", ZERO_OR_ONE, ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+
+ "frame", ZERO_OR_ONE, expect_uint(assign_variable_callback(frame)),
+ "scale", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(scale)),
+ "rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(rotation))
);
return ret;
}
-BaseButton::BaseButton() : sprite { nullptr } {}
+BaseButton::BaseButton() : sprite { nullptr }, text {}, font { nullptr } {}
bool BaseButton::_fill_key_map(NodeTools::case_insensitive_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,
+ // TODO - make these share a ONE_EXACTLY count
"quadTextureSprite", ZERO_OR_ONE,
- expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite)), true),
+ ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite), true),
"spriteType", ZERO_OR_ONE,
- expect_string(ui_manager.expect_sprite_str(assign_variable_callback_pointer(sprite)), true),
- "shortcut", ZERO_OR_ONE, success_callback // TODO - load and use shortcuts (how to integrate with custom keybinds?)
+ ui_manager.expect_sprite_string(assign_variable_callback_pointer(sprite)),
+
+ "buttonText", ZERO_OR_ONE, expect_string(assign_variable_callback_string(text), true),
+ /* Some buttons have multiple fonts listed with the last one being used. */
+ "buttonFont", ZERO_OR_MORE, ui_manager.expect_font_string(assign_variable_callback_pointer(font), true),
+
+ "shortcut", ZERO_OR_ONE, success_callback, // TODO - load and use shortcuts (how to integrate with custom keybinds?)
+ "tooltip", ZERO_OR_ONE, success_callback,
+ "tooltipText", ZERO_OR_ONE, success_callback,
+ "delayedTooltipText", ZERO_OR_ONE, success_callback
);
return ret;
}
-Button::Button() : text {}, font { nullptr} {}
+Button::Button() : size {}, rotation { 0 } {}
bool Button::_fill_key_map(NodeTools::case_insensitive_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
+ "size", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(size)),
+ "rotation", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(rotation)),
+
+ "format", ZERO_OR_ONE, success_callback, /* Is always left from what I've seen. */
+ "clicksound", ZERO_OR_ONE, success_callback, // TODO - clicksound!!!
+ "parent", ZERO_OR_ONE, success_callback /* Links buttons to a scrollbar, not needed thanks to contextual info. */
);
return ret;
}
@@ -128,7 +166,7 @@ bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_ma
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 }
+ { "left", left }, { "right", right }, { "centre", centre }, { "center", centre }, { "justified", justified }
};
ret &= add_key_map_entries(key_map,
"format", ZERO_OR_ONE, expect_identifier(expect_mapped_string(format_map, assign_variable_callback(format))
@@ -136,18 +174,19 @@ bool AlignedElement::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_ma
return ret;
}
-Text::Text() : text {}, font { nullptr } {}
+Text::Text() : text {}, font { nullptr }, max_size {} {}
bool Text::_fill_key_map(NodeTools::case_insensitive_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_fixed_point(assign_variable_callback(max_size.x)),
- "maxHeight", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_size.y)),
+ "font", ONE_EXACTLY, ui_manager.expect_font_string(assign_variable_callback_pointer(font)),
+ "maxWidth", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.x)),
+ "maxHeight", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(max_size.y)),
"borderSize", ZERO_OR_ONE, success_callback,
"fixedsize", ZERO_OR_ONE, success_callback,
+ "allwaystransparent", ZERO_OR_ONE, success_callback,
// Add warning about redundant key?
"textureFile", ZERO_OR_ONE, success_callback
@@ -155,7 +194,7 @@ bool Text::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManag
return ret;
}
-OverlappingElementsBox::OverlappingElementsBox() : size {} {}
+OverlappingElementsBox::OverlappingElementsBox() : size {}, spacing {} {}
bool OverlappingElementsBox::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
bool ret = AlignedElement::_fill_key_map(key_map, ui_manager);
@@ -166,16 +205,117 @@ bool OverlappingElementsBox::_fill_key_map(NodeTools::case_insensitive_key_map_t
return ret;
}
-ListBox::ListBox() : size {} {}
+ListBox::ListBox() : size {}, offset {}, spacing {}, scrollbar_name {} {}
bool ListBox::_fill_key_map(NodeTools::case_insensitive_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,
+ "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
+ "offset", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(offset)),
+ "spacing", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(spacing)),
+ "scrollbartype", ZERO_OR_ONE, expect_string(assign_variable_callback_string(scrollbar_name)),
+
"backGround", ZERO_OR_ONE, success_callback,
+ "borderSize", ZERO_OR_ONE, success_callback,
+ "horizontal", ZERO_OR_ONE, success_callback,
+ "priority", ZERO_OR_ONE, success_callback,
+ "allwaystransparent", ZERO_OR_ONE, success_callback
+ );
+ return ret;
+}
+
+TextEditBox::TextEditBox() : text {}, font { nullptr }, texture_file {}, size {}, border_size {} {}
+
+bool TextEditBox::_fill_key_map(NodeTools::case_insensitive_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,
+ "text", ONE_EXACTLY, expect_string(assign_variable_callback_string(text), true),
+ "font", ONE_EXACTLY, ui_manager.expect_font_string(assign_variable_callback_pointer(font)),
+ "textureFile", ZERO_OR_ONE, expect_string(assign_variable_callback_string(texture_file), true),
+ "size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
+ "borderSize", ONE_EXACTLY, expect_fvec2(assign_variable_callback(border_size))
+ );
+ return ret;
+}
+
+Scrollbar::Scrollbar()
+ : slider_button_name {}, track_button_name {}, less_button_name{}, more_button_name {}, size {}, border_size {},
+ min_value {}, max_value {}, step_size {}, start_value {}, horizontal { false }, use_range_limit { false },
+ range_limit_min {}, range_limit_max {}, range_limit_min_icon_name {}, range_limit_max_icon_name {} {
+ scrollbar_elements.reserve(4); /* Space for 4 buttons, might need 2 more for range limit icons. */
+}
+
+bool Scrollbar::_fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) {
+ bool ret = Element::_fill_key_map(key_map, ui_manager);
+ const auto add_element = [this](std::unique_ptr<Element>&& element) -> bool {
+ return scrollbar_elements.add_item(std::move(element));
+ };
+ ret &= add_key_map_entries(key_map,
+ "slider", ONE_EXACTLY, expect_string(assign_variable_callback_string(slider_button_name)),
+ "track", ONE_EXACTLY, expect_string(assign_variable_callback_string(track_button_name)),
+ "leftbutton", ONE_EXACTLY, expect_string(assign_variable_callback_string(less_button_name)),
+ "rightbutton", ONE_EXACTLY, expect_string(assign_variable_callback_string(more_button_name)),
"size", ONE_EXACTLY, expect_fvec2(assign_variable_callback(size)),
- "spacing", ZERO_OR_ONE, success_callback,
- "scrollbartype", ZERO_OR_ONE, success_callback, // TODO - implement modable listbox scrollbars
- "borderSize", ZERO_OR_ONE, success_callback
+ "borderSize", ZERO_OR_ONE, expect_fvec2(assign_variable_callback(border_size)),
+ "minValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(min_value)),
+ "maxValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(max_value)),
+ "stepSize", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(step_size)),
+ "startValue", ONE_EXACTLY, expect_fixed_point(assign_variable_callback(start_value)),
+ "horizontal", ONE_EXACTLY, expect_int_bool(assign_variable_callback(horizontal)),
+ "useRangeLimit", ZERO_OR_ONE, expect_bool(assign_variable_callback(use_range_limit)),
+ "rangeLimitMin", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(range_limit_min)),
+ "rangeLimitMax", ZERO_OR_ONE, expect_fixed_point(assign_variable_callback(range_limit_max)),
+ "rangeLimitMinIcon", ZERO_OR_ONE, expect_string(assign_variable_callback_string(range_limit_min_icon_name)),
+ "rangeLimitMaxIcon", ZERO_OR_ONE, expect_string(assign_variable_callback_string(range_limit_max_icon_name)),
+
+ "guiButtonType", ONE_OR_MORE, _expect_instance<Element, Button>(add_element, ui_manager),
+ "iconType", ZERO_OR_MORE, _expect_instance<Element, Icon>(add_element, ui_manager),
+
+ "priority", ZERO_OR_ONE, success_callback
);
return ret;
}
+
+template<std::derived_from<Element> T>
+T const* Scrollbar::get_element(std::string_view name, std::string_view type) const {
+ Element const* element = scrollbar_elements.get_item_by_identifier(name);
+ if (element != nullptr) {
+ T const* cast_element = element->cast_to<T>();
+ if (cast_element != nullptr) {
+ return cast_element;
+ } else {
+ Logger::error(
+ "GUI Scrollbar ", get_name(), " ", type, " element ", name, " has wrong type: ", element->get_type(),
+ " (expected ", T::get_type_static(), ")"
+ );
+ return nullptr;
+ }
+ } else {
+ Logger::error("GUI Scrollbar ", get_name(), " has no ", type, " element named ", name, "!");
+ return nullptr;
+ }
+}
+
+Button const* Scrollbar::get_slider_button() const {
+ return get_element<Button>(slider_button_name, "slider button");
+}
+
+Button const* Scrollbar::get_track_button() const {
+ return get_element<Button>(track_button_name, "track button");
+}
+
+Button const* Scrollbar::get_less_button() const {
+ return get_element<Button>(less_button_name, "less button");
+}
+
+Button const* Scrollbar::get_more_button() const {
+ return get_element<Button>(more_button_name, "more button");
+}
+
+Icon const* Scrollbar::get_range_limit_min_icon() const {
+ return get_element<Icon>(range_limit_min_icon_name, "range limit min icon");
+}
+
+Icon const* Scrollbar::get_range_limit_max_icon() const {
+ return get_element<Icon>(range_limit_max_icon_name, "range limit max icon");
+}
diff --git a/src/openvic-simulation/interface/GUI.hpp b/src/openvic-simulation/interface/GUI.hpp
index 96bb2a2..f044f7d 100644
--- a/src/openvic-simulation/interface/GUI.hpp
+++ b/src/openvic-simulation/interface/GUI.hpp
@@ -8,12 +8,27 @@ namespace OpenVic {
namespace OpenVic::GUI {
class Scene;
+ class Position final : public Named<> {
+ friend class LoadBase;
+
+ fvec2_t PROPERTY(position);
+
+ protected:
+ Position();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map) override;
+
+ public:
+ Position(Position&&) = default;
+ virtual ~Position() = default;
+ };
+
class Element : public Named<UIManager const&> {
friend class Scene;
public:
enum class orientation_t {
- UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, UPPER_RIGHT, CENTER
+ UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, UPPER_RIGHT, CENTER, CENTER_UP, CENTER_DOWN
};
private:
@@ -37,10 +52,13 @@ namespace OpenVic::GUI {
OV_DETAIL_GET_TYPE
};
+ using element_instance_registry_t = NamedInstanceRegistry<Element, UIManager const&>;
+
class Scene : public Named<UIManager const&> {
friend std::unique_ptr<Scene> std::make_unique<Scene>();
- NamedInstanceRegistry<Element, UIManager const&> IDENTIFIER_REGISTRY(scene_element);
+ element_instance_registry_t IDENTIFIER_REGISTRY(scene_element);
+ NamedRegistry<Position> IDENTIFIER_REGISTRY(scene_position);
protected:
Scene() = default;
@@ -62,12 +80,14 @@ namespace OpenVic::GUI {
class Window final : public Element {
friend std::unique_ptr<Window> std::make_unique<Window>();
- NamedInstanceRegistry<Element, UIManager const&> IDENTIFIER_REGISTRY(window_element);
+ element_instance_registry_t IDENTIFIER_REGISTRY(window_element);
+ std::string PROPERTY(background); /* The name of a child button who's sprite is used as the background. */
fvec2_t PROPERTY(size);
bool PROPERTY(moveable);
bool PROPERTY(fullscreen);
- // TODO - background, dontRender, horizontalBorder, verticalBorder
+
+ // TODO - dontRender, horizontalBorder, verticalBorder
protected:
Window();
@@ -86,6 +106,8 @@ namespace OpenVic::GUI {
GFX::Sprite const* PROPERTY(sprite);
GFX::frame_t PROPERTY(frame);
+ fixed_point_t PROPERTY(scale);
+ fixed_point_t PROPERTY(rotation); /* In radians, usually one of 0, PI/2 or -PI/2. */
protected:
Icon();
@@ -101,6 +123,9 @@ namespace OpenVic::GUI {
class BaseButton : public Element {
GFX::Sprite const* PROPERTY(sprite);
+ std::string PROPERTY(text);
+ GFX::Font const* PROPERTY(font);
+
// TODO - shortcut
protected:
@@ -118,8 +143,8 @@ namespace OpenVic::GUI {
class Button final : public BaseButton {
friend std::unique_ptr<Button> std::make_unique<Button>();
- std::string PROPERTY(text);
- GFX::Font const* PROPERTY(font);
+ fvec2_t PROPERTY(size);
+ fixed_point_t PROPERTY(rotation); /* In radians, usually one of 0, PI/2 or -PI/2. */
// TODO - clicksound
@@ -153,7 +178,7 @@ namespace OpenVic::GUI {
class AlignedElement : public Element {
public:
enum class format_t {
- left, centre, right
+ left, centre, right, justified
};
private:
@@ -176,7 +201,7 @@ namespace OpenVic::GUI {
std::string PROPERTY(text);
GFX::Font const* PROPERTY(font);
- fvec2_t PROPERTY(max_size); // maxWidth, maxHeight
+ fvec2_t PROPERTY(max_size); /* Defines keys: maxWidth, maxHeight */
// TODO - borderSize, fixedsize, textureFile
@@ -214,8 +239,11 @@ namespace OpenVic::GUI {
friend std::unique_ptr<ListBox> std::make_unique<ListBox>();
fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(offset);
+ fixed_point_t PROPERTY(spacing);
+ std::string PROPERTY(scrollbar_name); /* In vanilla this is always core's standardlistbox_slider */
- // TODO - backGround, spacing, scrollbartype, borderSize
+ // TODO - backGround, borderSize
protected:
ListBox();
@@ -228,4 +256,72 @@ namespace OpenVic::GUI {
OV_DETAIL_GET_TYPE
};
+
+ class TextEditBox final : public Element {
+ friend std::unique_ptr<TextEditBox> std::make_unique<TextEditBox>();
+
+ std::string PROPERTY(text);
+ GFX::Font const* PROPERTY(font);
+ std::string PROPERTY(texture_file);
+ fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(border_size);
+
+ protected:
+ TextEditBox();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override;
+
+ public:
+ TextEditBox(TextEditBox&&) = default;
+ virtual ~TextEditBox() = default;
+
+ OV_DETAIL_GET_TYPE
+ };
+
+ class Scrollbar final : public Element {
+ friend std::unique_ptr<Scrollbar> std::make_unique<Scrollbar>();
+
+ element_instance_registry_t IDENTIFIER_REGISTRY(scrollbar_element);
+
+ std::string PROPERTY(slider_button_name);
+ std::string PROPERTY(track_button_name);
+ std::string PROPERTY(less_button_name);
+ std::string PROPERTY(more_button_name);
+
+ fvec2_t PROPERTY(size);
+ fvec2_t PROPERTY(border_size);
+ fixed_point_t PROPERTY(min_value);
+ fixed_point_t PROPERTY(max_value);
+ fixed_point_t PROPERTY(step_size);
+ fixed_point_t PROPERTY(start_value);
+ bool PROPERTY_CUSTOM_PREFIX(horizontal, is)
+
+ bool PROPERTY(use_range_limit);
+ fixed_point_t PROPERTY(range_limit_min);
+ fixed_point_t PROPERTY(range_limit_max);
+ std::string PROPERTY(range_limit_min_icon_name);
+ std::string PROPERTY(range_limit_max_icon_name);
+
+ template<std::derived_from<Element> T>
+ T const* get_element(std::string_view name, std::string_view type) const;
+
+ protected:
+ Scrollbar();
+
+ bool _fill_key_map(NodeTools::case_insensitive_key_map_t& key_map, UIManager const& ui_manager) override;
+
+ public:
+ Scrollbar(Scrollbar&&) = default;
+ virtual ~Scrollbar() = default;
+
+ Button const* get_slider_button() const;
+ Button const* get_track_button() const;
+ Button const* get_less_button() const;
+ Button const* get_more_button() const;
+
+ Icon const* get_range_limit_min_icon() const;
+ Icon const* get_range_limit_max_icon() const;
+
+ OV_DETAIL_GET_TYPE
+ };
}
diff --git a/src/openvic-simulation/interface/LoadBase.hpp b/src/openvic-simulation/interface/LoadBase.hpp
index 10b0169..29de165 100644
--- a/src/openvic-simulation/interface/LoadBase.hpp
+++ b/src/openvic-simulation/interface/LoadBase.hpp
@@ -23,6 +23,18 @@ namespace OpenVic {
return ret;
}
+ template<std::derived_from<LoadBase<Context...>> T>
+ static NodeTools::node_callback_t _expect_value(
+ NodeTools::callback_t<T&&> callback, Context... context
+ ) {
+ return [callback, &context...](ast::NodeCPtr node) -> bool {
+ T value {};
+ bool ret = value.load(node, context...);
+ ret &= callback(std::move(value));
+ 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
diff --git a/src/openvic-simulation/interface/UI.cpp b/src/openvic-simulation/interface/UI.cpp
index b977406..2646bb7 100644
--- a/src/openvic-simulation/interface/UI.cpp
+++ b/src/openvic-simulation/interface/UI.cpp
@@ -7,7 +7,9 @@ using namespace OpenVic::NodeTools;
using namespace OpenVic::GFX;
using namespace OpenVic::GUI;
-bool UIManager::add_font(std::string_view identifier, colour_argb_t colour, std::string_view fontname) {
+bool UIManager::add_font(
+ std::string_view identifier, colour_argb_t colour, std::string_view fontname, std::string_view charset, uint32_t height
+) {
if (identifier.empty()) {
Logger::error("Invalid font identifier - empty!");
return false;
@@ -20,23 +22,39 @@ bool UIManager::add_font(std::string_view identifier, colour_argb_t colour, std:
Logger::error("Invalid fontname for font ", identifier, " - empty!");
return false;
}
- return fonts.add_item({ identifier, colour, fontname }, duplicate_warning_callback);
+ return fonts.add_item({ identifier, colour, fontname, charset, height }, duplicate_warning_callback);
}
bool UIManager::_load_font(ast::NodeCPtr node) {
- std::string_view identifier, fontname;
+ std::string_view identifier, fontname, charset;
colour_argb_t colour = colour_argb_t::null();
+ uint32_t height = 0;
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)),
+ "charset", ZERO_OR_ONE, expect_string(assign_variable_callback(charset)),
+ "height", ZERO_OR_ONE, expect_uint(assign_variable_callback(height)),
"colorcodes", ZERO_OR_ONE, success_callback,
"effect", ZERO_OR_ONE, success_callback
)(node);
- ret &= add_font(identifier, colour, fontname);
+ ret &= add_font(identifier, colour, fontname, charset, height);
return ret;
}
+NodeCallback auto UIManager::_load_fonts(std::string_view font_key) {
+ return expect_dictionary_reserve_length(
+ fonts,
+ [this, font_key](std::string_view key, ast::NodeCPtr node) -> bool {
+ if (key != font_key) {
+ Logger::error("Invalid key: \"", key, "\" (expected ", font_key, ")");
+ return false;
+ }
+ return _load_font(node);
+ }
+ );
+}
+
bool UIManager::load_gfx_file(ast::NodeCPtr root) {
return expect_dictionary_keys(
"spriteTypes", ZERO_OR_ONE, Sprite::expect_sprites(
@@ -65,19 +83,10 @@ bool UIManager::load_gfx_file(ast::NodeCPtr root) {
return sprites.add_item(std::move(sprite), duplicate_warning_callback);
}
),
- "bitmapfonts", ZERO_OR_ONE, expect_dictionary_reserve_length(
- fonts,
- [this](std::string_view key, ast::NodeCPtr node) -> bool {
- if (key != "bitmapfont") {
- Logger::error("Invalid bitmapfonts key: ", key);
- return false;
- }
- return _load_font(node);
- }
- ),
+ "bitmapfonts", ZERO_OR_ONE, _load_fonts("bitmapfont"),
+ "fonts", ZERO_OR_ONE, _load_fonts("font"),
"objectTypes", ZERO_OR_ONE, success_callback,
- "lightTypes", ZERO_OR_ONE, success_callback,
- "fonts", ZERO_OR_ONE, success_callback
+ "lightTypes", ZERO_OR_ONE, success_callback
)(root);
}
diff --git a/src/openvic-simulation/interface/UI.hpp b/src/openvic-simulation/interface/UI.hpp
index 286e4f7..c8ffa98 100644
--- a/src/openvic-simulation/interface/UI.hpp
+++ b/src/openvic-simulation/interface/UI.hpp
@@ -10,9 +10,13 @@ namespace OpenVic {
IdentifierRegistry<GFX::Font> IDENTIFIER_REGISTRY(font);
bool _load_font(ast::NodeCPtr node);
+ NodeTools::NodeCallback auto _load_fonts(std::string_view font_key);
public:
- bool add_font(std::string_view identifier, colour_argb_t colour, std::string_view fontname);
+ bool add_font(
+ std::string_view identifier, colour_argb_t colour, std::string_view fontname, std::string_view charset,
+ uint32_t height
+ );
bool load_gfx_file(ast::NodeCPtr root);
bool load_gui_file(std::string_view scene_name, ast::NodeCPtr root);