diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml
index 65ceab3e300..a06b0e9c4bf 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -22,13 +22,25 @@
The alignment of the container's children (must be one of [constant ALIGNMENT_BEGIN], [constant ALIGNMENT_CENTER], or [constant ALIGNMENT_END]).
+
+ If [code]true[/code], the [BoxContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HBoxContainer] and [VBoxContainer].
+
+ The child controls will be arranged at the beginning of the container, i.e. top if orientation is vertical, left if orientation is horizontal (right for RTL layout).
+ The child controls will be centered in the container.
+ The child controls will be arranged at the end of the container, i.e. bottom if orientation is vertical, right if orientation is horizontal (left for RTL layout).
+
+
+ The space between the [BoxContainer]'s elements, in pixels.
+
+
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 705d2282c15..e992d6f9d47 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -55,6 +55,7 @@
If [code]true[/code], saved color presets are visible.
+
diff --git a/doc/classes/FlowContainer.xml b/doc/classes/FlowContainer.xml
index 256e20447bf..d449049ef1e 100644
--- a/doc/classes/FlowContainer.xml
+++ b/doc/classes/FlowContainer.xml
@@ -17,4 +17,18 @@
+
+
+ If [code]true[/code], the [FlowContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HFlowContainer] and [VFlowContainer].
+
+
+
+
+ The horizontal separation of children nodes.
+
+
+ The vertical separation of children nodes.
+
+
diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml
index fb4b9466b59..f5646e9e973 100644
--- a/doc/classes/SplitContainer.xml
+++ b/doc/classes/SplitContainer.xml
@@ -27,6 +27,10 @@
The initial offset of the splitting between the two [Control]s, with [code]0[/code] being at the end of the first [Control].
+
+ If [code]true[/code], the [SplitContainer] will arrange its children vertically, rather than horizontally.
+ Can't be changed when using [HSplitContainer] and [VSplitContainer].
+
@@ -47,4 +51,18 @@
The split dragger is never visible and its space collapsed.
+
+
+ Boolean value. If 1 ([code]true[/code]), the grabber will hide automatically when it isn't under the cursor. If 0 ([code]false[/code]), it's always visible.
+
+
+ The space between sides of the container.
+
+
+ The icon used for the grabber drawn in the middle area when [member vertical] is [code]false[/code].
+
+
+ The icon used for the grabber drawn in the middle area when [member vertical] is [code]true[/code].
+
+
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index af0e40d1d45..d0bb63dde95 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1358,6 +1358,8 @@ Ref create_editor_theme(const Ref p_theme) {
theme->set_color("selection_color", "TextEdit", selection_color);
theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
+ theme->set_icon("h_grabber", "SplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
+ theme->set_icon("v_grabber", "SplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "VSplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons")));
theme->set_icon("grabber", "HSplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons")));
diff --git a/editor/icons/BoxContainer.svg b/editor/icons/BoxContainer.svg
new file mode 100644
index 00000000000..03b918d9cf8
--- /dev/null
+++ b/editor/icons/BoxContainer.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/FlowContainer.svg b/editor/icons/FlowContainer.svg
new file mode 100644
index 00000000000..57699ce8749
--- /dev/null
+++ b/editor/icons/FlowContainer.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/SplitContainer.svg b/editor/icons/SplitContainer.svg
new file mode 100644
index 00000000000..bb03350166b
--- /dev/null
+++ b/editor/icons/SplitContainer.svg
@@ -0,0 +1 @@
+
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 22c8f2cd4e5..151b0b93d4b 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -291,7 +291,7 @@ Size2 BoxContainer::get_minimum_size() const {
void BoxContainer::_update_theme_item_cache() {
Container::_update_theme_item_cache();
- theme_cache.separation = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer");
+ theme_cache.separation = get_theme_constant(SNAME("separation"));
}
void BoxContainer::_notification(int p_what) {
@@ -311,6 +311,12 @@ void BoxContainer::_notification(int p_what) {
}
}
+void BoxContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void BoxContainer::set_alignment(AlignmentMode p_alignment) {
if (alignment == p_alignment) {
return;
@@ -323,6 +329,17 @@ BoxContainer::AlignmentMode BoxContainer::get_alignment() const {
return alignment;
}
+void BoxContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool BoxContainer::is_vertical() const {
+ return vertical;
+}
+
Control *BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew(Control);
c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events
@@ -371,14 +388,17 @@ BoxContainer::BoxContainer(bool p_vertical) {
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);
ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &BoxContainer::set_alignment);
+ ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment);
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &BoxContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &BoxContainer::is_vertical);
BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN);
BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
BIND_ENUM_CONSTANT(ALIGNMENT_END);
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control *p_control, bool p_expand) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index 55dfb2ada72..0ee5bd17729 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -54,9 +54,12 @@ private:
void _resort();
protected:
+ bool is_fixed = false;
+
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -65,6 +68,9 @@ public:
void set_alignment(AlignmentMode p_alignment);
AlignmentMode get_alignment() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual Size2 get_minimum_size() const override;
virtual Vector get_allowed_size_flags_horizontal() const override;
@@ -78,7 +84,7 @@ class HBoxContainer : public BoxContainer {
public:
HBoxContainer() :
- BoxContainer(false) {}
+ BoxContainer(false) { is_fixed = true; }
};
class MarginContainer;
@@ -89,7 +95,7 @@ public:
MarginContainer *add_margin_child(const String &p_label, Control *p_control, bool p_expand = false);
VBoxContainer() :
- BoxContainer(true) {}
+ BoxContainer(true) { is_fixed = true; }
};
VARIANT_ENUM_CAST(BoxContainer::AlignmentMode);
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index ca230b8e81a..b0d15aa7f4f 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -272,14 +272,36 @@ void FlowContainer::_notification(int p_what) {
}
}
+void FlowContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
int FlowContainer::get_line_count() const {
return cached_line_count;
}
+void FlowContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool FlowContainer::is_vertical() const {
+ return vertical;
+}
+
FlowContainer::FlowContainer(bool p_vertical) {
vertical = p_vertical;
}
void FlowContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count);
+
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h
index 2cdf7d7c375..536df27ad63 100644
--- a/scene/gui/flow_container.h
+++ b/scene/gui/flow_container.h
@@ -50,14 +50,20 @@ private:
void _resort();
protected:
+ bool is_fixed = false;
+
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
int get_line_count() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual Size2 get_minimum_size() const override;
virtual Vector get_allowed_size_flags_horizontal() const override;
@@ -71,7 +77,7 @@ class HFlowContainer : public FlowContainer {
public:
HFlowContainer() :
- FlowContainer(false) {}
+ FlowContainer(false) { is_fixed = true; }
};
class VFlowContainer : public FlowContainer {
@@ -79,7 +85,7 @@ class VFlowContainer : public FlowContainer {
public:
VFlowContainer() :
- FlowContainer(true) {}
+ FlowContainer(true) { is_fixed = true; }
};
#endif // FLOW_CONTAINER_H
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index e7e955a17fa..04bd5b32826 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -55,6 +55,18 @@ Control *SplitContainer::_getch(int p_idx) const {
return nullptr;
}
+Ref SplitContainer::_get_grabber_icon() const {
+ if (is_fixed) {
+ return theme_cache.grabber_icon;
+ } else {
+ if (vertical) {
+ return theme_cache.grabber_icon_v;
+ } else {
+ return theme_cache.grabber_icon_h;
+ }
+ }
+}
+
void SplitContainer::_resort() {
int axis = vertical ? 1 : 0;
@@ -76,7 +88,8 @@ void SplitContainer::_resort() {
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
// Determine the separation between items
- int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? theme_cache.grabber_icon->get_height() : theme_cache.grabber_icon->get_width()) : 0;
+ Ref g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
// Compute the minimum size
Size2 ms_first = first->get_combined_minimum_size();
@@ -126,10 +139,9 @@ void SplitContainer::_resort() {
}
Size2 SplitContainer::get_minimum_size() const {
- /* Calculate MINIMUM SIZE */
-
Size2i minimum;
- int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? theme_cache.grabber_icon->get_height() : theme_cache.grabber_icon->get_width()) : 0;
+ Ref g = _get_grabber_icon();
+ int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0;
for (int i = 0; i < 2; i++) {
if (!_getch(i)) {
@@ -164,6 +176,8 @@ void SplitContainer::_update_theme_item_cache() {
theme_cache.separation = get_theme_constant(SNAME("separation"));
theme_cache.autohide = get_theme_constant(SNAME("autohide"));
theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
+ theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber"));
+ theme_cache.grabber_icon_v = get_theme_icon(SNAME("v_grabber"));
}
void SplitContainer::_notification(int p_what) {
@@ -214,6 +228,12 @@ void SplitContainer::_notification(int p_what) {
}
}
+void SplitContainer::_validate_property(PropertyInfo &p_property) const {
+ if (is_fixed && p_property.name == "vertical") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void SplitContainer::gui_input(const Ref &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -344,6 +364,17 @@ bool SplitContainer::is_collapsed() const {
return collapsed;
}
+void SplitContainer::set_vertical(bool p_vertical) {
+ ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
+ vertical = p_vertical;
+ update_minimum_size();
+ _resort();
+}
+
+bool SplitContainer::is_vertical() const {
+ return vertical;
+}
+
Vector SplitContainer::get_allowed_size_flags_horizontal() const {
Vector flags;
flags.append(SIZE_FILL);
@@ -379,11 +410,15 @@ void SplitContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_dragger_visibility", "mode"), &SplitContainer::set_dragger_visibility);
ClassDB::bind_method(D_METHOD("get_dragger_visibility"), &SplitContainer::get_dragger_visibility);
+ ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &SplitContainer::set_vertical);
+ ClassDB::bind_method(D_METHOD("is_vertical"), &SplitContainer::is_vertical);
+
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset")));
ADD_PROPERTY(PropertyInfo(Variant::INT, "split_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_split_offset", "get_split_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
BIND_ENUM_CONSTANT(DRAGGER_VISIBLE);
BIND_ENUM_CONSTANT(DRAGGER_HIDDEN);
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 18f95739738..8ab0779d4b4 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -59,17 +59,23 @@ private:
int separation = 0;
int autohide = 0;
Ref grabber_icon;
+ Ref grabber_icon_h;
+ Ref grabber_icon_v;
} theme_cache;
Control *_getch(int p_idx) const;
+ Ref _get_grabber_icon() const;
void _resort();
protected:
+ bool is_fixed = false;
+
virtual void gui_input(const Ref &p_event) override;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -83,6 +89,9 @@ public:
void set_dragger_visibility(DraggerVisibility p_visibility);
DraggerVisibility get_dragger_visibility() const;
+ void set_vertical(bool p_vertical);
+ bool is_vertical() const;
+
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
virtual Size2 get_minimum_size() const override;
@@ -100,7 +109,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) {}
+ SplitContainer(false) { is_fixed = true; }
};
class VSplitContainer : public SplitContainer {
@@ -108,7 +117,7 @@ class VSplitContainer : public SplitContainer {
public:
VSplitContainer() :
- SplitContainer(true) {}
+ SplitContainer(true) { is_fixed = true; }
};
#endif // SPLIT_CONTAINER_H
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index cc40d36fa37..00d97a9b468 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -378,14 +378,14 @@ void register_scene_types() {
GDREGISTER_CLASS(VSeparator);
GDREGISTER_CLASS(TextureButton);
GDREGISTER_CLASS(Container);
- GDREGISTER_ABSTRACT_CLASS(BoxContainer);
+ GDREGISTER_CLASS(BoxContainer);
GDREGISTER_CLASS(HBoxContainer);
GDREGISTER_CLASS(VBoxContainer);
GDREGISTER_CLASS(GridContainer);
GDREGISTER_CLASS(CenterContainer);
GDREGISTER_CLASS(ScrollContainer);
GDREGISTER_CLASS(PanelContainer);
- GDREGISTER_ABSTRACT_CLASS(FlowContainer);
+ GDREGISTER_CLASS(FlowContainer);
GDREGISTER_CLASS(HFlowContainer);
GDREGISTER_CLASS(VFlowContainer);
@@ -422,7 +422,7 @@ void register_scene_types() {
GDREGISTER_CLASS(MarginContainer);
GDREGISTER_CLASS(SubViewportContainer);
- GDREGISTER_ABSTRACT_CLASS(SplitContainer);
+ GDREGISTER_CLASS(SplitContainer);
GDREGISTER_CLASS(HSplitContainer);
GDREGISTER_CLASS(VSplitContainer);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 32c3c9fe9e2..208e28f17a8 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -996,9 +996,12 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
// Containers
+ theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
+ theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]);
+ theme->set_constant("separation", "BoxContainer", 4 * scale);
theme->set_constant("separation", "HBoxContainer", 4 * scale);
theme->set_constant("separation", "VBoxContainer", 4 * scale);
theme->set_constant("margin_left", "MarginContainer", 0 * scale);
@@ -1007,10 +1010,14 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
theme->set_constant("margin_bottom", "MarginContainer", 0 * scale);
theme->set_constant("h_separation", "GridContainer", 4 * scale);
theme->set_constant("v_separation", "GridContainer", 4 * scale);
+ theme->set_constant("separation", "SplitContainer", 12 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
+ theme->set_constant("autohide", "SplitContainer", 1 * scale);
theme->set_constant("autohide", "HSplitContainer", 1 * scale);
theme->set_constant("autohide", "VSplitContainer", 1 * scale);
+ theme->set_constant("h_separation", "FlowContainer", 4 * scale);
+ theme->set_constant("v_separation", "FlowContainer", 4 * scale);
theme->set_constant("h_separation", "HFlowContainer", 4 * scale);
theme->set_constant("v_separation", "HFlowContainer", 4 * scale);
theme->set_constant("h_separation", "VFlowContainer", 4 * scale);