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 --- .../src/openvic-extension/utility/UITools.cpp | 450 +++++++++++++++++++++ .../src/openvic-extension/utility/UITools.hpp | 18 + .../src/openvic-extension/utility/Utilities.cpp | 15 + .../src/openvic-extension/utility/Utilities.hpp | 20 +- 4 files changed, 496 insertions(+), 7 deletions(-) create mode 100644 extension/src/openvic-extension/utility/UITools.cpp create mode 100644 extension/src/openvic-extension/utility/UITools.hpp (limited to 'extension/src/openvic-extension/utility') diff --git a/extension/src/openvic-extension/utility/UITools.cpp b/extension/src/openvic-extension/utility/UITools.cpp new file mode 100644 index 0000000..cba65a4 --- /dev/null +++ b/extension/src/openvic-extension/utility/UITools.cpp @@ -0,0 +1,450 @@ +#include "UITools.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openvic-extension/classes/GFXIconTexture.hpp" +#include "openvic-extension/classes/GFXMaskedFlagTexture.hpp" +#include "openvic-extension/classes/GFXPieChartTexture.hpp" +#include "openvic-extension/classes/GUIOverlappingElementsBox.hpp" +#include "openvic-extension/singletons/AssetManager.hpp" +#include "openvic-extension/singletons/GameSingleton.hpp" +#include "openvic-extension/utility/Utilities.hpp" + +using namespace godot; +using namespace OpenVic; + +using OpenVic::Utilities::godot_to_std_string; +using OpenVic::Utilities::std_view_to_godot_string; +using OpenVic::Utilities::std_view_to_godot_string_name; + +GFX::Sprite const* UITools::get_gfx_sprite(godot::String const& gfx_sprite) { + GameSingleton* game_singleton = GameSingleton::get_singleton(); + ERR_FAIL_NULL_V(game_singleton, nullptr); + GFX::Sprite const* sprite = game_singleton->get_game_manager().get_ui_manager().get_sprite_by_identifier( + godot_to_std_string(gfx_sprite) + ); + ERR_FAIL_NULL_V_MSG(sprite, nullptr, vformat("GFX sprite not found: %s", gfx_sprite)); + return sprite; +} + +GUI::Element const* UITools::get_gui_element(godot::String const& gui_file, godot::String const& gui_element) { + GameSingleton const* game_singleton = GameSingleton::get_singleton(); + ERR_FAIL_NULL_V(game_singleton, nullptr); + 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, nullptr, 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, nullptr, vformat("Failed to find GUI element %s in GUI file %s", gui_element, gui_file)); + return element; +} + +/* GUI::Element tree -> godot::Control tree conversion code below: */ + +namespace OpenVic { + struct generate_gui_args_t { + GUI::Element const& element; + godot::String const& name; + AssetManager& asset_manager; + godot::Control*& result; + + constexpr generate_gui_args_t( + GUI::Element const& new_element, godot::String const& new_name, AssetManager& new_asset_manager, + godot::Control*& new_result + ) : element { new_element }, name { new_name }, asset_manager { new_asset_manager }, result { new_result } {} + }; +} + +template T> +static T* new_control(GUI::Element const& element, String const& name) { + T* node = memnew(T); + ERR_FAIL_NULL_V(node, nullptr); + + using enum GUI::Element::orientation_t; + using enum Control::LayoutPreset; + static const std::map orientation_map { + { UPPER_LEFT, PRESET_TOP_LEFT }, { LOWER_LEFT, PRESET_BOTTOM_LEFT }, + { LOWER_RIGHT, PRESET_BOTTOM_RIGHT }, { UPPER_RIGHT, PRESET_TOP_RIGHT }, + { CENTER, PRESET_CENTER } + }; + + if (name.is_empty()) { + node->set_name(std_view_to_godot_string(element.get_name())); + } else { + node->set_name(name); + } + + const decltype(orientation_map)::const_iterator it = orientation_map.find(element.get_orientation()); + if (it != orientation_map.end()) { + node->set_anchors_and_offsets_preset(it->second); + } else { + UtilityFunctions::push_error("Invalid orientation for GUI element ", + std_view_to_godot_string(element.get_name())); + } + node->set_position(Utilities::to_godot_fvec2(element.get_position())); + node->set_h_size_flags(Control::SizeFlags::SIZE_SHRINK_BEGIN); + node->set_v_size_flags(Control::SizeFlags::SIZE_SHRINK_BEGIN); + node->set_focus_mode(Control::FOCUS_NONE); + + return node; +} + +static bool generate_icon(generate_gui_args_t&& args) { + GUI::Icon const& icon = static_cast(args.element); + + const String icon_name = std_view_to_godot_string(icon.get_name()); + + /* Change to use sprite type to choose Godot node type! */ + bool ret = true; + if (icon.get_sprite() != nullptr) { + if (icon.get_sprite()->is_type()) { + TextureRect* godot_texture_rect = new_control(icon, args.name); + ERR_FAIL_NULL_V_MSG(godot_texture_rect, false, vformat("Failed to create TextureRect for GUI icon %s", icon_name)); + + GFX::TextureSprite const* texture_sprite = icon.get_sprite()->cast_to(); + Ref texture = GFXIconTexture::make_gfx_icon_texture(texture_sprite, icon.get_frame()); + if (texture.is_valid()) { + godot_texture_rect->set_texture(texture); + } else { + UtilityFunctions::push_error("Failed to make GFXIconTexture for GUI icon ", icon_name); + ret = false; + } + + args.result = godot_texture_rect; + } else if (icon.get_sprite()->is_type()) { + TextureRect* godot_texture_rect = new_control(icon, args.name); + ERR_FAIL_NULL_V_MSG(godot_texture_rect, false, vformat("Failed to create TextureRect for GUI icon %s", icon_name)); + + GFX::MaskedFlag const* masked_flag = icon.get_sprite()->cast_to(); + Ref texture = GFXMaskedFlagTexture::make_gfx_masked_flag_texture(masked_flag); + if (texture.is_valid()) { + godot_texture_rect->set_texture(texture); + } else { + UtilityFunctions::push_error("Failed to make GFXMaskedFlagTexture for GUI icon ", icon_name); + ret = false; + } + + args.result = godot_texture_rect; + } else if (icon.get_sprite()->is_type()) { + TextureProgressBar* godot_progress_bar = new_control(icon, args.name); + ERR_FAIL_NULL_V_MSG( + godot_progress_bar, false, vformat("Failed to create TextureProgressBar for GUI icon %s", icon_name) + ); + + const StringName back_texture_file = + std_view_to_godot_string_name(icon.get_sprite()->cast_to()->get_back_texture_file()); + const Ref back_texture = args.asset_manager.get_texture(back_texture_file); + if (back_texture.is_valid()) { + godot_progress_bar->set_under_texture(back_texture); + } else { + UtilityFunctions::push_error("Failed to load progress bar base sprite ", back_texture_file, " for GUI icon ", icon_name); + ret = false; + } + + const StringName progress_texture_file = + std_view_to_godot_string_name(icon.get_sprite()->cast_to()->get_progress_texture_file()); + const Ref progress_texture = args.asset_manager.get_texture(progress_texture_file); + if (progress_texture.is_valid()) { + godot_progress_bar->set_progress_texture(progress_texture); + } else { + UtilityFunctions::push_error( + "Failed to load progress bar base sprite ", progress_texture_file, " for GUI icon ", icon_name + ); + ret = false; + } + + args.result = godot_progress_bar; + } else if (icon.get_sprite()->is_type()) { + TextureRect* godot_texture_rect = new_control(icon, args.name); + ERR_FAIL_NULL_V_MSG(godot_texture_rect, false, vformat("Failed to create TextureRect for GUI icon %s", icon_name)); + + GFX::PieChart const* pie_chart = icon.get_sprite()->cast_to(); + Ref texture = GFXPieChartTexture::make_gfx_pie_chart_texture(pie_chart); + if (texture.is_valid()) { + godot_texture_rect->set_texture(texture); + // TODO - work out why this is needed + Vector2 pos = godot_texture_rect->get_position(); + pos.x -= texture->get_width() / 2; + godot_texture_rect->set_position(pos); + } else { + UtilityFunctions::push_error("Failed to make GFXPieChartTexture for GUI icon ", icon_name); + ret = false; + } + + args.result = godot_texture_rect; + } else if (icon.get_sprite()->is_type()) { + + } else { + UtilityFunctions::push_error("Invalid sprite type ", std_view_to_godot_string(icon.get_sprite()->get_type()), + " for GUI icon ", icon_name); + ret = false; + } + } else { + UtilityFunctions::push_error("Null sprite for GUI icon ", icon_name); + ret = false; + } + return ret; +} + +static bool generate_button(generate_gui_args_t&& args) { + GUI::Button const& button = static_cast(args.element); + + // TODO - shortcut, sprite, text + const String button_name = std_view_to_godot_string(button.get_name()); + + Button* godot_button = new_control