#include "UITools.hpp" #include #include #include #include #include #include #include #include #include #include #include "openvic-extension/classes/GFXButtonStateTexture.hpp" #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 ordered_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) ); GFX::ProgressBar const* progress_bar = icon.get_sprite()->cast_to(); Ref back_texture; if (!progress_bar->get_back_texture_file().empty()) { const StringName back_texture_file = std_view_to_godot_string_name(progress_bar->get_back_texture_file()); back_texture = args.asset_manager.get_texture(back_texture_file); if (back_texture.is_null()) { UtilityFunctions::push_error( "Failed to load progress bar sprite back texture ", back_texture_file, " for GUI icon ", icon_name ); ret = false; } } if (back_texture.is_null()) { const Color back_colour = Utilities::to_godot_color(progress_bar->get_back_colour()); back_texture = Utilities::make_solid_colour_texture( back_colour, progress_bar->get_size().x, progress_bar->get_size().y ); if (back_texture.is_null()) { UtilityFunctions::push_error( "Failed to generate progress bar sprite ", back_colour, " back texture for GUI icon ", icon_name ); ret = false; } } if (back_texture.is_valid()) { godot_progress_bar->set_under_texture(back_texture); } else { UtilityFunctions::push_error( "Failed to create and set progress bar sprite back texture for GUI icon ", icon_name ); ret = false; } Ref progress_texture; if (!progress_bar->get_progress_texture_file().empty()) { const StringName progress_texture_file = std_view_to_godot_string_name(progress_bar->get_progress_texture_file()); progress_texture = args.asset_manager.get_texture(progress_texture_file); if (progress_texture.is_null()) { UtilityFunctions::push_error( "Failed to load progress bar sprite progress texture ", progress_texture_file, " for GUI icon ", icon_name ); ret = false; } } if (progress_texture.is_null()) { const Color progress_colour = Utilities::to_godot_color(progress_bar->get_progress_colour()); progress_texture = Utilities::make_solid_colour_texture( progress_colour, progress_bar->get_size().x, progress_bar->get_size().y ); if (progress_texture.is_null()) { UtilityFunctions::push_error( "Failed to generate progress bar sprite ", progress_colour, " progress texture for GUI icon ", icon_name ); ret = false; } } if (progress_texture.is_valid()) { godot_progress_bar->set_progress_texture(progress_texture); } else { UtilityFunctions::push_error( "Failed to create and set progress bar sprite progress texture for GUI icon ", icon_name ); ret = false; } // TODO - work out why progress bar is missing bottom border pixel (e.g. province building expansion bar) godot_progress_bar->set_custom_minimum_size(Utilities::to_godot_fvec2(static_cast(progress_bar->get_size()))); 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