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