From 4e9764ee29fb7b453862835d5aa3a081b0f9a269 Mon Sep 17 00:00:00 2001 From: hop311 Date: Mon, 18 Dec 2023 23:38:54 +0000 Subject: Back to UI Work - UIAdapter -> UITools with cleaner API - GUIOverlappingElementsBox (for core and modifier icons) - Improved GUINode API - Province building slots - TypeHints for files in the GameSession folder - Incorporate SIM strong colour types --- .../openvic-extension/classes/GFXIconTexture.cpp | 9 +- .../openvic-extension/classes/GFXIconTexture.hpp | 4 +- .../classes/GFXMaskedFlagTexture.cpp | 31 +++- .../classes/GFXMaskedFlagTexture.hpp | 11 +- .../classes/GFXPieChartTexture.cpp | 40 ++--- .../classes/GFXPieChartTexture.hpp | 41 ++++- .../src/openvic-extension/classes/GUINode.cpp | 173 ++++++++++---------- .../src/openvic-extension/classes/GUINode.hpp | 50 +++--- .../classes/GUIOverlappingElementsBox.cpp | 177 +++++++++++++++++++++ .../classes/GUIOverlappingElementsBox.hpp | 51 ++++++ 10 files changed, 439 insertions(+), 148 deletions(-) create mode 100644 extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp create mode 100644 extension/src/openvic-extension/classes/GUIOverlappingElementsBox.hpp (limited to 'extension/src/openvic-extension/classes') diff --git a/extension/src/openvic-extension/classes/GFXIconTexture.cpp b/extension/src/openvic-extension/classes/GFXIconTexture.cpp index 57c5d50..895bf6b 100644 --- a/extension/src/openvic-extension/classes/GFXIconTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXIconTexture.cpp @@ -5,6 +5,7 @@ #include "openvic-extension/singletons/AssetManager.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/ClassBindings.hpp" +#include "openvic-extension/utility/UITools.hpp" #include "openvic-extension/utility/Utilities.hpp" using namespace godot; @@ -71,12 +72,8 @@ Error GFXIconTexture::set_gfx_texture_sprite_name(String const& gfx_texture_spri if (gfx_texture_sprite_name.is_empty()) { return set_gfx_texture_sprite(nullptr); } - GameSingleton* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, FAILED); - GFX::Sprite const* sprite = game_singleton->get_game_manager().get_ui_manager().get_sprite_by_identifier( - godot_to_std_string(gfx_texture_sprite_name) - ); - ERR_FAIL_NULL_V_MSG(sprite, FAILED, vformat("GFX sprite not found: %s", gfx_texture_sprite_name)); + GFX::Sprite const* sprite = UITools::get_gfx_sprite(gfx_texture_sprite_name); + ERR_FAIL_NULL_V(sprite, FAILED); GFX::TextureSprite const* new_texture_sprite = sprite->cast_to(); ERR_FAIL_NULL_V_MSG( new_texture_sprite, FAILED, vformat( diff --git a/extension/src/openvic-extension/classes/GFXIconTexture.hpp b/extension/src/openvic-extension/classes/GFXIconTexture.hpp index 3ed5b3e..176d855 100644 --- a/extension/src/openvic-extension/classes/GFXIconTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXIconTexture.hpp @@ -35,12 +35,12 @@ namespace OpenVic { ); /* Search for a GFX::TextureSprite with the specfied name and, - * if successful, call set_gfx_texture_sprite to set it and its icon */ + * if successful, call set_gfx_texture_sprite to set it and its icon. */ godot::Error set_gfx_texture_sprite_name( godot::String const& gfx_texture_sprite_name, GFX::frame_t icon = GFX::NO_FRAMES ); - /* Return the name of the GFX::TextureSprite, or an empty String if it's null */ + /* Return the name of the GFX::TextureSprite, or an empty String if it's null. */ godot::String get_gfx_texture_sprite_name() const; /* Set icon_index to a value between one and icon_count (inclusive), and update the AtlasTexture's region diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp index 3636855..0ed7755 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.cpp @@ -1,10 +1,9 @@ #include "GFXMaskedFlagTexture.hpp" -#include - #include "openvic-extension/singletons/AssetManager.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/ClassBindings.hpp" +#include "openvic-extension/utility/UITools.hpp" #include "openvic-extension/utility/Utilities.hpp" using namespace godot; @@ -66,6 +65,7 @@ void GFXMaskedFlagTexture::_bind_methods() { OV_BIND_METHOD(GFXMaskedFlagTexture::get_gfx_masked_flag_name); OV_BIND_METHOD(GFXMaskedFlagTexture::set_flag_country_name_and_type, { "new_flag_country_name", "new_flag_type" }); + OV_BIND_METHOD(GFXMaskedFlagTexture::set_flag_country_name, { "new_flag_country_name" }); OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_country_name); OV_BIND_METHOD(GFXMaskedFlagTexture::get_flag_type); } @@ -123,12 +123,8 @@ Error GFXMaskedFlagTexture::set_gfx_masked_flag_name(String const& gfx_masked_fl if (gfx_masked_flag_name.is_empty()) { return set_gfx_masked_flag(nullptr); } - GameSingleton* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, FAILED); - GFX::Sprite const* sprite = game_singleton->get_game_manager().get_ui_manager().get_sprite_by_identifier( - godot_to_std_string(gfx_masked_flag_name) - ); - ERR_FAIL_NULL_V_MSG(sprite, FAILED, vformat("GFX sprite not found: %s", gfx_masked_flag_name)); + GFX::Sprite const* sprite = UITools::get_gfx_sprite(gfx_masked_flag_name); + ERR_FAIL_NULL_V(sprite, FAILED); GFX::MaskedFlag const* new_masked_flag = sprite->cast_to(); ERR_FAIL_NULL_V_MSG( new_masked_flag, FAILED, vformat( @@ -158,6 +154,7 @@ Error GFXMaskedFlagTexture::set_flag_country_and_type(Country const* new_flag_co flag_type = new_flag_type; flag_image = new_flag_image; } else { + // TODO - use REB flag as default/error flag flag_country = nullptr; flag_type = String {}; flag_image.unref(); @@ -178,6 +175,24 @@ Error GFXMaskedFlagTexture::set_flag_country_name_and_type(String const& new_fla return set_flag_country_and_type(new_flag_country, new_flag_type); } +Error GFXMaskedFlagTexture::set_flag_country(Country const* new_flag_country) { + // TODO - get country's current flag type from the game state + return set_flag_country_and_type( new_flag_country, {}); +} + +Error GFXMaskedFlagTexture::set_flag_country_name(String const& new_flag_country_name) { + if (new_flag_country_name.is_empty()) { + return set_flag_country(nullptr); + } + GameSingleton* game_singleton = GameSingleton::get_singleton(); + ERR_FAIL_NULL_V(game_singleton, FAILED); + Country const* new_flag_country = game_singleton->get_game_manager().get_country_manager().get_country_by_identifier( + godot_to_std_string(new_flag_country_name) + ); + ERR_FAIL_NULL_V_MSG(new_flag_country, FAILED, vformat("Country not found: %s", new_flag_country_name)); + return set_flag_country(new_flag_country); +} + String GFXMaskedFlagTexture::get_flag_country_name() const { return flag_country != nullptr ? std_view_to_godot_string(flag_country->get_identifier()) : String {}; } diff --git a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp index be3b15a..f71a1d7 100644 --- a/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXMaskedFlagTexture.hpp @@ -37,7 +37,7 @@ namespace OpenVic { /* Search for a GFX::MaskedFlag with the specfied name and, if successful, set it using set_gfx_masked_flag. */ godot::Error set_gfx_masked_flag_name(godot::String const& gfx_masked_flag_name); - /* Return the name of the GFX::MaskedFlag, or an empty String if it's null */ + /* Return the name of the GFX::MaskedFlag, or an empty String if it's null. */ godot::String get_gfx_masked_flag_name() const; /* Set flag_country and flag_type and update the combined image to use that flag, or no flag if it doesn't exist. */ @@ -49,7 +49,14 @@ namespace OpenVic { godot::String const& new_flag_country_name, godot::StringName const& new_flag_type ); - /* Return the name of the selected flag's country, or an empty String if it's null */ + /* Look up the specified country's current flag type, then call set_flag_country_and_type + * with the country and its flag type as arguments. */ + godot::Error set_flag_country(Country const* new_flag_country); + + /* Look up the country with the specified identifier, then call set_flag_country with the country its argument. */ + godot::Error set_flag_country_name(godot::String const& new_flag_country_name); + + /* Return the name of the selected flag's country, or an empty String if it's null. */ godot::String get_flag_country_name() const; }; } diff --git a/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp b/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp index 6fe2fe0..e1bffc5 100644 --- a/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp +++ b/extension/src/openvic-extension/classes/GFXPieChartTexture.cpp @@ -1,11 +1,9 @@ #include "GFXPieChartTexture.hpp" -#include - #include "openvic-extension/singletons/AssetManager.hpp" #include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/ClassBindings.hpp" -#include "openvic-extension/utility/Utilities.hpp" +#include "openvic-extension/utility/UITools.hpp" using namespace godot; using namespace OpenVic; @@ -14,14 +12,14 @@ using OpenVic::Utilities::godot_to_std_string; using OpenVic::Utilities::std_view_to_godot_string; using OpenVic::Utilities::std_view_to_godot_string_name; -#define PI std::numbers::pi_v +static constexpr float PI = std::numbers::pi_v; Error GFXPieChartTexture::_generate_pie_chart_image() { ERR_FAIL_NULL_V(gfx_pie_chart, FAILED); - if (gfx_pie_chart->get_size() <= 0) { - UtilityFunctions::push_error("Invalid GFX::PieChart size for GFXPieChartTexture - ", gfx_pie_chart->get_size()); - return FAILED; - } + ERR_FAIL_COND_V_MSG( + gfx_pie_chart->get_size() <= 0, FAILED, + vformat("Invalid GFX::PieChart size for GFXPieChartTexture - %d", gfx_pie_chart->get_size()) + ); const int32_t pie_chart_size = 2 * gfx_pie_chart->get_size(); bool can_update = true; if ( @@ -75,7 +73,7 @@ Error GFXPieChartTexture::_generate_pie_chart_image() { return OK; } -Error GFXPieChartTexture::set_slices(Array const& new_slices) { +Error GFXPieChartTexture::set_slices_array(TypedArray const& new_slices) { static const StringName colour_key = "colour"; static const StringName weight_key = "weight"; @@ -83,15 +81,11 @@ Error GFXPieChartTexture::set_slices(Array const& new_slices) { total_weight = 0.0f; for (int32_t i = 0; i < new_slices.size(); ++i) { Dictionary const& slice_dict = new_slices[i]; - if (!slice_dict.has(colour_key) || !slice_dict.has(weight_key)) { - UtilityFunctions::push_error("Invalid slice keys at index ", i, " - ", slice_dict); - continue; - } + ERR_CONTINUE_MSG( + !slice_dict.has(colour_key) || !slice_dict.has(weight_key), vformat("Invalid slice keys at index %d", i) + ); const slice_t slice = std::make_pair(slice_dict[colour_key], slice_dict[weight_key]); - if (slice.second <= 0.0f) { - UtilityFunctions::push_error("Invalid slice weight at index ", i, " - ", slice.second); - continue; - } + ERR_CONTINUE_MSG(slice.second <= 0.0f, vformat("Invalid slice values at index %d", i)); total_weight += slice.second; slices.emplace_back(std::move(slice)); } @@ -104,10 +98,10 @@ void GFXPieChartTexture::_bind_methods() { OV_BIND_METHOD(GFXPieChartTexture::set_gfx_pie_chart_name, { "gfx_pie_chart_name" }); OV_BIND_METHOD(GFXPieChartTexture::get_gfx_pie_chart_name); - OV_BIND_METHOD(GFXPieChartTexture::set_slices, { "new_slices" }); + OV_BIND_METHOD(GFXPieChartTexture::set_slices_array, { "new_slices" }); } -GFXPieChartTexture::GFXPieChartTexture() : total_weight { 0.0f } {} +GFXPieChartTexture::GFXPieChartTexture() : gfx_pie_chart { nullptr }, total_weight { 0.0f } {} Ref GFXPieChartTexture::make_gfx_pie_chart_texture(GFX::PieChart const* gfx_pie_chart) { Ref pie_chart_texture; @@ -146,12 +140,8 @@ Error GFXPieChartTexture::set_gfx_pie_chart_name(String const& gfx_pie_chart_nam if (gfx_pie_chart_name.is_empty()) { return set_gfx_pie_chart(nullptr); } - GameSingleton* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, FAILED); - GFX::Sprite const* sprite = game_singleton->get_game_manager().get_ui_manager().get_sprite_by_identifier( - godot_to_std_string(gfx_pie_chart_name) - ); - ERR_FAIL_NULL_V_MSG(sprite, FAILED, vformat("GFX sprite not found: %s", gfx_pie_chart_name)); + GFX::Sprite const* sprite = UITools::get_gfx_sprite(gfx_pie_chart_name); + ERR_FAIL_NULL_V(sprite, FAILED); GFX::PieChart const* new_pie_chart = sprite->cast_to(); ERR_FAIL_NULL_V_MSG( new_pie_chart, FAILED, vformat( diff --git a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp index 315b00e..ad8e751 100644 --- a/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp +++ b/extension/src/openvic-extension/classes/GFXPieChartTexture.hpp @@ -4,6 +4,8 @@ #include +#include "openvic-extension/utility/Utilities.hpp" + namespace OpenVic { class GFXPieChartTexture : public godot::ImageTexture { GDCLASS(GFXPieChartTexture, godot::ImageTexture) @@ -23,11 +25,40 @@ namespace OpenVic { public: GFXPieChartTexture(); - /* Set slices given new_slices, an Array of Dictionaries, each with the following keys: + /* Set slices given an Array of Dictionaries, each with the following key-value entries: * - colour: Color - * - weight: float - */ - godot::Error set_slices(godot::Array const& new_slices); + * - weight: float */ + godot::Error set_slices_array(godot::TypedArray const& new_slices); + + /* Generate slice data from a distribution of HasIdentifierAndColour derived objects, sorted by their weight. + * The resulting Array of Dictionaries can be used as an argument for set_slices_array. */ + template T> + static godot::TypedArray distribution_to_slices_array(fixed_point_map_t const& dist) { + using entry_t = std::pair; + std::vector sorted_dist; + sorted_dist.reserve(dist.size()); + for (entry_t const& entry : dist) { + ERR_CONTINUE_MSG( + entry.first == nullptr, godot::vformat("Null distribution key with value %f", entry.second.to_float()) + ); + sorted_dist.push_back(entry); + } + std::sort(sorted_dist.begin(), sorted_dist.end(), [](entry_t const& lhs, entry_t const& rhs) -> bool { + return lhs.second < rhs.second; + }); + static const godot::StringName identifier_key = "identifier"; + static const godot::StringName colour_key = "colour"; + static const godot::StringName weight_key = "weight"; + godot::TypedArray array; + for (auto const& [key, val] : sorted_dist) { + godot::Dictionary sub_dict; + sub_dict[identifier_key] = Utilities::std_view_to_godot_string(key->get_identifier()); + sub_dict[colour_key] = Utilities::to_godot_color(key->get_colour()); + sub_dict[weight_key] = val.to_float(); + array.push_back(sub_dict); + } + return array; + } /* Create a GFXPieChartTexture using the specific GFX::PieChart. * Returns nullptr if setting gfx_pie_chart fails. */ @@ -43,7 +74,7 @@ namespace OpenVic { /* Search for a GFX::PieChart with the specfied name and, if successful, set it using set_gfx_pie_chart. */ godot::Error set_gfx_pie_chart_name(godot::String const& gfx_pie_chart_name); - /* Return the name of the GFX::PieChart, or an empty String if it's null */ + /* Return the name of the GFX::PieChart, or an empty String if it's null. */ godot::String get_gfx_pie_chart_name() const; }; } diff --git a/extension/src/openvic-extension/classes/GUINode.cpp b/extension/src/openvic-extension/classes/GUINode.cpp index 1d55c54..043f65d 100644 --- a/extension/src/openvic-extension/classes/GUINode.cpp +++ b/extension/src/openvic-extension/classes/GUINode.cpp @@ -3,10 +3,8 @@ #include #include -#include "openvic-extension/UIAdapter.hpp" -#include "openvic-extension/singletons/AssetManager.hpp" -#include "openvic-extension/singletons/GameSingleton.hpp" #include "openvic-extension/utility/ClassBindings.hpp" +#include "openvic-extension/utility/UITools.hpp" #include "openvic-extension/utility/Utilities.hpp" using namespace godot; @@ -15,33 +13,58 @@ using namespace OpenVic; using OpenVic::Utilities::godot_to_std_string; using OpenVic::Utilities::std_view_to_godot_string; +#define APPLY_TO_CHILD_TYPES(F) \ + F(Button, button) \ + F(CheckBox, check_box) \ + F(Label, label) \ + F(Panel, panel) \ + F(TextureProgressBar, progress_bar) \ + F(TextureRect, texture_rect) \ + F(GUIOverlappingElementsBox, gui_overlapping_elements_box) + +#define APPLY_TO_TEXTURE_TYPES(F) \ + F(GFXIconTexture, gfx_icon_texture) \ + F(GFXMaskedFlagTexture, gfx_masked_flag_texture) \ + F(GFXPieChartTexture, gfx_pie_chart_texture) + void GUINode::_bind_methods() { + OV_BIND_SMETHOD(generate_gui_element, { "gui_file", "gui_element", "name" }, DEFVAL(String {})); OV_BIND_METHOD(GUINode::add_gui_element, { "gui_file", "gui_element", "name" }, DEFVAL(String {})); - OV_BIND_METHOD(GUINode::get_button_node, { "path" }); - OV_BIND_METHOD(GUINode::get_check_box_node, { "path" }); - OV_BIND_METHOD(GUINode::get_label_node, { "path" }); - OV_BIND_METHOD(GUINode::get_panel_node, { "path" }); - OV_BIND_METHOD(GUINode::get_progress_bar_node, { "path" }); - OV_BIND_METHOD(GUINode::get_texture_rect_node, { "path" }); +#define GET_BINDINGS(type, name) \ + OV_BIND_SMETHOD(get_##name##_from_node, { "node" }); \ + OV_BIND_METHOD(GUINode::get_##name##_from_nodepath, { "path" }); + + APPLY_TO_CHILD_TYPES(GET_BINDINGS) + + OV_BIND_SMETHOD(get_texture_from_node, { "node" }); + OV_BIND_METHOD(GUINode::get_texture_from_nodepath, { "path" }); + + APPLY_TO_TEXTURE_TYPES(GET_BINDINGS) - OV_BIND_METHOD(GUINode::get_texture_from_node, { "path" }); - OV_BIND_METHOD(GUINode::get_gfx_icon_texture_from_node, { "path" }); - OV_BIND_METHOD(GUINode::get_gfx_masked_flag_texture_from_node, { "path" }); - OV_BIND_METHOD(GUINode::get_gfx_pie_chart_texture_from_node, { "path" }); +#undef GET_BINDINGS OV_BIND_METHOD(GUINode::hide_node, { "path" }); OV_BIND_METHOD(GUINode::hide_nodes, { "paths" }); } -Error GUINode::_add_gui_element(GUI::Element const* element, String const& name) { - ERR_FAIL_NULL_V(element, FAILED); - AssetManager* asset_manager = AssetManager::get_singleton(); - ERR_FAIL_NULL_V(asset_manager, FAILED); +GUINode::GUINode() { + set_mouse_filter(MOUSE_FILTER_IGNORE); +} + +Control* GUINode::generate_gui_element(String const& gui_file, String const& gui_element, String const& name) { + Control* result = nullptr; + if (!UITools::generate_gui_element(gui_file, gui_element, name, result)) { + UtilityFunctions::push_error("Error generating GUI element ", gui_element, " from GUI file ", gui_file); + } + return result; +} + +Error GUINode::add_gui_element(String const& gui_file, String const& gui_element, String const& name) { Error err = OK; Control* result = nullptr; - if (!GodotGUIBuilder::generate_element(element, name, *asset_manager, result)) { - UtilityFunctions::push_error("Failed to generate GUI element ", std_view_to_godot_string(element->get_name())); + if (!UITools::generate_gui_element(gui_file, gui_element, name, result)) { + UtilityFunctions::push_error("Error generating GUI element ", gui_element, " from GUI file ", gui_file); err = FAILED; } if (result != nullptr) { @@ -50,107 +73,95 @@ Error GUINode::_add_gui_element(GUI::Element const* element, String const& name) return err; } -Error GUINode::add_gui_element(String const& gui_file, String const& gui_element, String const& name) { - GameSingleton const* game_singleton = GameSingleton::get_singleton(); - ERR_FAIL_NULL_V(game_singleton, FAILED); - GUI::Scene const* scene = - game_singleton->get_game_manager().get_ui_manager().get_scene_by_identifier(godot_to_std_string(gui_file)); - ERR_FAIL_NULL_V_MSG(scene, FAILED, vformat("Failed to find GUI file %s", gui_file)); - GUI::Element const* element = scene->get_scene_element_by_identifier(godot_to_std_string(gui_element)); - ERR_FAIL_NULL_V_MSG(element, FAILED, vformat("Failed to find GUI element %s in GUI file %s", gui_element, gui_file)); - return _add_gui_element(element, name); -} - template T> -T* GUINode::_get_cast_node(NodePath const& path) const { - Node* node = get_node_or_null(path); - ERR_FAIL_NULL_V_MSG(node, nullptr, vformat("Failed to find node %s", path)); +static T* _cast_node(Node* node) { + ERR_FAIL_NULL_V(node, nullptr); T* result = Object::cast_to(node); - ERR_FAIL_NULL_V_MSG(result, nullptr, vformat("Failed to cast node %s to type %s", path, T::get_class_static())); + ERR_FAIL_NULL_V_MSG( + result, nullptr, + vformat("Failed to cast node %s from type %s to %s", node->get_name(), node->get_class(), T::get_class_static()) + ); return result; } -Button* GUINode::get_button_node(NodePath const& path) const { - return _get_cast_node