From e6ee1f0c0fb8f3301899f9d2b1342010c675fee0 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 20 Oct 2023 13:44:43 +0200 Subject: [PATCH] Added a new CBoxContainer type which acts as both a VBoxContainer and HBoxContainer and allows changing between them using a property. --- doc/classes/CBoxContainer.xml | 32 ++++ editor/icons/icon_c_box_container.svg | 42 +++++ scene/gui/box_container.cpp | 216 ++++++++++++++++---------- scene/gui/box_container.h | 48 ++++-- scene/register_scene_types.cpp | 1 + 5 files changed, 249 insertions(+), 90 deletions(-) create mode 100644 doc/classes/CBoxContainer.xml create mode 100644 editor/icons/icon_c_box_container.svg diff --git a/doc/classes/CBoxContainer.xml b/doc/classes/CBoxContainer.xml new file mode 100644 index 000000000..ee876517c --- /dev/null +++ b/doc/classes/CBoxContainer.xml @@ -0,0 +1,32 @@ + + + + Horizontal or vertical box container. + + + Horizontal or vertical box container depending on it's [member mode] setting. See [BoxContainer]. + + + $DOCS_URL/tutorials/ui/gui_containers.md + + + + + + Sets whether this [CBoxContainer] will act as a [HBoxContainer] or a [VBoxContainer]. + + + + + This [CBoxContainer] will act as a [HBoxContainer]. + + + This [CBoxContainer] will act as a [VBoxContainer]. + + + + + The horizontal or vertical space between the [CBoxContainer]'s elements. + + + diff --git a/editor/icons/icon_c_box_container.svg b/editor/icons/icon_c_box_container.svg new file mode 100644 index 000000000..d51b5a28c --- /dev/null +++ b/editor/icons/icon_c_box_container.svg @@ -0,0 +1,42 @@ + + + + + + + diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 2fa64d2f9..118b38914 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -32,6 +32,116 @@ #include "label.h" #include "margin_container.h" +Size2 BoxContainer::get_minimum_size() const { + /* Calculate MINIMUM SIZE */ + + Size2i minimum; + int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); + + bool first = true; + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to(get_child(i)); + if (!c) { + continue; + } + if (c->is_set_as_toplevel()) { + continue; + } + + if (!c->is_visible()) { + continue; + } + + Size2i size = c->get_combined_minimum_size(); + + if (vertical) { /* VERTICAL */ + + if (size.width > minimum.width) { + minimum.width = size.width; + } + + minimum.height += size.height + (first ? 0 : sep); + + } else { /* HORIZONTAL */ + + if (size.height > minimum.height) { + minimum.height = size.height; + } + + minimum.width += size.width + (first ? 0 : sep); + } + + first = false; + } + + return minimum; +} + +void BoxContainer::set_alignment(AlignMode p_align) { + align = p_align; + _resort(); +} + +BoxContainer::AlignMode BoxContainer::get_alignment() const { + return align; +} + +void BoxContainer::add_spacer(bool p_begin) { + Control *c = memnew(Control); + c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events + c->set_meta("is_box_container_spacer", true); + + if (vertical) { + c->set_v_size_flags(SIZE_EXPAND_FILL); + } else { + c->set_h_size_flags(SIZE_EXPAND_FILL); + } + + add_child(c); + if (p_begin) { + move_child(c, 0); + } +} + +BoxContainer::BoxContainer(bool p_vertical) { + vertical = p_vertical; + align = ALIGN_BEGIN; + //set_ignore_mouse(true); + set_mouse_filter(MOUSE_FILTER_PASS); +} + +bool BoxContainer::_get_vertical() const { + return vertical; +} +void BoxContainer::_set_vertical(bool p_vertical) { + if (vertical == p_vertical) { + return; + } + + vertical = p_vertical; + + int cc = get_child_count(); + + for (int i = 0; i < cc; ++i) { + Control *c = Object::cast_to(get_child(i)); + + if (c) { + if (c->has_meta("is_box_container_spacer")) { + if (vertical) { + c->set_v_size_flags(SIZE_EXPAND_FILL); + c->set_h_size_flags(SIZE_FILL); + } else { + c->set_v_size_flags(SIZE_FILL); + c->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + } + } + + _resort(); +} + void BoxContainer::_resort() { /** First pass, determine minimum size AND amount of stretchable elements */ @@ -205,52 +315,6 @@ void BoxContainer::_resort() { } } -Size2 BoxContainer::get_minimum_size() const { - /* Calculate MINIMUM SIZE */ - - Size2i minimum; - int sep = get_theme_constant("separation"); //,vertical?"VBoxContainer":"HBoxContainer"); - - bool first = true; - - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to(get_child(i)); - if (!c) { - continue; - } - if (c->is_set_as_toplevel()) { - continue; - } - - if (!c->is_visible()) { - continue; - } - - Size2i size = c->get_combined_minimum_size(); - - if (vertical) { /* VERTICAL */ - - if (size.width > minimum.width) { - minimum.width = size.width; - } - - minimum.height += size.height + (first ? 0 : sep); - - } else { /* HORIZONTAL */ - - if (size.height > minimum.height) { - minimum.height = size.height; - } - - minimum.width += size.width + (first ? 0 : sep); - } - - first = false; - } - - return minimum; -} - void BoxContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { @@ -262,38 +326,6 @@ void BoxContainer::_notification(int p_what) { } } -void BoxContainer::set_alignment(AlignMode p_align) { - align = p_align; - _resort(); -} - -BoxContainer::AlignMode BoxContainer::get_alignment() const { - return align; -} - -void BoxContainer::add_spacer(bool p_begin) { - Control *c = memnew(Control); - c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events - - if (vertical) { - c->set_v_size_flags(SIZE_EXPAND_FILL); - } else { - c->set_h_size_flags(SIZE_EXPAND_FILL); - } - - add_child(c); - if (p_begin) { - move_child(c, 0); - } -} - -BoxContainer::BoxContainer(bool p_vertical) { - vertical = p_vertical; - align = ALIGN_BEGIN; - //set_ignore_mouse(true); - set_mouse_filter(MOUSE_FILTER_PASS); -} - void BoxContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("add_spacer", "begin"), &BoxContainer::add_spacer); ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment); @@ -320,3 +352,31 @@ MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control return mc; } + +CBoxContainer::ContainerMode CBoxContainer::get_mode() const { + return _mode; +} +void CBoxContainer::set_mode(const ContainerMode p_mode) { + if (p_mode == _mode) { + return; + } + + _mode = p_mode; + + _set_vertical(_mode == CONTAINER_MODE_VERTICAL); +} + +CBoxContainer::CBoxContainer() { + _mode = CONTAINER_MODE_HORIZONTAL; +} +CBoxContainer::~CBoxContainer() { +} + +void CBoxContainer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_mode"), &CBoxContainer::get_mode); + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CBoxContainer::set_mode); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), "set_mode", "get_mode"); + + BIND_ENUM_CONSTANT(CONTAINER_MODE_HORIZONTAL); + BIND_ENUM_CONSTANT(CONTAINER_MODE_VERTICAL); +} diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index c3b936577..a2ee3f7bd 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -48,18 +48,6 @@ public: ALIGN_END }; -private: - bool vertical; - AlignMode align; - - void _resort(); - -protected: - void _notification(int p_what); - - static void _bind_methods(); - -public: void add_spacer(bool p_begin = false); void set_alignment(AlignMode p_align); @@ -68,6 +56,20 @@ public: virtual Size2 get_minimum_size() const; BoxContainer(bool p_vertical = false); + +protected: + bool _get_vertical() const; + void _set_vertical(bool p_vertical); + + void _resort(); + + void _notification(int p_what); + + static void _bind_methods(); + +private: + bool vertical; + AlignMode align; }; class HBoxContainer : public BoxContainer { @@ -89,6 +91,28 @@ public: BoxContainer(true) {} }; +class CBoxContainer : public BoxContainer { + GDCLASS(CBoxContainer, BoxContainer); + +public: + enum ContainerMode { + CONTAINER_MODE_HORIZONTAL = 0, + CONTAINER_MODE_VERTICAL, + }; + + ContainerMode get_mode() const; + void set_mode(const ContainerMode p_mode); + + CBoxContainer(); + ~CBoxContainer(); + +protected: + static void _bind_methods(); + + ContainerMode _mode; +}; + VARIANT_ENUM_CAST(BoxContainer::AlignMode); +VARIANT_ENUM_CAST(CBoxContainer::ContainerMode); #endif // BOX_CONTAINER_H diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 083e6988f..cd5b10e0b 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -341,6 +341,7 @@ void register_scene_types() { ClassDB::register_virtual_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class();