diff --git a/doc/classes/CSplitContainer.xml b/doc/classes/CSplitContainer.xml
new file mode 100644
index 000000000..45d2231f5
--- /dev/null
+++ b/doc/classes/CSplitContainer.xml
@@ -0,0 +1,44 @@
+
+
+
+ Horizontal or vertical split container.
+
+
+ Horizontal or vertical split container depending on it's [member mode] setting. See [SplitContainer].
+
+
+ $DOCS_URL/tutorials/ui/gui_containers.md
+
+
+
+
+
+ Sets whether this [CSplitContainer] will act as a [HSplitContainer] or a [VSplitContainer].
+
+
+
+
+ This [CSplitContainer] will act as a [HSplitContainer].
+
+
+ This [CSplitContainer] will act as a [VSplitContainer].
+
+
+
+
+ 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 horizontal or vertical space between the [CSplitContainer]'s elements.
+
+
+ The icon used for the horizontal grabber drawn in the middle area.
+
+
+ The icon used for the vertical grabber drawn in the middle area.
+
+
+ The background drawn under this control.
+
+
+
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 6ffc09bd1..cf4ea7394 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1063,17 +1063,22 @@ Ref create_editor_theme(const Ref p_theme) {
// H/VSplitContainer
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(theme->get_icon("GuiVsplitBg", "EditorIcons"), 1, 1, 1, 1));
theme->set_stylebox("bg", "HSplitContainer", make_stylebox(theme->get_icon("GuiHsplitBg", "EditorIcons"), 1, 1, 1, 1));
+ theme->set_stylebox("bg", "CSplitContainer", make_stylebox(theme->get_icon("GuiHsplitBg", "EditorIcons"), 1, 1, 1, 1));
theme->set_icon("grabber", "VSplitContainer", theme->get_icon("GuiVsplitter", "EditorIcons"));
theme->set_icon("grabber", "HSplitContainer", theme->get_icon("GuiHsplitter", "EditorIcons"));
+ theme->set_icon("vgrabber", "CSplitContainer", theme->get_icon("GuiVsplitter", "EditorIcons"));
+ theme->set_icon("hgrabber", "CSplitContainer", theme->get_icon("GuiHsplitter", "EditorIcons"));
theme->set_constant("separation", "HSplitContainer", default_margin_size * 2 * EDSCALE);
theme->set_constant("separation", "VSplitContainer", default_margin_size * 2 * EDSCALE);
+ theme->set_constant("separation", "CSplitContainer", default_margin_size * 2 * EDSCALE);
// Containers
theme->set_constant("separation", "BoxContainer", default_margin_size * EDSCALE);
theme->set_constant("separation", "HBoxContainer", default_margin_size * EDSCALE);
theme->set_constant("separation", "VBoxContainer", default_margin_size * EDSCALE);
+ theme->set_constant("separation", "CBoxContainer", default_margin_size * EDSCALE);
theme->set_constant("margin_left", "MarginContainer", 0);
theme->set_constant("margin_top", "MarginContainer", 0);
theme->set_constant("margin_right", "MarginContainer", 0);
diff --git a/editor/icons/icon_c_split_container.svg b/editor/icons/icon_c_split_container.svg
new file mode 100644
index 000000000..3bdb62a1b
--- /dev/null
+++ b/editor/icons/icon_c_split_container.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index f7df97742..e40a5dcd9 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -55,6 +55,25 @@ Control *SplitContainer::_getch(int p_idx) const {
return nullptr;
}
+bool SplitContainer::_get_vertical() const {
+ return vertical;
+}
+void SplitContainer::_set_vertical(bool p_vertical) {
+ if (vertical == p_vertical) {
+ return;
+ }
+
+ vertical = p_vertical;
+
+ should_clamp_split_offset = true;
+ queue_sort();
+ minimum_size_changed();
+}
+
+String SplitContainer::get_grabber_theme_constant_name() const {
+ return "grabber";
+}
+
void SplitContainer::_resort() {
int axis = vertical ? 1 : 0;
@@ -76,7 +95,7 @@ void SplitContainer::_resort() {
bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND;
// Determine the separation between items
- Ref g = get_theme_icon("grabber");
+ Ref g = get_theme_icon(get_grabber_theme_constant_name());
int sep = get_theme_constant("separation");
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
@@ -124,7 +143,7 @@ Size2 SplitContainer::get_minimum_size() const {
/* Calculate MINIMUM SIZE */
Size2i minimum;
- Ref g = get_theme_icon("grabber");
+ Ref g = get_theme_icon(get_grabber_theme_constant_name());
int sep = get_theme_constant("separation");
sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0;
@@ -180,7 +199,7 @@ void SplitContainer::_notification(int p_what) {
}
int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant("separation") : 0;
- Ref tex = get_theme_icon("grabber");
+ Ref tex = get_theme_icon(get_grabber_theme_constant_name());
Size2 size = get_size();
if (vertical) {
@@ -353,3 +372,39 @@ SplitContainer::SplitContainer(bool p_vertical) {
collapsed = false;
dragger_visibility = DRAGGER_VISIBLE;
}
+
+CSplitContainer::ContainerMode CSplitContainer::get_mode() const {
+ return _mode;
+}
+void CSplitContainer::set_mode(const ContainerMode p_mode) {
+ if (p_mode == _mode) {
+ return;
+ }
+
+ _mode = p_mode;
+
+ _set_vertical(_mode == CONTAINER_MODE_VERTICAL);
+}
+
+CSplitContainer::CSplitContainer() {
+ _mode = CONTAINER_MODE_HORIZONTAL;
+}
+CSplitContainer::~CSplitContainer() {
+}
+
+String CSplitContainer::get_grabber_theme_constant_name() const {
+ if (_get_vertical()) {
+ return "vgrabber";
+ } else {
+ return "hgrabber";
+ }
+}
+
+void CSplitContainer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_mode"), &CSplitContainer::get_mode);
+ ClassDB::bind_method(D_METHOD("set_mode", "mode"), &CSplitContainer::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/split_container.h b/scene/gui/split_container.h
index f0a128808..265c2e36e 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -56,9 +56,14 @@ private:
Control *_getch(int p_idx) const;
+protected:
+ bool _get_vertical() const;
+ void _set_vertical(bool p_vertical);
+
+ virtual String get_grabber_theme_constant_name() const;
+
void _resort();
-protected:
void _gui_input(const Ref &p_event);
void _notification(int p_what);
static void _bind_methods();
@@ -83,6 +88,8 @@ public:
VARIANT_ENUM_CAST(SplitContainer::DraggerVisibility);
+// ==== HSplitContainer ====
+
class HSplitContainer : public SplitContainer {
GDCLASS(HSplitContainer, SplitContainer);
@@ -91,6 +98,8 @@ public:
SplitContainer(false) {}
};
+// ==== VSplitContainer ====
+
class VSplitContainer : public SplitContainer {
GDCLASS(VSplitContainer, SplitContainer);
@@ -99,4 +108,31 @@ public:
SplitContainer(true) {}
};
+// ==== CSplitContainer ====
+
+class CSplitContainer : public SplitContainer {
+ GDCLASS(CSplitContainer, SplitContainer);
+
+public:
+ enum ContainerMode {
+ CONTAINER_MODE_HORIZONTAL = 0,
+ CONTAINER_MODE_VERTICAL,
+ };
+
+ ContainerMode get_mode() const;
+ void set_mode(const ContainerMode p_mode);
+
+ CSplitContainer();
+ ~CSplitContainer();
+
+protected:
+ virtual String get_grabber_theme_constant_name() const;
+
+ static void _bind_methods();
+
+ ContainerMode _mode;
+};
+
+VARIANT_ENUM_CAST(CSplitContainer::ContainerMode);
+
#endif // SPLIT_CONTAINER_H
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index cd5b10e0b..1e8b97fb5 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -387,6 +387,7 @@ void register_scene_types() {
ClassDB::register_virtual_class();
ClassDB::register_class();
ClassDB::register_class();
+ ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_class();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 1bf9bfe74..3fea74c1a 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -880,12 +880,17 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1));
theme->set_stylebox("bg", "HSplitContainer", make_stylebox(hsplit_bg_png, 1, 1, 1, 1));
+ theme->set_stylebox("bg", "CSplitContainer", make_stylebox(hsplit_bg_png, 1, 1, 1, 1));
theme->set_icon("grabber", "VSplitContainer", make_icon(vsplitter_png));
theme->set_icon("grabber", "HSplitContainer", make_icon(hsplitter_png));
+ theme->set_icon("vgrabber", "CSplitContainer", make_icon(vsplitter_png));
+ theme->set_icon("hgrabber", "CSplitContainer", make_icon(hsplitter_png));
theme->set_constant("separation", "HBoxContainer", 4 * scale);
theme->set_constant("separation", "VBoxContainer", 4 * scale);
+ theme->set_constant("separation", "CBoxContainer", 4 * scale);
+
theme->set_constant("margin_left", "MarginContainer", 0 * scale);
theme->set_constant("margin_top", "MarginContainer", 0 * scale);
theme->set_constant("margin_right", "MarginContainer", 0 * scale);
@@ -894,8 +899,10 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const
theme->set_constant("vseparation", "GridContainer", 4 * scale);
theme->set_constant("separation", "HSplitContainer", 12 * scale);
theme->set_constant("separation", "VSplitContainer", 12 * scale);
+ theme->set_constant("separation", "CSplitContainer", 12 * scale);
theme->set_constant("autohide", "HSplitContainer", 1);
theme->set_constant("autohide", "VSplitContainer", 1);
+ theme->set_constant("autohide", "CSplitContainer", 1);
theme->set_constant("hseparation", "HFlowContainer", 4 * scale);
theme->set_constant("vseparation", "HFlowContainer", 4 * scale);
theme->set_constant("hseparation", "VFlowContainer", 4 * scale);