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,119 @@ 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
+ if (mouse_inside_tabbar) {
87
+ queue_redraw ();
88
+ }
89
+ mouse_inside_tabbar = drop_tabbar->get_rect ().has_point (pos);
90
+ }
91
+ }
92
+
93
+ void EditorDockDragHint::set_slot (EditorDockManager::DockSlot p_slot) {
94
+ occupied_slot = p_slot;
95
+ drop_tabbar = dock_manager->dock_slot [occupied_slot]->get_tab_bar ();
96
+ }
97
+
98
+ void EditorDockDragHint::_notification (int p_what) {
99
+ switch (p_what) {
100
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
101
+ if (EditorSettings::get_singleton ()->check_changed_settings_in_group (" interface/theme" )) {
102
+ dock_drop_highlight->set_corner_radius_all (EDSCALE * EDITOR_GET (" interface/theme/corner_radius" ).operator int ());
103
+ if (is_visible_in_tree ()) {
104
+ queue_redraw ();
105
+ }
106
+ }
107
+ } break ;
108
+
109
+ case NOTIFICATION_THEME_CHANGED: {
110
+ valid_drop_color = get_theme_color (SNAME (" accent_color" ), EditorStringName (Editor));
111
+ invalid_drop_color = get_theme_color (SNAME (" error_color" ), EditorStringName (Editor));
112
+ dock_drop_highlight->set_bg_color (valid_drop_color * Color (1 , 1 , 1 , 0.1 ));
113
+ } break ;
114
+
115
+ case NOTIFICATION_MOUSE_ENTER:
116
+ case NOTIFICATION_MOUSE_EXIT: {
117
+ bool new_mouse_inside = p_what == NOTIFICATION_MOUSE_ENTER;
118
+ if (new_mouse_inside != mouse_inside) {
119
+ mouse_inside = new_mouse_inside;
120
+ queue_redraw ();
121
+ }
122
+ } break ;
123
+
124
+ case NOTIFICATION_DRAG_BEGIN: {
125
+ Control *dragged_dock = dock_manager->_get_dock_tab_dragged ();
126
+ if (!dragged_dock) {
127
+ return ;
128
+ }
129
+
130
+ // TODO: Update logic when GH-106503 is merged to use flags.
131
+ can_drop_dock = is_layout_horizontal ? bool (dragged_dock->call (" _can_dock_horizontal" )) : true ;
132
+ dock_drop_highlight->set_border_color (can_drop_dock ? valid_drop_color : invalid_drop_color);
133
+ } break ;
134
+ case NOTIFICATION_DRAG_END: {
135
+ dock_manager->_dock_drag_stopped ();
136
+ can_drop_dock = false ;
137
+ hide ();
138
+ } break ;
139
+
140
+ case NOTIFICATION_DRAW: {
141
+ // Draw highlights around docks that can be dropped.
142
+ if (mouse_inside) {
143
+ Rect2 dock_rect = Rect2 (Point2 (), get_size ()).grow (2 * EDSCALE);
144
+ draw_style_box (dock_drop_highlight, dock_rect);
145
+
146
+ // Only display hint if the mouse is over the tabbar.
147
+ if (!drop_tabbar->get_global_rect ().has_point (get_global_mouse_position ())) {
148
+ return ;
149
+ }
150
+
151
+ drop_tabbar->_draw_tab_drop (get_canvas_item ());
152
+ }
153
+ } break ;
154
+ }
155
+ }
156
+
157
+ EditorDockDragHint::EditorDockDragHint () {
158
+ dock_manager = EditorDockManager::get_singleton ();
159
+
160
+ set_as_top_level (true );
161
+ dock_drop_highlight.instantiate ();
162
+ dock_drop_highlight->set_corner_radius_all (EDSCALE * EDITOR_GET (" interface/theme/corner_radius" ).operator int ());
163
+ dock_drop_highlight->set_border_width_all (Math::round (2 * EDSCALE));
164
+ }
165
+
166
+ // //////////////////////////////////////////////
167
+ // //////////////////////////////////////////////
168
+
55
169
void DockSplitContainer::_update_visibility () {
56
170
if (is_updating) {
57
171
return ;
@@ -114,6 +228,56 @@ void DockSplitContainer::remove_child_notify(Node *p_child) {
114
228
_update_visibility ();
115
229
}
116
230
231
+ // //////////////////////////////////////////////
232
+ // //////////////////////////////////////////////
233
+
234
+ Control *EditorDockManager::_get_dock_tab_dragged () {
235
+ if (dock_tab_dragged) {
236
+ return dock_tab_dragged;
237
+ }
238
+
239
+ Dictionary dock_drop_data = dock_slot[DOCK_SLOT_LEFT_BL]->get_viewport ()->gui_get_drag_data ();
240
+
241
+ // Check if we are dragging a dock.
242
+ const String type = dock_drop_data.get (" type" , " " );
243
+ if (type == " tab_container_tab" ) {
244
+ Node *from_node = dock_slot[DOCK_SLOT_LEFT_BL]->get_node (dock_drop_data[" from_path" ]);
245
+ if (!from_node) {
246
+ return nullptr ;
247
+ }
248
+
249
+ TabContainer *parent = Object::cast_to<TabContainer>(from_node->get_parent ());
250
+ if (!parent) {
251
+ return nullptr ;
252
+ }
253
+
254
+ // TODO: Update logic when GH-106503 is merged to cast to EditorDock.
255
+ for (int i = 0 ; i < DOCK_SLOT_MAX; i++) {
256
+ if (dock_slot[i] == parent) {
257
+ dock_tab_dragged = parent->get_tab_control (dock_drop_data[" tab_index" ]);
258
+ break ;
259
+ }
260
+ }
261
+ if (!dock_tab_dragged) {
262
+ return nullptr ;
263
+ }
264
+
265
+ for (int i = 0 ; i < DOCK_SLOT_MAX; i++) {
266
+ if (dock_slot[i]->is_visible_in_tree ()) {
267
+ dock_drag_rects[i]->set_rect (dock_slot[i]->get_global_rect ());
268
+ dock_drag_rects[i]->show ();
269
+ }
270
+ }
271
+
272
+ return dock_tab_dragged;
273
+ }
274
+ return nullptr ;
275
+ }
276
+
277
+ void EditorDockManager::_dock_drag_stopped () {
278
+ dock_tab_dragged = nullptr ;
279
+ }
280
+
117
281
void EditorDockManager::_dock_split_dragged (int p_offset) {
118
282
EditorNode::get_singleton ()->save_editor_layout_delayed ();
119
283
}
@@ -830,6 +994,12 @@ void EditorDockManager::register_dock_slot(DockSlot p_dock_slot, TabContainer *p
830
994
p_tab_container->set_use_hidden_tabs_for_min_size (true );
831
995
p_tab_container->get_tab_bar ()->connect (SceneStringName (gui_input), callable_mp (this , &EditorDockManager::_dock_container_gui_input).bind (p_tab_container));
832
996
p_tab_container->hide ();
997
+
998
+ // Create dock dragging hint.
999
+ dock_drag_rects[p_dock_slot] = memnew (EditorDockDragHint);
1000
+ dock_drag_rects[p_dock_slot]->set_slot (p_dock_slot);
1001
+ dock_drag_rects[p_dock_slot]->hide ();
1002
+ EditorNode::get_singleton ()->get_gui_base ()->add_child (dock_drag_rects[p_dock_slot]);
833
1003
}
834
1004
835
1005
int EditorDockManager::get_vsplit_count () const {
@@ -854,6 +1024,9 @@ EditorDockManager::EditorDockManager() {
854
1024
EditorNode::get_singleton ()->get_gui_base ()->connect (SceneStringName (theme_changed), callable_mp (this , &EditorDockManager::update_docks_menu));
855
1025
}
856
1026
1027
+ // //////////////////////////////////////////////
1028
+ // //////////////////////////////////////////////
1029
+
857
1030
void DockContextPopup::_notification (int p_what) {
858
1031
switch (p_what) {
859
1032
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
0 commit comments