diff --git a/editor/icons/GuiViewportHdiagsplitter.svg b/editor/icons/GuiViewportHdiagsplitter.svg
deleted file mode 100644
index ad55722da1..0000000000
--- a/editor/icons/GuiViewportHdiagsplitter.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/editor/icons/GuiViewportVdiagsplitter.svg b/editor/icons/GuiViewportVdiagsplitter.svg
deleted file mode 100644
index d5f035b4e6..0000000000
--- a/editor/icons/GuiViewportVdiagsplitter.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/editor/icons/GuiViewportVhsplitter.svg b/editor/icons/GuiViewportVhsplitter.svg
deleted file mode 100644
index ae3746ea9f..0000000000
--- a/editor/icons/GuiViewportVhsplitter.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/editor/scene/3d/node_3d_editor_plugin.cpp b/editor/scene/3d/node_3d_editor_plugin.cpp
index dbe5e5e168..e758c10713 100644
--- a/editor/scene/3d/node_3d_editor_plugin.cpp
+++ b/editor/scene/3d/node_3d_editor_plugin.cpp
@@ -6128,317 +6128,139 @@ Node3DEditorViewport::~Node3DEditorViewport() {
//////////////////////////////////////////////////////////////
-void Node3DEditorViewportContainer::gui_input(const Ref &p_event) {
- ERR_FAIL_COND(p_event.is_null());
-
- if (_redirect_freelook_input(p_event)) {
+void Node3DEditorViewportContainer::_update_split_drag_margin() {
+ if (view != VIEW_USE_4_VIEWPORTS && view != VIEW_USE_3_VIEWPORTS) {
return;
}
+ // Also for 3 viewports view since the first split container is used to remember the offset.
+ first_split->set_split_offset(second_split->get_split_offset());
- Ref mb = p_event;
-
- if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_pressed()) {
- Vector2 size = get_size();
-
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- dragging_h = mb->get_position().x >= (mid_w - h_sep / 2) && mb->get_position().x < (mid_w + h_sep / 2);
- dragging_v = mb->get_position().y >= (mid_h - v_sep / 2) && mb->get_position().y < (mid_h + v_sep / 2);
-
- drag_begin_pos = mb->get_position();
- drag_begin_ratio.x = ratio_h;
- drag_begin_ratio.y = ratio_v;
-
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
- dragging_h = false;
- dragging_v = false;
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
- dragging_h = false;
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
- dragging_v = false;
-
- } break;
- case VIEW_USE_3_VIEWPORTS:
- case VIEW_USE_3_VIEWPORTS_ALT:
- case VIEW_USE_4_VIEWPORTS: {
- // Do nothing.
-
- } break;
- }
- } else {
- dragging_h = false;
- dragging_v = false;
- }
- }
-
- Ref mm = p_event;
-
- if (mm.is_valid()) {
- if (view == VIEW_USE_3_VIEWPORTS || view == VIEW_USE_3_VIEWPORTS_ALT || view == VIEW_USE_4_VIEWPORTS) {
- Vector2 size = get_size();
-
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- bool was_hovering_h = hovering_h;
- bool was_hovering_v = hovering_v;
- hovering_h = mm->get_position().x >= (mid_w - h_sep / 2) && mm->get_position().x < (mid_w + h_sep / 2);
- hovering_v = mm->get_position().y >= (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
-
- if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
- queue_redraw();
- }
- }
-
- if (dragging_h) {
- real_t new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
- new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
- ratio_h = new_ratio;
- queue_sort();
- queue_redraw();
- }
- if (dragging_v) {
- real_t new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
- new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
- ratio_v = new_ratio;
- queue_sort();
- queue_redraw();
- }
+ if (view == VIEW_USE_4_VIEWPORTS) {
+ // Extend to cover the first split on top.
+ second_split->set_drag_area_margin_begin(second_split->get_size().y - get_size().y);
}
}
void Node3DEditorViewportContainer::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_MOUSE_ENTER:
- case NOTIFICATION_MOUSE_EXIT: {
- mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
- queue_redraw();
- } break;
-
- case NOTIFICATION_DRAW: {
- if (mouseover && Input::get_singleton()->get_mouse_mode() != Input::MouseMode::MOUSE_MODE_CAPTURED) {
- Ref h_grabber = get_theme_icon(SNAME("grabber"), SNAME("HSplitContainer"));
- Ref v_grabber = get_theme_icon(SNAME("grabber"), SNAME("VSplitContainer"));
-
- Ref hdiag_grabber = get_editor_theme_icon(SNAME("GuiViewportHdiagsplitter"));
- Ref vdiag_grabber = get_editor_theme_icon(SNAME("GuiViewportVdiagsplitter"));
- Ref vh_grabber = get_editor_theme_icon(SNAME("GuiViewportVhsplitter"));
-
- Vector2 size = get_size();
-
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
-
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- int size_left = mid_w - h_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
-
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
- // Nothing to show.
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
-
- } break;
- case VIEW_USE_3_VIEWPORTS: {
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- case VIEW_USE_4_VIEWPORTS: {
- Vector2 half(mid_w, mid_h);
- if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
- draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_DRAG);
- } else if ((hovering_v && !dragging_h) || dragging_v) {
- draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_VSPLIT);
- } else if (hovering_h || dragging_h) {
- draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
- set_default_cursor_shape(CURSOR_HSPLIT);
- }
-
- } break;
- }
- }
- } break;
-
- case NOTIFICATION_SORT_CHILDREN: {
- Node3DEditorViewport *viewports[4];
- int vc = 0;
- for (int i = 0; i < get_child_count(); i++) {
- viewports[vc] = Object::cast_to(get_child(i));
- if (viewports[vc]) {
- vc++;
- }
- }
-
- ERR_FAIL_COND(vc != 4);
-
- Size2 size = get_size();
-
- if (size.x < 10 || size.y < 10) {
- for (int i = 0; i < 4; i++) {
- viewports[i]->hide();
- }
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (!EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen")) {
return;
}
- int h_sep = get_theme_constant(SNAME("separation"), SNAME("HSplitContainer"));
-
- int v_sep = get_theme_constant(SNAME("separation"), SNAME("VSplitContainer"));
-
- int mid_w = size.width * ratio_h;
- int mid_h = size.height * ratio_v;
-
- int size_left = mid_w - h_sep / 2;
- int size_right = size.width - mid_w - h_sep / 2;
-
- int size_top = mid_h - v_sep / 2;
- int size_bottom = size.height - mid_h - v_sep / 2;
-
- switch (view) {
- case VIEW_USE_1_VIEWPORT: {
- viewports[0]->show();
- for (int i = 1; i < 4; i++) {
- viewports[i]->hide();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
-
- } break;
- case VIEW_USE_2_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- if (i == 1 || i == 3) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
- }
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
-
- } break;
- case VIEW_USE_2_VIEWPORTS_ALT: {
- for (int i = 0; i < 4; i++) {
- if (i == 1 || i == 3) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
- }
- }
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
-
- } break;
- case VIEW_USE_3_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- if (i == 1) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
- }
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
-
- } break;
- case VIEW_USE_3_VIEWPORTS_ALT: {
- for (int i = 0; i < 4; i++) {
- if (i == 1) {
- viewports[i]->hide();
- } else {
- viewports[i]->show();
- }
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
-
- } break;
- case VIEW_USE_4_VIEWPORTS: {
- for (int i = 0; i < 4; i++) {
- viewports[i]->show();
- }
-
- fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
- fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
- fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
- fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
-
- } break;
- }
+ [[fallthrough]];
+ }
+ case NOTIFICATION_READY: {
+ bool touch_optimizations = EDITOR_GET("interface/touchscreen/enable_touch_optimizations");
+ main_split->set_touch_dragger_enabled(touch_optimizations);
+ first_split->set_touch_dragger_enabled(touch_optimizations);
+ second_split->set_touch_dragger_enabled(touch_optimizations);
} break;
}
}
void Node3DEditorViewportContainer::set_view(View p_view) {
view = p_view;
- queue_sort();
+
+ Node3DEditorViewport *viewports[4];
+ for (uint32_t i = 0; i < 4; i++) {
+ viewports[i] = Node3DEditor::get_singleton()->get_editor_viewport(i);
+ ERR_FAIL_NULL(viewports[i]);
+ }
+
+ const bool previous_main_vertical = !first_split->is_vertical();
+ const float horizontal_offset = previous_main_vertical ? first_split->get_split_offset() : main_split->get_split_offset();
+ const float vertical_offset = previous_main_vertical ? main_split->get_split_offset() : first_split->get_split_offset();
+
+ first_split->set_dragging_enabled(true);
+ second_split->set_drag_area_margin_begin(0);
+ viewports[0]->show();
+
+ switch (view) {
+ case VIEW_USE_1_VIEWPORT: {
+ for (int i = 1; i < 4; i++) {
+ viewports[i]->hide();
+ }
+ second_split->hide();
+ } break;
+ case VIEW_USE_2_VIEWPORTS:
+ case VIEW_USE_2_VIEWPORTS_ALT: {
+ viewports[1]->show();
+ viewports[2]->hide();
+ viewports[3]->hide();
+ second_split->hide();
+ const bool is_vertical = view == VIEW_USE_2_VIEWPORTS;
+ if (first_split->is_vertical() != is_vertical) {
+ first_split->set_vertical(is_vertical);
+ first_split->set_split_offset(is_vertical ? vertical_offset : horizontal_offset);
+ main_split->set_split_offset(is_vertical ? horizontal_offset : vertical_offset); // Store the other offset here for later.
+ }
+ } break;
+ case VIEW_USE_3_VIEWPORTS:
+ case VIEW_USE_3_VIEWPORTS_ALT: {
+ // Default mode has two on bottom (second_split). Alt mode has two on the left (first_split).
+ const bool main_vertical = view == VIEW_USE_3_VIEWPORTS;
+ viewports[1]->set_visible(!main_vertical);
+ viewports[2]->show();
+ viewports[3]->set_visible(main_vertical);
+ second_split->show();
+ main_split->set_vertical(main_vertical);
+ main_split->set_split_offset(main_vertical ? vertical_offset : horizontal_offset);
+ first_split->set_vertical(!main_vertical);
+ first_split->set_split_offset(main_vertical ? horizontal_offset : vertical_offset);
+ second_split->set_split_offset(main_vertical ? horizontal_offset : vertical_offset);
+ } break;
+ case VIEW_USE_4_VIEWPORTS: {
+ for (int i = 1; i < 4; i++) {
+ viewports[i]->show();
+ }
+ second_split->show();
+ main_split->set_vertical(true);
+ main_split->set_split_offset(vertical_offset);
+ first_split->set_vertical(false);
+ first_split->set_split_offset(horizontal_offset);
+ second_split->set_split_offset(horizontal_offset);
+
+ first_split->set_dragging_enabled(false);
+ _update_split_drag_margin();
+ } break;
+ }
}
Node3DEditorViewportContainer::View Node3DEditorViewportContainer::get_view() {
return view;
}
+void Node3DEditorViewportContainer::add_viewport(Node3DEditorViewport *p_viewport, int p_index) {
+ if (p_index <= 1) {
+ first_split->add_child(p_viewport);
+ } else {
+ second_split->add_child(p_viewport);
+ if (p_index == 3) {
+ // Connect to the second split's child to update the drag margin immediately whenever the split offset changes.
+ p_viewport->connect(SceneStringName(resized), callable_mp(this, &Node3DEditorViewportContainer::_update_split_drag_margin));
+ }
+ }
+}
+
Node3DEditorViewportContainer::Node3DEditorViewportContainer() {
set_clip_contents(true);
- view = VIEW_USE_1_VIEWPORT;
- mouseover = false;
- ratio_h = 0.5;
- ratio_v = 0.5;
- hovering_v = false;
- hovering_h = false;
- dragging_v = false;
- dragging_h = false;
+
+ main_split = memnew(SplitContainer);
+ main_split->set_drag_nested_intersections(true);
+
+ first_split = memnew(SplitContainer);
+ first_split->set_h_size_flags(SIZE_EXPAND_FILL);
+ first_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ first_split->set_drag_nested_intersections(true);
+
+ second_split = memnew(SplitContainer);
+ second_split->set_h_size_flags(SIZE_EXPAND_FILL);
+ second_split->set_v_size_flags(SIZE_EXPAND_FILL);
+ second_split->set_drag_nested_intersections(true);
+
+ main_split->add_child(first_split);
+ main_split->add_child(second_split);
+ add_child(main_split);
}
///////////////////////////////////////////////////////////////////
@@ -9752,7 +9574,10 @@ Node3DEditor::Node3DEditor() {
viewports[i]->connect("toggle_maximize_view", callable_mp(this, &Node3DEditor::_toggle_maximize_view));
viewports[i]->connect("clicked", callable_mp(this, &Node3DEditor::_viewport_clicked).bind(i));
viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
- viewport_base->add_child(viewports[i]);
+ viewports[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ viewports[i]->set_v_size_flags(SIZE_EXPAND_FILL);
+ viewports[i]->set_custom_minimum_size(Size2(39, 39));
+ viewport_base->add_viewport(viewports[i], i);
}
/* SNAP DIALOG */
diff --git a/editor/scene/3d/node_3d_editor_plugin.h b/editor/scene/3d/node_3d_editor_plugin.h
index e07314b7d3..ed69218509 100644
--- a/editor/scene/3d/node_3d_editor_plugin.h
+++ b/editor/scene/3d/node_3d_editor_plugin.h
@@ -37,6 +37,7 @@
#include "scene/debugger/view_3d_controller.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
+#include "scene/gui/margin_container.h"
#include "scene/gui/spin_box.h"
#include "scene/resources/gradient.h"
#include "scene/resources/immediate_mesh.h"
@@ -58,6 +59,7 @@ class OptionButton;
class PanelContainer;
class ProceduralSkyMaterial;
class RichTextLabel;
+class SplitContainer;
class SubViewport;
class SubViewportContainer;
class VSeparator;
@@ -519,8 +521,8 @@ public:
~Node3DEditorSelectedItem();
};
-class Node3DEditorViewportContainer : public Container {
- GDCLASS(Node3DEditorViewportContainer, Container);
+class Node3DEditorViewportContainer : public MarginContainer {
+ GDCLASS(Node3DEditorViewportContainer, MarginContainer);
public:
enum View {
@@ -533,20 +535,12 @@ public:
};
private:
- View view;
- bool mouseover;
- real_t ratio_h;
- real_t ratio_v;
+ View view = VIEW_USE_1_VIEWPORT;
+ SplitContainer *main_split = nullptr;
+ SplitContainer *first_split = nullptr;
+ SplitContainer *second_split = nullptr;
- bool hovering_v;
- bool hovering_h;
-
- bool dragging_v;
- bool dragging_h;
- Vector2 drag_begin_pos;
- Vector2 drag_begin_ratio;
-
- virtual void gui_input(const Ref &p_event) override;
+ void _update_split_drag_margin();
protected:
void _notification(int p_what);
@@ -555,6 +549,8 @@ public:
void set_view(View p_view);
View get_view();
+ void add_viewport(Node3DEditorViewport *p_viewport, int p_index);
+
Node3DEditorViewportContainer();
};
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 2d3e7665cf..6feee52efc 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -302,6 +302,7 @@ void SplitContainerDragger::update_touch_dragger() {
touch_dragger->set_texture(sc->_get_touch_dragger_icon());
touch_dragger->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
touch_dragger->set_default_cursor_shape(sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
+ touch_dragger->set_visible(sc->dragging_enabled);
}
void SplitContainerDragger::stop_dragging() {
@@ -850,9 +851,6 @@ void SplitContainer::_resort() {
}
for (SplitContainerDragger *dragger : dragging_area_controls) {
dragger->set_visible(!collapsed);
- if (touch_dragger_enabled) {
- dragger->touch_dragger->set_visible(dragging_enabled);
- }
}
_update_default_dragger_positions();
@@ -1483,6 +1481,11 @@ void SplitContainer::set_dragging_enabled(bool p_enabled) {
dragger->stop_dragging();
}
}
+ if (touch_dragger_enabled) {
+ for (SplitContainerDragger *dragger : dragging_area_controls) {
+ dragger->update_touch_dragger();
+ }
+ }
if (get_viewport()) {
get_viewport()->update_mouse_cursor_state();
}