Rework editor docks

This commit is contained in:
kobewi 2025-05-16 21:44:43 +02:00
parent 9283328fe7
commit 97b398cba1
26 changed files with 806 additions and 387 deletions

View file

@ -37,6 +37,7 @@
#include "scene/gui/tab_container.h"
#include "scene/main/window.h"
#include "editor/docks/editor_dock.h"
#include "editor/editor_node.h"
#include "editor/editor_string_names.h"
#include "editor/gui/editor_bottom_panel.h"
@ -51,7 +52,13 @@ enum class TabStyle {
TEXT_AND_ICON,
};
EditorDockManager *EditorDockManager::singleton = nullptr;
static inline Ref<Texture2D> _get_dock_icon(const EditorDock *p_dock, const Callable &p_icon_fetch) {
Ref<Texture2D> icon = p_dock->get_dock_icon();
if (icon.is_null() && !p_dock->get_icon_name().is_empty()) {
icon = p_icon_fetch.call(p_dock->get_icon_name());
}
return icon;
}
bool EditorDockDragHint::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
return can_drop_dock;
@ -233,7 +240,7 @@ DockSplitContainer::DockSplitContainer() {
////////////////////////////////////////////////
////////////////////////////////////////////////
Control *EditorDockManager::_get_dock_tab_dragged() {
EditorDock *EditorDockManager::_get_dock_tab_dragged() {
if (dock_tab_dragged) {
return dock_tab_dragged;
}
@ -243,23 +250,17 @@ Control *EditorDockManager::_get_dock_tab_dragged() {
// 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) {
Node *source_tab_bar = EditorNode::get_singleton()->get_node(dock_drop_data["from_path"]);
if (!source_tab_bar) {
return nullptr;
}
TabContainer *parent = Object::cast_to<TabContainer>(from_node->get_parent());
if (!parent) {
TabContainer *source_tab_container = Object::cast_to<TabContainer>(source_tab_bar->get_parent());
if (!source_tab_container) {
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;
}
}
dock_tab_dragged = Object::cast_to<EditorDock>(source_tab_container->get_tab_control(dock_drop_data["tab_index"]));
if (!dock_tab_dragged) {
return nullptr;
}
@ -294,13 +295,13 @@ void EditorDockManager::_dock_container_gui_input(const Ref<InputEvent> &p_input
}
// Right click context menu.
dock_context_popup->set_dock(p_dock_container->get_tab_control(tab_id));
dock_context_popup->set_dock(Object::cast_to<EditorDock>(p_dock_container->get_tab_control(tab_id)));
dock_context_popup->set_position(p_dock_container->get_screen_position() + mb->get_position());
dock_context_popup->popup();
}
}
void EditorDockManager::_bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, Control *p_dock, Button *p_bottom_button) {
void EditorDockManager::_bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, EditorDock *p_dock, Button *p_bottom_button) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
@ -337,38 +338,42 @@ void EditorDockManager::update_docks_menu() {
bool global_menu = !bool(EDITOR_GET("interface/editor/use_embedded_menu")) && NativeMenu::get_singleton()->has_feature(NativeMenu::FEATURE_GLOBAL_MENU);
bool dark_mode = DisplayServer::get_singleton()->is_dark_mode_supported() && DisplayServer::get_singleton()->is_dark_mode();
int icon_max_width = EditorNode::get_singleton()->get_editor_theme()->get_constant(SNAME("class_icon_size"), EditorStringName(Editor));
// Add docks.
docks_menu_docks.clear();
int id = 0;
for (const KeyValue<Control *, DockInfo> &dock : all_docks) {
if (!dock.value.enabled) {
const Callable icon_fetch = callable_mp((Window *)docks_menu, &Window::get_editor_theme_native_menu_icon).bind(global_menu, dark_mode);
for (EditorDock *dock : all_docks) {
if (!dock->enabled) {
continue;
}
if (dock.value.shortcut.is_valid()) {
docks_menu->add_shortcut(dock.value.shortcut, id);
docks_menu->set_item_text(id, dock.value.title);
if (dock->shortcut.is_valid()) {
docks_menu->add_shortcut(dock->shortcut, id);
docks_menu->set_item_text(id, dock->get_display_title());
} else {
docks_menu->add_item(dock.value.title, id);
docks_menu->add_item(dock->get_display_title(), id);
}
const Ref<Texture2D> icon = dock.value.icon_name ? docks_menu->get_editor_theme_native_menu_icon(dock.value.icon_name, global_menu, dark_mode) : dock.value.icon;
docks_menu->set_item_icon_max_width(id, icon_max_width);
const Ref<Texture2D> icon = _get_dock_icon(dock, icon_fetch);
docks_menu->set_item_icon(id, icon.is_valid() ? icon : default_icon);
if (!dock.value.open) {
if (!dock->open) {
docks_menu->set_item_icon_modulate(id, closed_icon_color_mod);
docks_menu->set_item_tooltip(id, vformat(TTR("Open the %s dock."), dock.value.title));
docks_menu->set_item_tooltip(id, vformat(TTR("Open the %s dock."), dock->get_display_title()));
} else {
docks_menu->set_item_tooltip(id, vformat(TTR("Focus on the %s dock."), dock.value.title));
docks_menu->set_item_tooltip(id, vformat(TTR("Focus on the %s dock."), dock->get_display_title()));
}
docks_menu_docks.push_back(dock.key);
docks_menu_docks.push_back(dock);
id++;
}
}
void EditorDockManager::_docks_menu_option(int p_id) {
Control *dock = docks_menu_docks[p_id];
EditorDock *dock = docks_menu_docks[p_id];
ERR_FAIL_NULL(dock);
ERR_FAIL_COND_MSG(!all_docks.has(dock), vformat("Menu option for unknown dock '%s'.", dock->get_name()));
if (all_docks[dock].enabled && all_docks[dock].open) {
ERR_FAIL_COND_MSG(!all_docks.has(dock), vformat("Menu option for unknown dock '%s'.", dock->get_display_title()));
if (dock->enabled && dock->open) {
PopupMenu *parent_menu = Object::cast_to<PopupMenu>(docks_menu->get_parent());
ERR_FAIL_NULL(parent_menu);
parent_menu->hide();
@ -378,11 +383,11 @@ void EditorDockManager::_docks_menu_option(int p_id) {
void EditorDockManager::_window_close_request(WindowWrapper *p_wrapper) {
// Give the dock back to the original owner.
Control *dock = _close_window(p_wrapper);
EditorDock *dock = _close_window(p_wrapper);
ERR_FAIL_COND(!all_docks.has(dock));
if (all_docks[dock].previous_at_bottom || all_docks[dock].dock_slot_index != DOCK_SLOT_NONE) {
all_docks[dock].open = false;
if (dock->previous_at_bottom || dock->dock_slot_index != DOCK_SLOT_NONE) {
dock->open = false;
open_dock(dock);
focus_dock(dock);
} else {
@ -390,19 +395,19 @@ void EditorDockManager::_window_close_request(WindowWrapper *p_wrapper) {
}
}
Control *EditorDockManager::_close_window(WindowWrapper *p_wrapper) {
EditorDock *EditorDockManager::_close_window(WindowWrapper *p_wrapper) {
p_wrapper->set_block_signals(true);
Control *dock = p_wrapper->release_wrapped_control();
EditorDock *dock = Object::cast_to<EditorDock>(p_wrapper->release_wrapped_control());
p_wrapper->set_block_signals(false);
ERR_FAIL_COND_V(!all_docks.has(dock), nullptr);
all_docks[dock].dock_window = nullptr;
dock->dock_window = nullptr;
dock_windows.erase(p_wrapper);
p_wrapper->queue_free();
return dock;
}
void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window, bool p_reset_size) {
void EditorDockManager::_open_dock_in_window(EditorDock *p_dock, bool p_show_window, bool p_reset_size) {
ERR_FAIL_NULL(p_dock);
Size2 borders = Size2(4, 4) * EDSCALE;
@ -411,7 +416,7 @@ void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window
Point2 dock_screen_pos = p_dock->get_screen_position();
WindowWrapper *wrapper = memnew(WindowWrapper);
wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), all_docks[p_dock].title));
wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), p_dock->get_display_title()));
wrapper->set_margins_enabled(true);
EditorNode::get_singleton()->get_gui_base()->add_child(wrapper);
@ -419,8 +424,8 @@ void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window
_move_dock(p_dock, nullptr);
wrapper->set_wrapped_control(p_dock);
all_docks[p_dock].dock_window = wrapper;
all_docks[p_dock].open = true;
p_dock->dock_window = wrapper;
p_dock->open = true;
p_dock->show();
wrapper->connect("window_close_requested", callable_mp(this, &EditorDockManager::_window_close_request).bind(wrapper));
@ -439,45 +444,44 @@ void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window
}
}
void EditorDockManager::_restore_dock_to_saved_window(Control *p_dock, const Dictionary &p_window_dump) {
if (!all_docks[p_dock].dock_window) {
void EditorDockManager::_restore_dock_to_saved_window(EditorDock *p_dock, const Dictionary &p_window_dump) {
if (!p_dock->dock_window) {
_open_dock_in_window(p_dock, false);
}
all_docks[p_dock].dock_window->restore_window_from_saved_position(
p_dock->dock_window->restore_window_from_saved_position(
p_window_dump.get("window_rect", Rect2i()),
p_window_dump.get("window_screen", -1),
p_window_dump.get("window_screen_rect", Rect2i()));
}
void EditorDockManager::_dock_move_to_bottom(Control *p_dock, bool p_visible) {
void EditorDockManager::_dock_move_to_bottom(EditorDock *p_dock, bool p_visible) {
_move_dock(p_dock, nullptr);
all_docks[p_dock].at_bottom = true;
all_docks[p_dock].previous_at_bottom = false;
p_dock->call("_set_dock_horizontal", true);
p_dock->at_bottom = true;
p_dock->previous_at_bottom = false;
p_dock->update_layout(EditorDock::DOCK_LAYOUT_HORIZONTAL);
// Force docks moved to the bottom to appear first in the list, and give them their associated shortcut to toggle their bottom panel.
Button *bottom_button = EditorNode::get_bottom_panel()->add_item(all_docks[p_dock].title, p_dock, all_docks[p_dock].shortcut, true);
Button *bottom_button = EditorNode::get_bottom_panel()->add_item(p_dock->get_display_title(), p_dock, p_dock->shortcut, true);
bottom_button->connect(SceneStringName(gui_input), callable_mp(this, &EditorDockManager::_bottom_dock_button_gui_input).bind(bottom_button).bind(p_dock));
EditorNode::get_bottom_panel()->make_item_visible(p_dock, p_visible);
}
void EditorDockManager::_dock_remove_from_bottom(Control *p_dock) {
all_docks[p_dock].at_bottom = false;
all_docks[p_dock].previous_at_bottom = true;
void EditorDockManager::_dock_remove_from_bottom(EditorDock *p_dock) {
p_dock->at_bottom = false;
p_dock->previous_at_bottom = true;
EditorNode::get_bottom_panel()->remove_item(p_dock);
p_dock->call("_set_dock_horizontal", false);
p_dock->update_layout(EditorDock::DOCK_LAYOUT_VERTICAL);
}
bool EditorDockManager::_is_dock_at_bottom(Control *p_dock) {
bool EditorDockManager::_is_dock_at_bottom(EditorDock *p_dock) {
ERR_FAIL_COND_V(!all_docks.has(p_dock), false);
return all_docks[p_dock].at_bottom;
return p_dock->at_bottom;
}
void EditorDockManager::_move_dock_tab_index(Control *p_dock, int p_tab_index, bool p_set_current) {
void EditorDockManager::_move_dock_tab_index(EditorDock *p_dock, int p_tab_index, bool p_set_current) {
TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_dock->get_parent());
if (!dock_tab_container) {
return;
@ -486,7 +490,7 @@ void EditorDockManager::_move_dock_tab_index(Control *p_dock, int p_tab_index, b
dock_tab_container->set_block_signals(true);
int target_index = CLAMP(p_tab_index, 0, dock_tab_container->get_tab_count() - 1);
dock_tab_container->move_child(p_dock, dock_tab_container->get_tab_control(target_index)->get_index(false));
all_docks[p_dock].previous_tab_index = target_index;
p_dock->previous_tab_index = target_index;
if (p_set_current) {
dock_tab_container->set_current_tab(target_index);
@ -494,9 +498,9 @@ void EditorDockManager::_move_dock_tab_index(Control *p_dock, int p_tab_index, b
dock_tab_container->set_block_signals(false);
}
void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab_index, bool p_set_current) {
void EditorDockManager::_move_dock(EditorDock *p_dock, Control *p_target, int p_tab_index, bool p_set_current) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot move unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot move unknown dock '%s'.", p_dock->get_display_title()));
Node *parent = p_dock->get_parent();
if (parent == p_target) {
@ -509,15 +513,15 @@ void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab
// Remove dock from its existing parent.
if (parent) {
if (all_docks[p_dock].dock_window) {
_close_window(all_docks[p_dock].dock_window);
} else if (all_docks[p_dock].at_bottom) {
if (p_dock->dock_window) {
_close_window(p_dock->dock_window);
} else if (p_dock->at_bottom) {
_dock_remove_from_bottom(p_dock);
} else {
all_docks[p_dock].previous_at_bottom = false;
p_dock->previous_at_bottom = false;
TabContainer *parent_tabs = Object::cast_to<TabContainer>(parent);
if (parent_tabs) {
all_docks[p_dock].previous_tab_index = parent_tabs->get_tab_idx_from_control(p_dock);
p_dock->previous_tab_index = parent_tabs->get_tab_idx_from_control(p_dock);
}
parent->set_block_signals(true);
parent->remove_child(p_dock);
@ -547,36 +551,35 @@ void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab
}
}
void EditorDockManager::_update_tab_style(Control *p_dock) {
const DockInfo &dock_info = all_docks[p_dock];
if (!dock_info.enabled || !dock_info.open) {
void EditorDockManager::_update_tab_style(EditorDock *p_dock) {
if (!p_dock->enabled || !p_dock->open) {
return; // Disabled by feature profile or manually closed by user.
}
if (dock_info.dock_window || dock_info.at_bottom) {
if (p_dock->dock_window || p_dock->at_bottom) {
return; // Floating or sent to bottom.
}
TabContainer *tab_container = get_dock_tab_container(p_dock);
ERR_FAIL_NULL(tab_container);
int index = tab_container->get_tab_idx_from_control(p_dock);
ERR_FAIL_COND(index == -1);
const TabStyle style = (TabStyle)EDITOR_GET("interface/editor/dock_tab_style").operator int();
const Ref<Texture2D> icon = _get_dock_icon(p_dock, callable_mp((Control *)tab_container, &Control::get_editor_theme_icon));
switch (style) {
case TabStyle::TEXT_ONLY: {
tab_container->set_tab_title(index, dock_info.title);
tab_container->set_tab_title(index, p_dock->get_display_title());
tab_container->set_tab_icon(index, Ref<Texture2D>());
tab_container->set_tab_tooltip(index, String());
} break;
case TabStyle::ICON_ONLY: {
const Ref<Texture2D> icon = dock_info.icon_name ? tab_container->get_editor_theme_icon(dock_info.icon_name) : dock_info.icon;
tab_container->set_tab_title(index, icon.is_valid() ? String() : dock_info.title);
tab_container->set_tab_title(index, icon.is_valid() ? String() : p_dock->get_display_title());
tab_container->set_tab_icon(index, icon);
tab_container->set_tab_tooltip(index, icon.is_valid() ? dock_info.title : String());
tab_container->set_tab_tooltip(index, p_dock->get_display_title());
} break;
case TabStyle::TEXT_AND_ICON: {
const Ref<Texture2D> icon = dock_info.icon_name ? tab_container->get_editor_theme_icon(dock_info.icon_name) : dock_info.icon;
tab_container->set_tab_title(index, dock_info.title);
tab_container->set_tab_title(index, p_dock->get_display_title());
tab_container->set_tab_icon(index, icon);
tab_container->set_tab_tooltip(index, String());
} break;
@ -588,7 +591,7 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
String names;
for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) {
String name = dock_slot[i]->get_tab_control(j)->get_name();
String name = Object::cast_to<EditorDock>(dock_slot[i]->get_tab_control(j))->get_effective_layout_key();
if (!names.is_empty()) {
names += ",";
}
@ -618,7 +621,7 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
// Save docks in windows.
Dictionary floating_docks_dump;
for (WindowWrapper *wrapper : dock_windows) {
Control *dock = wrapper->get_wrapped_control();
EditorDock *dock = Object::cast_to<EditorDock>(wrapper->get_wrapped_control());
Dictionary window_dump;
window_dump["window_rect"] = wrapper->get_window_rect();
@ -627,11 +630,11 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
window_dump["window_screen"] = wrapper->get_window_screen();
window_dump["window_screen_rect"] = DisplayServer::get_singleton()->screen_get_usable_rect(screen);
String name = dock->get_name();
String name = dock->get_effective_layout_key();
floating_docks_dump[name] = window_dump;
// Append to regular dock section so we know where to restore it to.
int dock_slot_id = all_docks[dock].dock_slot_index;
int dock_slot_id = dock->dock_slot_index;
String config_key = "dock_" + itos(dock_slot_id + 1);
String names = p_layout->get_value(p_section, config_key, "");
@ -647,22 +650,23 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str
// Save closed and bottom docks.
Array bottom_docks_dump;
Array closed_docks_dump;
for (const KeyValue<Control *, DockInfo> &d : all_docks) {
d.key->call(SNAME("_save_layout_to_config"), p_layout, p_section);
for (const EditorDock *dock : all_docks) {
const String section_name = p_section + "/" + dock->get_effective_layout_key();
dock->save_layout_to_config(p_layout, section_name);
if (!d.value.at_bottom && d.value.open && (!d.value.previous_at_bottom || !d.value.dock_window)) {
if (!dock->at_bottom && dock->open && (!dock->previous_at_bottom || !dock->dock_window)) {
continue;
}
// Use the name of the Control since it isn't translated.
String name = d.key->get_name();
if (d.value.at_bottom || (d.value.previous_at_bottom && d.value.dock_window)) {
const String name = dock->get_effective_layout_key();
if (dock->at_bottom || (dock->previous_at_bottom && dock->dock_window)) {
bottom_docks_dump.push_back(name);
}
if (!d.value.open) {
if (!dock->open) {
closed_docks_dump.push_back(name);
}
int dock_slot_id = all_docks[d.key].dock_slot_index;
int dock_slot_id = dock->dock_slot_index;
String config_key = "dock_" + itos(dock_slot_id + 1);
String names = p_layout->get_value(p_section, config_key, "");
@ -696,9 +700,9 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
bool allow_floating_docks = EditorNode::get_singleton()->is_multi_window_enabled() && (!p_first_load || EDITOR_GET("interface/multi_window/restore_windows_on_load"));
// Store the docks by name for easy lookup.
HashMap<String, Control *> dock_map;
for (const KeyValue<Control *, DockInfo> &dock : all_docks) {
dock_map[dock.key->get_name()] = dock.key;
HashMap<String, EditorDock *> dock_map;
for (EditorDock *dock : all_docks) {
dock_map[dock->get_effective_layout_key()] = dock;
}
// Load docks by slot. Index -1 is for docks that have no slot.
@ -710,21 +714,22 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
Vector<String> names = String(p_layout->get_value(p_section, "dock_" + itos(i + 1))).split(",");
for (int j = names.size() - 1; j >= 0; j--) {
String name = names[j];
const String &name = names[j];
const String section_name = p_section + "/" + name;
if (!dock_map.has(name)) {
continue;
}
Control *dock = dock_map[name];
EditorDock *dock = dock_map[name];
if (!all_docks[dock].enabled) {
if (!dock->enabled) {
// Don't open disabled docks.
dock->call(SNAME("_load_layout_from_config"), p_layout, p_section);
dock->load_layout_from_config(p_layout, section_name);
continue;
}
bool at_bottom = false;
if (allow_floating_docks && floating_docks_dump.has(name)) {
all_docks[dock].previous_at_bottom = dock_bottom.has(name);
dock->previous_at_bottom = dock_bottom.has(name);
_restore_dock_to_saved_window(dock, floating_docks_dump[name]);
} else if (dock_bottom.has(name)) {
_dock_move_to_bottom(dock, false);
@ -732,15 +737,15 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
} else if (i >= 0) {
_move_dock(dock, dock_slot[i], 0);
}
dock->call(SNAME("_load_layout_from_config"), p_layout, p_section);
dock->load_layout_from_config(p_layout, section_name);
if (closed_docks.has(name)) {
_move_dock(dock, closed_dock_parent);
all_docks[dock].open = false;
dock->open = false;
dock->hide();
} else {
// Make sure it is open.
all_docks[dock].open = true;
dock->open = true;
// It's important to not update the visibility of bottom panels.
// Visibility of bottom panels are managed in EditorBottomPanel.
if (!at_bottom) {
@ -748,8 +753,8 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
}
}
all_docks[dock].dock_slot_index = i;
all_docks[dock].previous_tab_index = i >= 0 ? j : 0;
dock->dock_slot_index = i;
dock->previous_tab_index = i >= 0 ? j : 0;
}
}
@ -785,7 +790,7 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S
update_docks_menu();
}
void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock) {
void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, EditorDock *p_dock) {
ERR_FAIL_COND(!all_docks.has(p_dock));
dock_context_popup->set_dock(p_dock);
@ -801,15 +806,15 @@ void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_positio
dock_context_popup->popup();
}
void EditorDockManager::set_dock_enabled(Control *p_dock, bool p_enabled) {
void EditorDockManager::set_dock_enabled(EditorDock *p_dock, bool p_enabled) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot set enabled unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot set enabled unknown dock '%s'.", p_dock->get_display_title()));
if (all_docks[p_dock].enabled == p_enabled) {
if (p_dock->enabled == p_enabled) {
return;
}
all_docks[p_dock].enabled = p_enabled;
p_dock->enabled = p_enabled;
if (p_enabled) {
open_dock(p_dock, false);
} else {
@ -817,39 +822,39 @@ void EditorDockManager::set_dock_enabled(Control *p_dock, bool p_enabled) {
}
}
void EditorDockManager::close_dock(Control *p_dock) {
void EditorDockManager::close_dock(EditorDock *p_dock) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot close unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot close unknown dock '%s'.", p_dock->get_display_title()));
if (!all_docks[p_dock].open) {
if (!p_dock->open) {
return;
}
_move_dock(p_dock, closed_dock_parent);
all_docks[p_dock].open = false;
p_dock->open = false;
p_dock->hide();
_update_layout();
}
void EditorDockManager::open_dock(Control *p_dock, bool p_set_current) {
void EditorDockManager::open_dock(EditorDock *p_dock, bool p_set_current) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot open unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot open unknown dock '%s'.", p_dock->get_display_title()));
if (all_docks[p_dock].open) {
if (p_dock->open) {
return;
}
all_docks[p_dock].open = true;
p_dock->open = true;
p_dock->show();
// Open dock to its previous location.
if (all_docks[p_dock].previous_at_bottom) {
if (p_dock->previous_at_bottom) {
_dock_move_to_bottom(p_dock, true);
} else if (all_docks[p_dock].dock_slot_index != DOCK_SLOT_NONE) {
TabContainer *slot = dock_slot[all_docks[p_dock].dock_slot_index];
int tab_index = all_docks[p_dock].previous_tab_index;
} else if (p_dock->dock_slot_index != DOCK_SLOT_NONE) {
TabContainer *slot = dock_slot[p_dock->dock_slot_index];
int tab_index = p_dock->previous_tab_index;
if (tab_index < 0) {
tab_index = slot->get_tab_count();
}
@ -866,24 +871,24 @@ TabContainer *EditorDockManager::get_dock_tab_container(Control *p_dock) const {
return Object::cast_to<TabContainer>(p_dock->get_parent());
}
void EditorDockManager::focus_dock(Control *p_dock) {
void EditorDockManager::focus_dock(EditorDock *p_dock) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot focus unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot focus unknown dock '%s'.", p_dock->get_display_title()));
if (!all_docks[p_dock].enabled) {
if (!p_dock->enabled) {
return;
}
if (!all_docks[p_dock].open) {
if (!p_dock->open) {
open_dock(p_dock);
}
if (all_docks[p_dock].dock_window) {
if (p_dock->dock_window) {
p_dock->get_window()->grab_focus();
return;
}
if (all_docks[p_dock].at_bottom) {
if (p_dock->at_bottom) {
EditorNode::get_bottom_panel()->make_item_visible(p_dock, true, true);
return;
}
@ -901,19 +906,16 @@ void EditorDockManager::focus_dock(Control *p_dock) {
tab_container->set_current_tab(tab_index);
}
void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref<Shortcut> &p_shortcut, const StringName &p_icon_name) {
void EditorDockManager::add_dock(EditorDock *p_dock) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(all_docks.has(p_dock), vformat("Cannot add dock '%s', already added.", p_dock->get_name()));
ERR_FAIL_COND_MSG(all_docks.has(p_dock), vformat("Cannot add dock '%s', already added.", p_dock->get_display_title()));
DockInfo dock_info;
dock_info.title = p_title.is_empty() ? String(p_dock->get_name()) : p_title;
dock_info.dock_slot_index = p_slot;
dock_info.shortcut = p_shortcut;
dock_info.icon_name = p_icon_name;
all_docks[p_dock] = dock_info;
p_dock->dock_slot_index = p_dock->default_slot;
all_docks.push_back(p_dock);
p_dock->connect("tab_style_changed", callable_mp(this, &EditorDockManager::_update_tab_style).bind(p_dock));
p_dock->connect("renamed", callable_mp(this, &EditorDockManager::_update_tab_style).bind(p_dock));
if (p_slot != DOCK_SLOT_NONE) {
ERR_FAIL_INDEX(p_slot, DOCK_SLOT_MAX);
if (p_dock->default_slot != DOCK_SLOT_NONE) {
open_dock(p_dock, false);
} else {
closed_dock_parent->add_child(p_dock);
@ -922,24 +924,18 @@ void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlo
}
}
void EditorDockManager::remove_dock(Control *p_dock) {
void EditorDockManager::remove_dock(EditorDock *p_dock) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot remove unknown dock '%s'.", p_dock->get_name()));
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot remove unknown dock '%s'.", p_dock->get_display_title()));
_move_dock(p_dock, nullptr);
all_docks.erase(p_dock);
p_dock->disconnect("tab_style_changed", callable_mp(this, &EditorDockManager::_update_tab_style));
p_dock->disconnect("renamed", callable_mp(this, &EditorDockManager::_update_tab_style));
_update_layout();
}
void EditorDockManager::set_dock_tab_icon(Control *p_dock, const Ref<Texture2D> &p_icon) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot set tab icon for unknown dock '%s'.", p_dock->get_name()));
all_docks[p_dock].icon = p_icon;
_update_tab_style(p_dock);
}
void EditorDockManager::set_docks_visible(bool p_show) {
if (docks_visible == p_show) {
return;
@ -956,8 +952,8 @@ bool EditorDockManager::are_docks_visible() const {
}
void EditorDockManager::update_tab_styles() {
for (const KeyValue<Control *, DockInfo> &dock : all_docks) {
_update_tab_style(dock.key);
for (EditorDock *dock : all_docks) {
_update_tab_style(dock);
}
}
@ -1125,7 +1121,7 @@ void DockContextPopup::_dock_select_input(const Ref<InputEvent> &p_input) {
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
if (dock_manager->get_dock_tab_container(context_dock) != target_tab_container) {
dock_manager->_move_dock(context_dock, target_tab_container, target_tab_container->get_tab_count());
dock_manager->all_docks[context_dock].dock_slot_index = over_dock_slot;
context_dock->dock_slot_index = over_dock_slot;
dock_manager->_update_layout();
hide();
}
@ -1238,21 +1234,21 @@ void DockContextPopup::_update_buttons() {
tab_move_right_button->set_disabled(context_tab_index >= context_tab_container->get_tab_count() - 1);
}
dock_to_bottom_button->set_visible(!dock_at_bottom && bool(context_dock->call("_can_dock_horizontal")));
dock_to_bottom_button->set_visible(!dock_at_bottom && bool(context_dock->available_layouts & EditorDock::DOCK_LAYOUT_HORIZONTAL));
reset_size();
}
void DockContextPopup::select_current_dock_in_dock_slot(int p_dock_slot) {
context_dock = dock_manager->dock_slot[p_dock_slot]->get_current_tab_control();
context_dock = Object::cast_to<EditorDock>(dock_manager->dock_slot[p_dock_slot]->get_current_tab_control());
_update_buttons();
}
void DockContextPopup::set_dock(Control *p_dock) {
void DockContextPopup::set_dock(EditorDock *p_dock) {
context_dock = p_dock;
_update_buttons();
}
Control *DockContextPopup::get_dock() const {
EditorDock *DockContextPopup::get_dock() const {
return context_dock;
}