diff options
Diffstat (limited to 'extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp')
-rw-r--r-- | extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp b/extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp new file mode 100644 index 0000000..ff88781 --- /dev/null +++ b/extension/src/openvic-extension/classes/GUIOverlappingElementsBox.cpp @@ -0,0 +1,177 @@ +#include "GUIOverlappingElementsBox.hpp" + +#include <godot_cpp/variant/utility_functions.hpp> + +#include "openvic-extension/utility/ClassBindings.hpp" +#include "openvic-extension/utility/UITools.hpp" +#include "openvic-extension/utility/Utilities.hpp" + +using namespace OpenVic; +using namespace godot; + +using OpenVic::Utilities::std_view_to_godot_string; + +Error GUIOverlappingElementsBox::_update_child_positions() { + ERR_FAIL_NULL_V(gui_overlapping_elements_box, FAILED); + const int32_t child_count = get_child_count(); + if (child_count <= 0) { + return OK; + } + + const auto _get_child = [this](int32_t index) -> Control* { return Object::cast_to<Control>(get_child(index)); }; + + const float box_width = get_size().x; + const float child_width = _get_child(0)->get_size().x; + + const float max_spacing = box_width / (child_count + 1); + const float default_spacing = child_width + gui_overlapping_elements_box->get_spacing().to_float(); + + const float spacing = std::min(max_spacing, default_spacing); + + const float total_width = spacing * (child_count - 1) + child_width; + + float starting_x = 0.0f; + Error err = OK; + using enum GUI::AlignedElement::format_t; + switch (gui_overlapping_elements_box->get_format()) { + case left: + break; + case centre: + starting_x = (box_width - total_width) / 2; + break; + case right: + starting_x = box_width - total_width; + break; + default: + UtilityFunctions::push_error( + "Invalid GUIOverlappingElementsBox alignment: ", + static_cast<int32_t>(gui_overlapping_elements_box->get_format()) + ); + err = FAILED; + } + + for (int32_t index = 0; index < child_count; ++index) { + _get_child(index)->set_position({ starting_x + spacing * index, 0.0f }); + } + + return err; +} + +void GUIOverlappingElementsBox::_bind_methods() { + OV_BIND_METHOD(GUIOverlappingElementsBox::clear); + OV_BIND_METHOD(GUIOverlappingElementsBox::clear_children); + OV_BIND_METHOD(GUIOverlappingElementsBox::set_child_count, { "new_count" }); + + OV_BIND_METHOD(GUIOverlappingElementsBox::get_gui_overlapping_elements_box_name); + + OV_BIND_METHOD( + GUIOverlappingElementsBox::set_gui_child_element_name, { "gui_child_element_file", "gui_child_element_name" } + ); + OV_BIND_METHOD(GUIOverlappingElementsBox::get_gui_child_element_name); +} + +void GUIOverlappingElementsBox::_notification(int what) { + if (what == NOTIFICATION_SORT_CHILDREN) { + _update_child_positions(); + } +} + +GUIOverlappingElementsBox::GUIOverlappingElementsBox() + : gui_overlapping_elements_box { nullptr }, gui_child_element { nullptr } {} + +void GUIOverlappingElementsBox::clear() { + clear_children(); + gui_child_element = nullptr; + gui_overlapping_elements_box = nullptr; +} + +void GUIOverlappingElementsBox::clear_children() { + set_child_count(0); +} + +Error GUIOverlappingElementsBox::set_child_count(int32_t new_count) { + ERR_FAIL_COND_V_MSG(new_count < 0, FAILED, "Child count must be non-negative"); + int32_t child_count = get_child_count(); + if (child_count == new_count) { + return OK; + } else if (child_count > new_count) { + do { + remove_child(get_child(--child_count)); + } while (child_count > new_count); + return OK; + } else { + ERR_FAIL_NULL_V_MSG( + gui_child_element, FAILED, vformat( + "GUIOverlappingElementsBox child element is null (child_count = %d, new_count = %d)", child_count, new_count + ) + ); + Error err = OK; + const String gui_child_element_name = std_view_to_godot_string(gui_child_element->get_name()) + "_"; + do { + Control* child = nullptr; + const String name = gui_child_element_name + itos(child_count); + if (!UITools::generate_gui_element(gui_child_element, name, child)) { + UtilityFunctions::push_error("Error generating GUIOverlappingElementsBox child element ", name); + err = FAILED; + } + ERR_FAIL_NULL_V_MSG( + child, FAILED, vformat( + "Failed to generate GUIOverlappingElementsBox child element %s (child_count = %d, new_count = %d)", + name, child_count, new_count + ) + ); + add_child(child); + child_count++; + } while (child_count < new_count); + return err; + } +} + +Error GUIOverlappingElementsBox::set_gui_overlapping_elements_box( + GUI::OverlappingElementsBox const* new_gui_overlapping_elements_box +) { + if (gui_overlapping_elements_box == new_gui_overlapping_elements_box) { + return OK; + } + gui_overlapping_elements_box = new_gui_overlapping_elements_box; + if (gui_overlapping_elements_box == nullptr) { + return OK; + } + + set_custom_minimum_size(Utilities::to_godot_fvec2(gui_overlapping_elements_box->get_size())); + queue_sort(); + return OK; +} + +String GUIOverlappingElementsBox::get_gui_overlapping_elements_box_name() const { + return gui_overlapping_elements_box != nullptr ? std_view_to_godot_string(gui_overlapping_elements_box->get_name()) : String {}; +} + +Error GUIOverlappingElementsBox::set_gui_child_element(GUI::Element const* new_gui_child_element) { + clear_children(); + gui_child_element = new_gui_child_element; + return OK; +} + +Error GUIOverlappingElementsBox::set_gui_child_element_name( + String const& gui_child_element_file, String const& gui_child_element_name +) { + if (gui_child_element_file.is_empty() && gui_child_element_name.is_empty()) { + return set_gui_child_element(nullptr); + } + ERR_FAIL_COND_V_MSG( + gui_child_element_file.is_empty(), FAILED, + vformat("GUI child element file name is empty but element name is not: %s", gui_child_element_name) + ); + ERR_FAIL_COND_V_MSG( + gui_child_element_name.is_empty(), FAILED, + vformat("GUI child element name is empty but file name is not: %s", gui_child_element_file) + ); + GUI::Element const* const new_gui_child_element = UITools::get_gui_element(gui_child_element_file, gui_child_element_name); + ERR_FAIL_NULL_V(new_gui_child_element, FAILED); + return set_gui_child_element(new_gui_child_element); +} + +String GUIOverlappingElementsBox::get_gui_child_element_name() const { + return gui_child_element != nullptr ? std_view_to_godot_string(gui_child_element->get_name()) : String {}; +} |