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();