43
43
#include " editor/gui/editor_bottom_panel.h"
44
44
#include " editor/themes/editor_scale.h"
45
45
#include " editor/window_wrapper.h"
46
+ #include " scene/resources/style_box_flat.h"
46
47
47
48
enum class TabStyle {
48
49
TEXT_ONLY,
@@ -52,6 +53,118 @@ enum class TabStyle {
52
53
53
54
EditorDockManager *EditorDockManager::singleton = nullptr ;
54
55
56
+ bool EditorDockDragHint::can_drop_data (const Point2 &p_point, const Variant &p_data) const {
57
+ return can_drop_dock;
58
+ }
59
+
60
+ void EditorDockDragHint::drop_data (const Point2 &p_point, const Variant &p_data) {
61
+ if (can_drop_dock) {
62
+ // Drop dock into last spot if not over tabbar.
63
+ if (drop_tabbar->get_rect ().has_point (p_point)) {
64
+ drop_tabbar->_handle_drop_data (" tab_container_tab" , p_point, p_data, callable_mp (this , &EditorDockDragHint::_drag_move_tab), callable_mp (this , &EditorDockDragHint::_drag_move_tab_from));
65
+ } else {
66
+ dock_manager->_move_dock (dock_manager->_get_dock_tab_dragged (), dock_manager->dock_slot [occupied_slot], drop_tabbar->get_tab_count ());
67
+ }
68
+ }
69
+ }
70
+
71
+ void EditorDockDragHint::_drag_move_tab (int p_from_index, int p_to_index) {
72
+ dock_manager->_move_dock_tab_index (dock_manager->_get_dock_tab_dragged (), p_to_index, true );
73
+ }
74
+
75
+ void EditorDockDragHint::_drag_move_tab_from (TabBar *p_from_tabbar, int p_from_index, int p_to_index) {
76
+ dock_manager->_move_dock (dock_manager->_get_dock_tab_dragged (), dock_manager->dock_slot [occupied_slot], p_to_index);
77
+ }
78
+
79
+ void EditorDockDragHint::gui_input (const Ref<InputEvent> &p_event) {
80
+ ERR_FAIL_COND (p_event.is_null ());
81
+
82
+ Ref<InputEventMouseMotion> mm = p_event;
83
+ if (mm.is_valid ()) {
84
+ Point2 pos = mm->get_position ();
85
+
86
+ // Redraw when inside the tabbar and just exited.
87
+ if (mouse_inside_tabbar) {
88
+ queue_redraw ();
89
+ }
90
+ mouse_inside_tabbar = drop_tabbar->get_rect ().has_point (pos);
91
+ }
92
+ }
93
+
94
+ void EditorDockDragHint::set_slot (EditorDockManager::DockSlot p_slot) {
95
+ occupied_slot = p_slot;
96
+ drop_tabbar = dock_manager->dock_slot [occupied_slot]->get_tab_bar ();
97
+ }
98
+
99
+ void EditorDockDragHint::_notification (int p_what) {
100
+ switch (p_what) {
101
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
102
+ if (EditorSettings::get_singleton ()->check_changed_settings_in_group (" interface/theme" )) {
103
+ dock_drop_highlight->set_corner_radius_all (EDSCALE * EDITOR_GET (" interface/theme/corner_radius" ).operator int ());
104
+ if (mouse_inside) {
105
+ queue_redraw ();
106
+ }
107
+ }
108
+ } break ;
109
+
110
+ case NOTIFICATION_THEME_CHANGED: {
111
+ valid_drop_color = get_theme_color (SNAME (" accent_color" ), EditorStringName (Editor));
112
+ invalid_drop_color = get_theme_color (SNAME (" error_color" ), EditorStringName (Editor));
113
+ } break ;
114
+
115
+ case NOTIFICATION_MOUSE_ENTER:
116
+ case NOTIFICATION_MOUSE_EXIT: {
117
+ mouse_inside = p_what == NOTIFICATION_MOUSE_ENTER;
118
+ queue_redraw ();
119
+ } break ;
120
+
121
+ case NOTIFICATION_DRAG_BEGIN: {
122
+ Control *dragged_dock = dock_manager->_get_dock_tab_dragged ();
123
+ if (!dragged_dock) {
124
+ return ;
125
+ }
126
+
127
+ // TODO: Update logic when GH-106503 is merged to use flags.
128
+ can_drop_dock = is_layout_horizontal ? bool (dragged_dock->call (" _can_dock_horizontal" )) : true ;
129
+
130
+ Color hint_color = can_drop_dock ? valid_drop_color : invalid_drop_color;
131
+ dock_drop_highlight->set_border_color (hint_color);
132
+ dock_drop_highlight->set_bg_color (hint_color * Color (1 , 1 , 1 , 0.1 ));
133
+ } break ;
134
+ case NOTIFICATION_DRAG_END: {
135
+ dock_manager->_dock_drag_stopped ();
136
+ can_drop_dock = false ;
137
+ mouse_inside = false ;
138
+ hide ();
139
+ } break ;
140
+
141
+ case NOTIFICATION_DRAW: {
142
+ // Draw highlights around docks that can be dropped.
143
+ if (mouse_inside) {
144
+ Rect2 dock_rect = Rect2 (Point2 (), get_size ()).grow (2 * EDSCALE);
145
+ draw_style_box (dock_drop_highlight, dock_rect);
146
+
147
+ // Only display hint if the mouse is over the tabbar.
148
+ if (drop_tabbar->get_global_rect ().has_point (get_global_mouse_position ())) {
149
+ drop_tabbar->_draw_tab_drop (get_canvas_item ());
150
+ }
151
+ }
152
+ } break ;
153
+ }
154
+ }
155
+
156
+ EditorDockDragHint::EditorDockDragHint () {
157
+ dock_manager = EditorDockManager::get_singleton ();
158
+
159
+ set_as_top_level (true );
160
+ dock_drop_highlight.instantiate ();
161
+ dock_drop_highlight->set_corner_radius_all (EDSCALE * EDITOR_GET (" interface/theme/corner_radius" ).operator int ());
162
+ dock_drop_highlight->set_border_width_all (Math::round (2 * EDSCALE));
163
+ }
164
+
165
+ // //////////////////////////////////////////////
166
+ // //////////////////////////////////////////////
167
+
55
168
void DockSplitContainer::_update_visibility () {
56
169
if (is_updating) {
57
170
return ;
@@ -114,6 +227,56 @@ void DockSplitContainer::remove_child_notify(Node *p_child) {
114
227
_update_visibility ();
115
228
}
116
229
230
+ // //////////////////////////////////////////////
231
+ // //////////////////////////////////////////////
232
+
233
+ Control *EditorDockManager::_get_dock_tab_dragged () {
234
+ if (dock_tab_dragged) {
235
+ return dock_tab_dragged;
236
+ }
237
+
238
+ Dictionary dock_drop_data = dock_slot[DOCK_SLOT_LEFT_BL]->get_viewport ()->gui_get_drag_data ();
239
+
240
+ // Check if we are dragging a dock.
241
+ const String type = dock_drop_data.get (" type" , " " );
242
+ if (type == " tab_container_tab" ) {
243
+ Node *from_node = dock_slot[DOCK_SLOT_LEFT_BL]->get_node (dock_drop_data[" from_path" ]);
244
+ if (!from_node) {
245
+ return nullptr ;
246
+ }
247
+
248
+ TabContainer *parent = Object::cast_to<TabContainer>(from_node->get_parent ());
249
+ if (!parent) {
250
+ return nullptr ;
251
+ }
252
+
253
+ // TODO: Update logic when GH-106503 is merged to cast directly to EditorDock instead of the below check.
254
+ for (int i = 0 ; i < DOCK_SLOT_MAX; i++) {
255
+ if (dock_slot[i] == parent) {
256
+ dock_tab_dragged = parent->get_tab_control (dock_drop_data[" tab_index" ]);
257
+ break ;
258
+ }
259
+ }
260
+ if (!dock_tab_dragged) {
261
+ return nullptr ;
262
+ }
263
+
264
+ for (int i = 0 ; i < DOCK_SLOT_MAX; i++) {
265
+ if (dock_slot[i]->is_visible_in_tree ()) {
266
+ dock_drag_rects[i]->set_rect (dock_slot[i]->get_global_rect ());
267
+ dock_drag_rects[i]->show ();
268
+ }
269
+ }
270
+
271
+ return dock_tab_dragged;
272
+ }
273
+ return nullptr ;
274
+ }
275
+
276
+ void EditorDockManager::_dock_drag_stopped () {
277
+ dock_tab_dragged = nullptr ;
278
+ }
279
+
117
280
void EditorDockManager::_dock_split_dragged (int p_offset) {
118
281
EditorNode::get_singleton ()->save_editor_layout_delayed ();
119
282
}
@@ -830,6 +993,12 @@ void EditorDockManager::register_dock_slot(DockSlot p_dock_slot, TabContainer *p
830
993
p_tab_container->set_use_hidden_tabs_for_min_size (true );
831
994
p_tab_container->get_tab_bar ()->connect (SceneStringName (gui_input), callable_mp (this , &EditorDockManager::_dock_container_gui_input).bind (p_tab_container));
832
995
p_tab_container->hide ();
996
+
997
+ // Create dock dragging hint.
998
+ dock_drag_rects[p_dock_slot] = memnew (EditorDockDragHint);
999
+ dock_drag_rects[p_dock_slot]->set_slot (p_dock_slot);
1000
+ dock_drag_rects[p_dock_slot]->hide ();
1001
+ EditorNode::get_singleton ()->get_gui_base ()->add_child (dock_drag_rects[p_dock_slot]);
833
1002
}
834
1003
835
1004
int EditorDockManager::get_vsplit_count () const {
@@ -854,6 +1023,9 @@ EditorDockManager::EditorDockManager() {
854
1023
EditorNode::get_singleton ()->get_gui_base ()->connect (SceneStringName (theme_changed), callable_mp (this , &EditorDockManager::update_docks_menu));
855
1024
}
856
1025
1026
+ // //////////////////////////////////////////////
1027
+ // //////////////////////////////////////////////
1028
+
857
1029
void DockContextPopup::_notification (int p_what) {
858
1030
switch (p_what) {
859
1031
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
0 commit comments