1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-13 13:31:48 +00:00

Add dock dragging area and highlight

This commit is contained in:
Logan Detrick
2025-05-23 15:42:54 -07:00
parent 5dd76968d8
commit 0413297f7f
4 changed files with 252 additions and 37 deletions

View File

@@ -43,6 +43,7 @@
#include "editor/gui/editor_bottom_panel.h"
#include "editor/themes/editor_scale.h"
#include "editor/window_wrapper.h"
#include "scene/resources/style_box_flat.h"
enum class TabStyle {
TEXT_ONLY,
@@ -52,6 +53,115 @@ enum class TabStyle {
EditorDockManager *EditorDockManager::singleton = nullptr;
bool EditorDockDragHint::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
return can_drop_dock;
}
void EditorDockDragHint::drop_data(const Point2 &p_point, const Variant &p_data) {
// Drop dock into last spot if not over tabbar.
if (drop_tabbar->get_rect().has_point(p_point)) {
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));
} else {
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_manager->dock_slot[occupied_slot], drop_tabbar->get_tab_count());
}
}
void EditorDockDragHint::_drag_move_tab(int p_from_index, int p_to_index) {
dock_manager->_move_dock_tab_index(dock_manager->_get_dock_tab_dragged(), p_to_index, true);
}
void EditorDockDragHint::_drag_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) {
dock_manager->_move_dock(dock_manager->_get_dock_tab_dragged(), dock_manager->dock_slot[occupied_slot], p_to_index);
}
void EditorDockDragHint::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
Point2 pos = mm->get_position();
// Redraw when inside the tabbar and just exited.
if (mouse_inside_tabbar) {
queue_redraw();
}
mouse_inside_tabbar = drop_tabbar->get_rect().has_point(pos);
}
}
void EditorDockDragHint::set_slot(EditorDockManager::DockSlot p_slot) {
occupied_slot = p_slot;
drop_tabbar = dock_manager->dock_slot[occupied_slot]->get_tab_bar();
}
void EditorDockDragHint::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/theme")) {
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
if (mouse_inside) {
queue_redraw();
}
}
} break;
case NOTIFICATION_THEME_CHANGED: {
valid_drop_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
} break;
case NOTIFICATION_MOUSE_ENTER:
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = p_what == NOTIFICATION_MOUSE_ENTER;
queue_redraw();
} break;
case NOTIFICATION_DRAG_BEGIN: {
Control *dragged_dock = dock_manager->_get_dock_tab_dragged();
if (!dragged_dock) {
return;
}
can_drop_dock = true;
dock_drop_highlight->set_border_color(valid_drop_color);
dock_drop_highlight->set_bg_color(valid_drop_color * Color(1, 1, 1, 0.1));
} break;
case NOTIFICATION_DRAG_END: {
dock_manager->_dock_drag_stopped();
can_drop_dock = false;
mouse_inside = false;
hide();
} break;
case NOTIFICATION_DRAW: {
if (!mouse_inside) {
return;
}
// Draw highlights around docks that can be dropped.
Rect2 dock_rect = Rect2(Point2(), get_size()).grow(2 * EDSCALE);
draw_style_box(dock_drop_highlight, dock_rect);
// Only display tabbar hint if the mouse is over the tabbar.
if (drop_tabbar->get_global_rect().has_point(get_global_mouse_position())) {
drop_tabbar->_draw_tab_drop(get_canvas_item());
}
} break;
}
}
EditorDockDragHint::EditorDockDragHint() {
dock_manager = EditorDockManager::get_singleton();
set_as_top_level(true);
dock_drop_highlight.instantiate();
dock_drop_highlight->set_corner_radius_all(EDSCALE * EDITOR_GET("interface/theme/corner_radius").operator int());
dock_drop_highlight->set_border_width_all(Math::round(2 * EDSCALE));
}
////////////////////////////////////////////////
////////////////////////////////////////////////
void DockSplitContainer::_update_visibility() {
if (is_updating) {
return;
@@ -120,6 +230,56 @@ DockSplitContainer::DockSplitContainer() {
}
}
////////////////////////////////////////////////
////////////////////////////////////////////////
Control *EditorDockManager::_get_dock_tab_dragged() {
if (dock_tab_dragged) {
return dock_tab_dragged;
}
Dictionary dock_drop_data = dock_slot[DOCK_SLOT_LEFT_BL]->get_viewport()->gui_get_drag_data();
// Check if we are dragging a dock.
const String type = dock_drop_data.get("type", "");
if (type == "tab_container_tab") {
Node *from_node = dock_slot[DOCK_SLOT_LEFT_BL]->get_node(dock_drop_data["from_path"]);
if (!from_node) {
return nullptr;
}
TabContainer *parent = Object::cast_to<TabContainer>(from_node->get_parent());
if (!parent) {
return nullptr;
}
// TODO: Update logic when GH-106503 is merged to cast directly to EditorDock instead of the below check.
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
if (dock_slot[i] == parent) {
dock_tab_dragged = parent->get_tab_control(dock_drop_data["tab_index"]);
break;
}
}
if (!dock_tab_dragged) {
return nullptr;
}
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
if (dock_slot[i]->is_visible_in_tree()) {
dock_drag_rects[i]->set_rect(dock_slot[i]->get_global_rect());
dock_drag_rects[i]->show();
}
}
return dock_tab_dragged;
}
return nullptr;
}
void EditorDockManager::_dock_drag_stopped() {
dock_tab_dragged = nullptr;
}
void EditorDockManager::_dock_split_dragged(int p_offset) {
EditorNode::get_singleton()->save_editor_layout_delayed();
}
@@ -836,6 +996,12 @@ void EditorDockManager::register_dock_slot(DockSlot p_dock_slot, TabContainer *p
p_tab_container->set_use_hidden_tabs_for_min_size(true);
p_tab_container->get_tab_bar()->connect(SceneStringName(gui_input), callable_mp(this, &EditorDockManager::_dock_container_gui_input).bind(p_tab_container));
p_tab_container->hide();
// Create dock dragging hint.
dock_drag_rects[p_dock_slot] = memnew(EditorDockDragHint);
dock_drag_rects[p_dock_slot]->set_slot(p_dock_slot);
dock_drag_rects[p_dock_slot]->hide();
EditorNode::get_singleton()->get_gui_base()->add_child(dock_drag_rects[p_dock_slot]);
}
int EditorDockManager::get_vsplit_count() const {
@@ -860,6 +1026,9 @@ EditorDockManager::EditorDockManager() {
EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorDockManager::update_docks_menu));
}
////////////////////////////////////////////////
////////////////////////////////////////////////
void DockContextPopup::_notification(int p_what) {
switch (p_what) {
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: