diff --git a/doc/classes/EditorDock.xml b/doc/classes/EditorDock.xml new file mode 100644 index 00000000000..5067e79ae8a --- /dev/null +++ b/doc/classes/EditorDock.xml @@ -0,0 +1,100 @@ + + + + Dockable container for the editor. + + + EditorDock is a [Container] node that can be docked in one of the editor's dock slots. Docks are added by plugins to provide space for controls related to an [EditorPlugin]. The editor comes with a few built-in docks, such as the Scene dock, FileSystem dock, etc. + You can add a dock by using [method EditorPlugin.add_dock]. The dock can be customized by changing its properties. + [codeblock] + @tool + extends EditorPlugin + + # Dock reference. + var dock + + # Plugin initialization. + func _enter_tree(): + dock = EditorDock.new() + dock.title = "My Dock" + dock.dock_icon = preload("./dock_icon.png") + dock.default_slot = EditorPlugin.DOCK_SLOT_RIGHT_UL + var dock_content = preload("./dock_content.tscn").instantiate() + dock.add_child(dock_content) + add_dock(dock) + + # Plugin clean-up. + func _exit_tree(): + remove_dock(dock) + dock.queue_free() + dock = null + [/codeblock] + + + $DOCS_URL/tutorials/plugins/editor/making_plugins.html + + + + + + + + Implement this method to handle loading this dock's layout. It's equivalent to [method EditorPlugin._set_window_layout]. [param section] is a unique section based on [member layout_key]. + + + + + + + + Implement this method to handle saving this dock's layout. It's equivalent to [method EditorPlugin._get_window_layout]. [param section] is a unique section based on [member layout_key]. + + + + + + + Implement this method to handle the layout switching for this dock. [param layout] is one of the [enum DockLayout] constants. + [codeblock] + _update_layout(layout): + box_container.vertical = (layout == DOCK_LAYOUT_VERTICAL) + [/codeblock] + + + + + + The available layouts for this dock, as a bitmask. + If you want to make all layouts available, use [code]available_layouts = DOCK_LAYOUT_VERTICAL | DOCK_LAYOUT_HORIZONTAL[/code]. + + + + The default dock slot used when adding the dock with [method EditorPlugin.add_dock]. + After the dock is added, it can be moved to a different slot and the editor will automatically remember its position between sessions. If you remove and re-add the dock, it will be reset to default. + + + The icon for the dock, as a texture. If specified, it will override [member icon_name]. + + + The shortcut used to open the dock. This property can only be set before this dock is added via [method EditorPlugin.add_dock]. + + + The icon for the dock, as a name from the [code]EditorIcons[/code] theme type in the editor theme. You can find the list of available icons [url=https://godot-editor-icons.github.io/]here[/url]. + + + The key representing this dock in the editor's layout file. If empty, the dock's displayed name will be used instead. + + + The title of the dock's tab. If empty, the dock's [member Node.name] will be used. If the name is auto-generated (contains [code]@[/code]), the first child's name will be used instead. + + + + + Allows placing the dock in the vertical dock slots on either side of the editor. + [b]Note:[/b] Currently this flag has no effect because the bottom panel is not a proper dock slot. This means that the dock can always be vertical. + + + Allows placing the dock in the editor's bottom panel. Implement [method _update_layout] to handle changing layouts. + + + diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 9892d208329..6beb4044931 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -430,7 +430,7 @@ When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [method Node.queue_free]. - + @@ -464,6 +464,14 @@ Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin]. + + + + + Adds a new dock. + When your plugin is deactivated, make sure to remove your custom dock with [method remove_dock] and free it with [method Node.queue_free]. + + @@ -655,7 +663,7 @@ Removes the control from the specified container. You have to manually [method Node.queue_free] the control. - + @@ -676,6 +684,13 @@ Removes the debugger plugin with given script from the Debugger. + + + + + Removes [param dock] from the available docks. You should manually call [method Node.queue_free] to free it. + + @@ -753,7 +768,7 @@ Removes a callback previously added by [method add_undo_redo_inspector_hook_callback]. - + @@ -854,6 +869,9 @@ Tab of Project Settings dialog, to the right of other tabs. + + The dock is closed. + Dock slot, left side, upper-left (empty in default layout). diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml index b3dc51ffaa6..b0b23a81c64 100644 --- a/doc/classes/FileSystemDock.xml +++ b/doc/classes/FileSystemDock.xml @@ -1,5 +1,5 @@ - + Godot editor's dock for managing files in the project. diff --git a/editor/docks/editor_dock.cpp b/editor/docks/editor_dock.cpp new file mode 100644 index 00000000000..d231c7639ac --- /dev/null +++ b/editor/docks/editor_dock.cpp @@ -0,0 +1,131 @@ +/**************************************************************************/ +/* editor_dock.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "editor_dock.h" + +#include "core/input/shortcut.h" +#include "core/io/config_file.h" + +void EditorDock::_set_default_slot_bind(EditorPlugin::DockSlot p_slot) { + ERR_FAIL_COND(p_slot < EditorPlugin::DOCK_SLOT_NONE || p_slot >= EditorPlugin::DOCK_SLOT_MAX); + default_slot = (EditorDockManager::DockSlot)p_slot; +} + +void EditorDock::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_title", "title"), &EditorDock::set_title); + ClassDB::bind_method(D_METHOD("get_title"), &EditorDock::get_title); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); + + ClassDB::bind_method(D_METHOD("set_layout_key", "layout_key"), &EditorDock::set_layout_key); + ClassDB::bind_method(D_METHOD("get_layout_key"), &EditorDock::get_layout_key); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "layout_key"), "set_layout_key", "get_layout_key"); + + ClassDB::bind_method(D_METHOD("set_icon_name", "icon_name"), &EditorDock::set_icon_name); + ClassDB::bind_method(D_METHOD("get_icon_name"), &EditorDock::get_icon_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "icon_name"), "set_icon_name", "get_icon_name"); + + ClassDB::bind_method(D_METHOD("set_dock_icon", "icon"), &EditorDock::set_dock_icon); + ClassDB::bind_method(D_METHOD("get_dock_icon"), &EditorDock::get_dock_icon); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "dock_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_dock_icon", "get_dock_icon"); + + ClassDB::bind_method(D_METHOD("set_dock_shortcut", "shortcut"), &EditorDock::set_dock_shortcut); + ClassDB::bind_method(D_METHOD("get_dock_shortcut"), &EditorDock::get_dock_shortcut); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "dock_shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_dock_shortcut", "get_dock_shortcut"); + + ClassDB::bind_method(D_METHOD("set_default_slot", "slot"), &EditorDock::_set_default_slot_bind); + ClassDB::bind_method(D_METHOD("get_default_slot"), &EditorDock::_get_default_slot_bind); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_slot"), "set_default_slot", "get_default_slot"); + + ClassDB::bind_method(D_METHOD("set_available_layouts", "layouts"), &EditorDock::set_available_layouts); + ClassDB::bind_method(D_METHOD("get_available_layouts"), &EditorDock::get_available_layouts); + ADD_PROPERTY(PropertyInfo(Variant::INT, "available_layouts", PROPERTY_HINT_FLAGS, "Vertical:1,Horizontal:2"), "set_available_layouts", "get_available_layouts"); + + BIND_BITFIELD_FLAG(DOCK_LAYOUT_VERTICAL); + BIND_BITFIELD_FLAG(DOCK_LAYOUT_HORIZONTAL); + + GDVIRTUAL_BIND(_update_layout, "layout"); + GDVIRTUAL_BIND(_save_layout_to_config, "config", "section"); + GDVIRTUAL_BIND(_load_layout_from_config, "config", "section"); +} + +EditorDock::EditorDock() { + set_clip_contents(true); + add_user_signal(MethodInfo("tab_style_changed")); +} + +void EditorDock::set_title(const String &p_title) { + if (title == p_title) { + return; + } + title = p_title; + emit_signal("tab_style_changed"); +} + +void EditorDock::set_icon_name(const StringName &p_name) { + if (icon_name == p_name) { + return; + } + icon_name = p_name; + emit_signal("tab_style_changed"); +} + +void EditorDock::set_dock_icon(const Ref &p_icon) { + if (dock_icon == p_icon) { + return; + } + dock_icon = p_icon; + emit_signal("tab_style_changed"); +} + +void EditorDock::set_default_slot(EditorDockManager::DockSlot p_slot) { + ERR_FAIL_INDEX(p_slot, EditorDockManager::DOCK_SLOT_MAX); + default_slot = p_slot; +} + +String EditorDock::get_display_title() const { + if (!title.is_empty()) { + return title; + } + + const String sname = get_name(); + if (sname.contains_char('@')) { + // Auto-generated name, try to use something better. + const Node *child = get_child_count() > 0 ? get_child(0) : nullptr; + if (child) { + // In user plugins, the child will usually be dock's content and have a proper name. + return child->get_name(); + } + } + return sname; +} + +String EditorDock::get_effective_layout_key() const { + return layout_key.is_empty() ? get_display_title() : layout_key; +} diff --git a/editor/docks/editor_dock.h b/editor/docks/editor_dock.h new file mode 100644 index 00000000000..6bd58669d58 --- /dev/null +++ b/editor/docks/editor_dock.h @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* editor_dock.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#pragma once + +#include "editor/docks/editor_dock_manager.h" +#include "editor/plugins/editor_plugin.h" +#include "scene/gui/margin_container.h" + +class ConfigFile; +class Shortcut; +class WindowWrapper; + +class EditorDock : public MarginContainer { + GDCLASS(EditorDock, MarginContainer); + +public: + enum DockLayout { + DOCK_LAYOUT_VERTICAL = 1, + DOCK_LAYOUT_HORIZONTAL = 2, + }; + +private: + friend class EditorDockManager; + friend class DockContextPopup; + + String title; + String layout_key; + StringName icon_name; + Ref dock_icon; + Ref shortcut; + EditorDockManager::DockSlot default_slot = EditorDockManager::DOCK_SLOT_NONE; + + BitField available_layouts = DOCK_LAYOUT_VERTICAL; + + bool open = false; + bool enabled = true; + bool at_bottom = false; + int previous_tab_index = -1; + bool previous_at_bottom = false; + WindowWrapper *dock_window = nullptr; + int dock_slot_index = EditorDockManager::DOCK_SLOT_NONE; + + void _set_default_slot_bind(EditorPlugin::DockSlot p_slot); + EditorPlugin::DockSlot _get_default_slot_bind() const { return (EditorPlugin::DockSlot)default_slot; } + +protected: + static void _bind_methods(); + + GDVIRTUAL1(_update_layout, int) + GDVIRTUAL2C(_save_layout_to_config, Ref, const String &) + GDVIRTUAL2(_load_layout_from_config, Ref, const String &) + +public: + EditorDock(); + + void set_title(const String &p_title); + String get_title() const { return title; } + + void set_layout_key(const String &p_key) { layout_key = p_key; } + String get_layout_key() const { return layout_key; } + + void set_icon_name(const StringName &p_name); + StringName get_icon_name() const { return icon_name; } + + void set_dock_icon(const Ref &p_icon); + Ref get_dock_icon() const { return dock_icon; } + + void set_dock_shortcut(const Ref &p_shortcut) { shortcut = p_shortcut; } + Ref get_dock_shortcut() const { return shortcut; } + + void set_default_slot(EditorDockManager::DockSlot p_slot); + EditorDockManager::DockSlot get_default_slot() const { return default_slot; } + + void set_available_layouts(BitField p_layouts) { available_layouts = p_layouts; } + BitField get_available_layouts() const { return available_layouts; } + + String get_display_title() const; + String get_effective_layout_key() const; + + virtual void update_layout(DockLayout p_layout) { GDVIRTUAL_CALL(_update_layout, p_layout); } + virtual void save_layout_to_config(Ref &p_layout, const String &p_section) const { GDVIRTUAL_CALL(_save_layout_to_config, p_layout, p_section); } + virtual void load_layout_from_config(const Ref &p_layout, const String &p_section) { GDVIRTUAL_CALL(_load_layout_from_config, p_layout, p_section); } +}; + +VARIANT_BITFIELD_CAST(EditorDock::DockLayout); diff --git a/editor/docks/editor_dock_manager.cpp b/editor/docks/editor_dock_manager.cpp index 4221f571e05..9f519e7db38 100644 --- a/editor/docks/editor_dock_manager.cpp +++ b/editor/docks/editor_dock_manager.cpp @@ -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 _get_dock_icon(const EditorDock *p_dock, const Callable &p_icon_fetch) { + Ref 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(from_node->get_parent()); - if (!parent) { + TabContainer *source_tab_container = Object::cast_to(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(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 &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(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 &p_input, Control *p_dock, Button *p_bottom_button) { +void EditorDockManager::_bottom_dock_button_gui_input(const Ref &p_input, EditorDock *p_dock, Button *p_bottom_button) { Ref 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 &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 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 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(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(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(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(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 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()); tab_container->set_tab_tooltip(index, String()); } break; case TabStyle::ICON_ONLY: { - const Ref 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 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 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(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 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(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 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 p_layout, const Str // Save closed and bottom docks. Array bottom_docks_dump; Array closed_docks_dump; - for (const KeyValue &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 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 dock_map; - for (const KeyValue &dock : all_docks) { - dock_map[dock.key->get_name()] = dock.key; + HashMap 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 p_layout, const S Vector 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 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 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 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(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 &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 &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 &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 &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(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; } diff --git a/editor/docks/editor_dock_manager.h b/editor/docks/editor_dock_manager.h index b46260ec8e2..cdf7818b3e4 100644 --- a/editor/docks/editor_dock_manager.h +++ b/editor/docks/editor_dock_manager.h @@ -36,6 +36,7 @@ class Button; class ConfigFile; class Control; +class EditorDock; class PopupMenu; class TabBar; class TabContainer; @@ -83,21 +84,7 @@ private: friend class DockContextPopup; friend class EditorDockDragHint; - struct DockInfo { - String title; - bool open = false; - bool enabled = true; - bool at_bottom = false; - int previous_tab_index = -1; - bool previous_at_bottom = false; - WindowWrapper *dock_window = nullptr; - int dock_slot_index = DOCK_SLOT_NONE; - Ref shortcut; - Ref icon; // Only used when `icon_name` is empty. - StringName icon_name; - }; - - static EditorDockManager *singleton; + static inline EditorDockManager *singleton = nullptr; // To access splits easily by index. Vector vsplits; @@ -106,38 +93,38 @@ private: Vector dock_windows; TabContainer *dock_slot[DOCK_SLOT_MAX]; EditorDockDragHint *dock_drag_rects[DOCK_SLOT_MAX]; - HashMap all_docks; - Control *dock_tab_dragged = nullptr; + LocalVector all_docks; + EditorDock *dock_tab_dragged = nullptr; bool docks_visible = true; DockContextPopup *dock_context_popup = nullptr; PopupMenu *docks_menu = nullptr; - Vector docks_menu_docks; + LocalVector docks_menu_docks; Control *closed_dock_parent = nullptr; - Control *_get_dock_tab_dragged(); + EditorDock *_get_dock_tab_dragged(); void _dock_drag_stopped(); void _dock_split_dragged(int p_offset); void _dock_container_gui_input(const Ref &p_input, TabContainer *p_dock_container); - void _bottom_dock_button_gui_input(const Ref &p_input, Control *p_dock, Button *p_bottom_button); + void _bottom_dock_button_gui_input(const Ref &p_input, EditorDock *p_dock, Button *p_bottom_button); void _dock_container_update_visibility(TabContainer *p_dock_container); void _update_layout(); void _docks_menu_option(int p_id); void _window_close_request(WindowWrapper *p_wrapper); - Control *_close_window(WindowWrapper *p_wrapper); - void _open_dock_in_window(Control *p_dock, bool p_show_window = true, bool p_reset_size = false); - void _restore_dock_to_saved_window(Control *p_dock, const Dictionary &p_window_dump); + EditorDock *_close_window(WindowWrapper *p_wrapper); + void _open_dock_in_window(EditorDock *p_dock, bool p_show_window = true, bool p_reset_size = false); + void _restore_dock_to_saved_window(EditorDock *p_dock, const Dictionary &p_window_dump); - void _dock_move_to_bottom(Control *p_dock, bool p_visible); - void _dock_remove_from_bottom(Control *p_dock); - bool _is_dock_at_bottom(Control *p_dock); + void _dock_move_to_bottom(EditorDock *p_dock, bool p_visible); + void _dock_remove_from_bottom(EditorDock *p_dock); + bool _is_dock_at_bottom(EditorDock *p_dock); - void _move_dock_tab_index(Control *p_dock, int p_tab_index, bool p_set_current); - void _move_dock(Control *p_dock, Control *p_target, int p_tab_index = -1, bool p_set_current = true); + void _move_dock_tab_index(EditorDock *p_dock, int p_tab_index, bool p_set_current); + void _move_dock(EditorDock *p_dock, Control *p_target, int p_tab_index = -1, bool p_set_current = true); - void _update_tab_style(Control *p_dock); + void _update_tab_style(EditorDock *p_dock); public: static EditorDockManager *get_singleton() { return singleton; } @@ -156,22 +143,20 @@ public: void save_docks_to_config(Ref p_layout, const String &p_section) const; void load_docks_from_config(Ref p_layout, const String &p_section, bool p_first_load = false); - void set_dock_enabled(Control *p_dock, bool p_enabled); - void close_dock(Control *p_dock); - void open_dock(Control *p_dock, bool p_set_current = true); - void focus_dock(Control *p_dock); + void set_dock_enabled(EditorDock *p_dock, bool p_enabled); + void close_dock(EditorDock *p_dock); + void open_dock(EditorDock *p_dock, bool p_set_current = true); + void focus_dock(EditorDock *p_dock); TabContainer *get_dock_tab_container(Control *p_dock) const; - void bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock); + void bottom_dock_show_placement_popup(const Rect2i &p_position, EditorDock *p_dock); void set_docks_visible(bool p_show); bool are_docks_visible() const; - void add_dock(Control *p_dock, const String &p_title = "", DockSlot p_slot = DOCK_SLOT_NONE, const Ref &p_shortcut = nullptr, const StringName &p_icon_name = StringName()); - void remove_dock(Control *p_dock); - - void set_dock_tab_icon(Control *p_dock, const Ref &p_icon); + void add_dock(EditorDock *p_dock); + void remove_dock(EditorDock *p_dock); EditorDockManager(); }; @@ -222,7 +207,7 @@ private: Rect2 dock_select_rects[EditorDockManager::DOCK_SLOT_MAX]; int dock_select_rect_over_idx = -1; - Control *context_dock = nullptr; + EditorDock *context_dock = nullptr; EditorDockManager *dock_manager = nullptr; @@ -243,8 +228,8 @@ protected: public: void select_current_dock_in_dock_slot(int p_dock_slot); - void set_dock(Control *p_dock); - Control *get_dock() const; + void set_dock(EditorDock *p_dock); + EditorDock *get_dock() const; void docks_updated(); DockContextPopup(); diff --git a/editor/docks/filesystem_dock.cpp b/editor/docks/filesystem_dock.cpp index 0616dd97b8d..341317e68b4 100644 --- a/editor/docks/filesystem_dock.cpp +++ b/editor/docks/filesystem_dock.cpp @@ -53,11 +53,13 @@ #include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/scene/editor_scene_tabs.h" #include "editor/scene/scene_create_dialog.h" +#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_feature_profile.h" #include "editor/settings/editor_settings.h" #include "editor/shader/shader_create_dialog.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" +#include "scene/gui/box_container.h" #include "scene/gui/item_list.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" @@ -4008,16 +4010,13 @@ MenuButton *FileSystemDock::_create_file_menu_button() { return button; } -bool FileSystemDock::_can_dock_horizontal() const { - return true; -} - -void FileSystemDock::_set_dock_horizontal(bool p_enable) { - if (button_dock_placement->is_visible() == p_enable) { +void FileSystemDock::update_layout(EditorDock::DockLayout p_layout) { + bool horizontal = p_layout == EditorDock::DOCK_LAYOUT_HORIZONTAL; + if (button_dock_placement->is_visible() == horizontal) { return; } - if (p_enable) { + if (horizontal) { set_meta("_dock_display_mode", get_display_mode()); set_meta("_dock_file_display_mode", get_file_list_display_mode()); @@ -4041,75 +4040,49 @@ void FileSystemDock::_set_dock_horizontal(bool p_enable) { set_file_list_display_mode(new_file_display_mode); set_custom_minimum_size(Size2(0, 0)); } - - button_dock_placement->set_visible(p_enable); + button_dock_placement->set_visible(horizontal); } -void FileSystemDock::_bind_methods() { - ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path); - - ClassDB::bind_method(D_METHOD("add_resource_tooltip_plugin", "plugin"), &FileSystemDock::add_resource_tooltip_plugin); - ClassDB::bind_method(D_METHOD("remove_resource_tooltip_plugin", "plugin"), &FileSystemDock::remove_resource_tooltip_plugin); - - ClassDB::bind_method(D_METHOD("_set_dock_horizontal", "enable"), &FileSystemDock::_set_dock_horizontal); - ClassDB::bind_method(D_METHOD("_can_dock_horizontal"), &FileSystemDock::_can_dock_horizontal); - - ClassDB::bind_method(D_METHOD("_save_layout_to_config"), &FileSystemDock::_save_layout_to_config); - ClassDB::bind_method(D_METHOD("_load_layout_from_config"), &FileSystemDock::_load_layout_from_config); - - ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file"))); - ADD_SIGNAL(MethodInfo("instantiate", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); - - ADD_SIGNAL(MethodInfo("resource_removed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); - ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file"))); - ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); - ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file"))); - ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_folder"))); - ADD_SIGNAL(MethodInfo("folder_color_changed")); - - ADD_SIGNAL(MethodInfo("display_mode_changed")); -} - -void FileSystemDock::_save_layout_to_config(Ref p_layout, const String &p_section) const { - p_layout->set_value(p_section, "dock_filesystem_h_split_offset", get_h_split_offset()); - p_layout->set_value(p_section, "dock_filesystem_v_split_offset", get_v_split_offset()); - p_layout->set_value(p_section, "dock_filesystem_display_mode", get_display_mode()); - p_layout->set_value(p_section, "dock_filesystem_file_sort", (int)get_file_sort()); - p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", get_file_list_display_mode()); +void FileSystemDock::save_layout_to_config(Ref &p_layout, const String &p_section) const { + p_layout->set_value(p_section, "h_split_offset", get_h_split_offset()); + p_layout->set_value(p_section, "v_split_offset", get_v_split_offset()); + p_layout->set_value(p_section, "display_mode", get_display_mode()); + p_layout->set_value(p_section, "file_sort", (int)get_file_sort()); + p_layout->set_value(p_section, "file_list_display_mode", get_file_list_display_mode()); PackedStringArray selected_files = get_selected_paths(); - p_layout->set_value(p_section, "dock_filesystem_selected_paths", selected_files); + p_layout->set_value(p_section, "selected_paths", selected_files); Vector uncollapsed_paths = get_uncollapsed_paths(); - p_layout->set_value(p_section, "dock_filesystem_uncollapsed_paths", searched_tokens.is_empty() ? uncollapsed_paths : uncollapsed_paths_before_search); + p_layout->set_value(p_section, "uncollapsed_paths", searched_tokens.is_empty() ? uncollapsed_paths : uncollapsed_paths_before_search); } -void FileSystemDock::_load_layout_from_config(Ref p_layout, const String &p_section) { - if (p_layout->has_section_key(p_section, "dock_filesystem_h_split_offset")) { - int fs_h_split_ofs = p_layout->get_value(p_section, "dock_filesystem_h_split_offset"); +void FileSystemDock::load_layout_from_config(const Ref &p_layout, const String &p_section) { + if (p_layout->has_section_key(p_section, "h_split_offset")) { + int fs_h_split_ofs = p_layout->get_value(p_section, "h_split_offset"); set_h_split_offset(fs_h_split_ofs); } - if (p_layout->has_section_key(p_section, "dock_filesystem_v_split_offset")) { - int fs_v_split_ofs = p_layout->get_value(p_section, "dock_filesystem_v_split_offset"); + if (p_layout->has_section_key(p_section, "v_split_offset")) { + int fs_v_split_ofs = p_layout->get_value(p_section, "v_split_offset"); set_v_split_offset(fs_v_split_ofs); } - if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { - DisplayMode dock_filesystem_display_mode = DisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_display_mode"))); + if (p_layout->has_section_key(p_section, "display_mode")) { + DisplayMode dock_filesystem_display_mode = DisplayMode(int(p_layout->get_value(p_section, "display_mode"))); set_display_mode(dock_filesystem_display_mode); } - if (p_layout->has_section_key(p_section, "dock_filesystem_file_sort")) { - FileSortOption dock_filesystem_file_sort = FileSortOption(int(p_layout->get_value(p_section, "dock_filesystem_file_sort"))); + if (p_layout->has_section_key(p_section, "file_sort")) { + FileSortOption dock_filesystem_file_sort = FileSortOption(int(p_layout->get_value(p_section, "file_sort"))); set_file_sort(dock_filesystem_file_sort); } - if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) { - FileListDisplayMode dock_filesystem_file_list_display_mode = FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode"))); + if (p_layout->has_section_key(p_section, "file_list_display_mode")) { + FileListDisplayMode dock_filesystem_file_list_display_mode = FileListDisplayMode(int(p_layout->get_value(p_section, "file_list_display_mode"))); set_file_list_display_mode(dock_filesystem_file_list_display_mode); } - if (p_layout->has_section_key(p_section, "dock_filesystem_selected_paths")) { - PackedStringArray dock_filesystem_selected_paths = p_layout->get_value(p_section, "dock_filesystem_selected_paths"); + if (p_layout->has_section_key(p_section, "selected_paths")) { + PackedStringArray dock_filesystem_selected_paths = p_layout->get_value(p_section, "selected_paths"); for (int i = 0; i < dock_filesystem_selected_paths.size(); i++) { select_file(dock_filesystem_selected_paths[i]); } @@ -4117,8 +4090,8 @@ void FileSystemDock::_load_layout_from_config(Ref p_layout, const St // Restore collapsed state. PackedStringArray uncollapsed_tis; - if (p_layout->has_section_key(p_section, "dock_filesystem_uncollapsed_paths")) { - uncollapsed_tis = p_layout->get_value(p_section, "dock_filesystem_uncollapsed_paths"); + if (p_layout->has_section_key(p_section, "uncollapsed_paths")) { + uncollapsed_tis = p_layout->get_value(p_section, "uncollapsed_paths"); } else { uncollapsed_tis = { "res://" }; } @@ -4134,10 +4107,32 @@ void FileSystemDock::_load_layout_from_config(Ref p_layout, const St } } +void FileSystemDock::_bind_methods() { + ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path); + + ClassDB::bind_method(D_METHOD("add_resource_tooltip_plugin", "plugin"), &FileSystemDock::add_resource_tooltip_plugin); + ClassDB::bind_method(D_METHOD("remove_resource_tooltip_plugin", "plugin"), &FileSystemDock::remove_resource_tooltip_plugin); + + ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file"))); + ADD_SIGNAL(MethodInfo("instantiate", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); + + ADD_SIGNAL(MethodInfo("resource_removed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file"))); + ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder"))); + ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file"))); + ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_folder"))); + ADD_SIGNAL(MethodInfo("folder_color_changed")); + + ADD_SIGNAL(MethodInfo("display_mode_changed")); +} + FileSystemDock::FileSystemDock() { singleton = this; - set_name("FileSystem"); - current_path = "res://"; + set_name(TTRC("FileSystem")); + set_icon_name("Folder"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_filesystem", TTRC("Open FileSystem Dock"), KeyModifierMask::ALT | Key::F)); + set_default_slot(EditorDockManager::DOCK_SLOT_LEFT_BR); + set_available_layouts(DOCK_LAYOUT_VERTICAL | DOCK_LAYOUT_HORIZONTAL); ProjectSettings::get_singleton()->add_hidden_prefix("file_customization/"); @@ -4171,8 +4166,11 @@ FileSystemDock::FileSystemDock() { editor_is_dark_theme = EditorThemeManager::is_dark_theme(); + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + VBoxContainer *top_vbc = memnew(VBoxContainer); - add_child(top_vbc); + main_vb->add_child(top_vbc); HBoxContainer *toolbar_hbc = memnew(HBoxContainer); top_vbc->add_child(toolbar_hbc); @@ -4241,7 +4239,7 @@ FileSystemDock::FileSystemDock() { split_box->set_v_size_flags(SIZE_EXPAND_FILL); split_box->connect("dragged", callable_mp(this, &FileSystemDock::_split_dragged)); split_box_offset_h = 240 * EDSCALE; - add_child(split_box); + main_vb->add_child(split_box); tree = memnew(FileSystemTree); tree->set_accessibility_name(TTRC("Directories")); @@ -4305,7 +4303,7 @@ FileSystemDock::FileSystemDock() { scanning_vb = memnew(VBoxContainer); scanning_vb->hide(); - add_child(scanning_vb); + main_vb->add_child(scanning_vb); Label *slabel = memnew(Label); slabel->set_text(TTRC("Scanning Files,\nPlease Wait...")); diff --git a/editor/docks/filesystem_dock.h b/editor/docks/filesystem_dock.h index 1be6542bc8f..a5ed30ad346 100644 --- a/editor/docks/filesystem_dock.h +++ b/editor/docks/filesystem_dock.h @@ -30,6 +30,7 @@ #pragma once +#include "editor/docks/editor_dock.h" #include "editor/file_system/dependency_editor.h" #include "editor/file_system/editor_file_system.h" #include "editor/file_system/file_info.h" @@ -44,6 +45,7 @@ class CreateDialog; class EditorDirDialog; +class HBoxContainer; class ItemList; class LineEdit; class ProgressBar; @@ -51,6 +53,7 @@ class SceneCreateDialog; class ShaderCreateDialog; class DirectoryCreateDialog; class EditorResourceTooltipPlugin; +class VBoxContainer; class FileSystemTree : public Tree { virtual Control *make_custom_tooltip(const String &p_text) const; @@ -78,8 +81,8 @@ public: FileSystemList(); }; -class FileSystemDock : public VBoxContainer { - GDCLASS(FileSystemDock, VBoxContainer); +class FileSystemDock : public EditorDock { + GDCLASS(FileSystemDock, EditorDock); public: enum FileListDisplayMode { @@ -230,7 +233,7 @@ private: int history_pos; int history_max_size; - String current_path; + String current_path = "res://"; String select_after_scan; bool updating_tree = false; @@ -361,12 +364,6 @@ private: void _change_bottom_dock_placement(); - bool _can_dock_horizontal() const; - void _set_dock_horizontal(bool p_enable); - - void _save_layout_to_config(Ref p_layout, const String &p_section) const; - void _load_layout_from_config(Ref p_layout, const String &p_section); - private: inline static FileSystemDock *singleton = nullptr; @@ -377,6 +374,10 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void update_layout(EditorDock::DockLayout p_layout) override; + virtual void save_layout_to_config(Ref &p_layout, const String &p_section) const override; + virtual void load_layout_from_config(const Ref &p_layout, const String &p_section) override; + public: static constexpr double ITEM_COLOR_SCALE = 1.75; static constexpr double ITEM_ALPHA_MIN = 0.1; diff --git a/editor/docks/history_dock.cpp b/editor/docks/history_dock.cpp index 8e0fed8a3d6..fafad00aefc 100644 --- a/editor/docks/history_dock.cpp +++ b/editor/docks/history_dock.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_settings.h" #include "scene/gui/check_box.h" #include "scene/gui/item_list.h" @@ -175,14 +176,14 @@ void HistoryDock::refresh_version() { action_list->set_current(idx); } -void HistoryDock::_save_layout_to_config(Ref p_layout, const String &p_section) const { - p_layout->set_value(p_section, "dock_history_include_scene", current_scene_checkbox->is_pressed()); - p_layout->set_value(p_section, "dock_history_include_global", global_history_checkbox->is_pressed()); +void HistoryDock::save_layout_to_config(Ref &p_layout, const String &p_section) const { + p_layout->set_value(p_section, "include_scene", current_scene_checkbox->is_pressed()); + p_layout->set_value(p_section, "include_global", global_history_checkbox->is_pressed()); } -void HistoryDock::_load_layout_from_config(Ref p_layout, const String &p_section) { - current_scene_checkbox->set_pressed_no_signal(p_layout->get_value(p_section, "dock_history_include_scene", true)); - global_history_checkbox->set_pressed_no_signal(p_layout->get_value(p_section, "dock_history_include_global", true)); +void HistoryDock::load_layout_from_config(const Ref &p_layout, const String &p_section) { + current_scene_checkbox->set_pressed_no_signal(p_layout->get_value(p_section, "include_scene", true)); + global_history_checkbox->set_pressed_no_signal(p_layout->get_value(p_section, "include_global", true)); refresh_history(); } @@ -234,20 +235,21 @@ void HistoryDock::_notification(int p_notification) { } } -void HistoryDock::_bind_methods() { - ClassDB::bind_method(D_METHOD("_save_layout_to_config"), &HistoryDock::_save_layout_to_config); - ClassDB::bind_method(D_METHOD("_load_layout_from_config"), &HistoryDock::_load_layout_from_config); -} - HistoryDock::HistoryDock() { - set_name("History"); + set_name(TTRC("History")); + set_icon_name("History"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_history", TTRC("Open History Dock"))); + set_default_slot(EditorDockManager::DOCK_SLOT_RIGHT_UL); ur_manager = EditorUndoRedoManager::get_singleton(); ur_manager->connect("history_changed", callable_mp(this, &HistoryDock::on_history_changed)); ur_manager->connect("version_changed", callable_mp(this, &HistoryDock::on_version_changed)); + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + HBoxContainer *mode_hb = memnew(HBoxContainer); - add_child(mode_hb); + main_vb->add_child(mode_hb); current_scene_checkbox = memnew(CheckBox); mode_hb->add_child(current_scene_checkbox); @@ -269,7 +271,7 @@ HistoryDock::HistoryDock() { action_list = memnew(ItemList); action_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); - add_child(action_list); + main_vb->add_child(action_list); action_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); action_list->connect(SceneStringName(item_selected), callable_mp(this, &HistoryDock::seek_history)); } diff --git a/editor/docks/history_dock.h b/editor/docks/history_dock.h index 4f435d16d9c..0c1604be53d 100644 --- a/editor/docks/history_dock.h +++ b/editor/docks/history_dock.h @@ -30,15 +30,15 @@ #pragma once -#include "scene/gui/box_container.h" +#include "editor/docks/editor_dock.h" class CheckBox; class ConfigFile; class ItemList; class EditorUndoRedoManager; -class HistoryDock : public VBoxContainer { - GDCLASS(HistoryDock, VBoxContainer); +class HistoryDock : public EditorDock { + GDCLASS(HistoryDock, EditorDock); EditorUndoRedoManager *ur_manager; ItemList *action_list = nullptr; @@ -54,12 +54,11 @@ class HistoryDock : public VBoxContainer { void on_version_changed(); void refresh_version(); - void _save_layout_to_config(Ref p_layout, const String &p_section) const; - void _load_layout_from_config(Ref p_layout, const String &p_section); - protected: void _notification(int p_notification); - static void _bind_methods(); + + virtual void save_layout_to_config(Ref &p_layout, const String &p_section) const override; + virtual void load_layout_from_config(const Ref &p_layout, const String &p_section) override; public: void seek_history(int p_index); diff --git a/editor/docks/import_dock.cpp b/editor/docks/import_dock.cpp index 279e846089c..f434f8a2d20 100644 --- a/editor/docks/import_dock.cpp +++ b/editor/docks/import_dock.cpp @@ -35,9 +35,11 @@ #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" #include "editor/inspector/editor_resource_preview.h" +#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_settings.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" +#include "scene/gui/box_container.h" class ImportDockParameters : public Object { GDCLASS(ImportDockParameters, Object); @@ -742,11 +744,17 @@ void ImportDock::initialize_import_options() const { ImportDock::ImportDock() { singleton = this; - set_name("Import"); + set_name(TTRC("Import")); + set_icon_name("FileAccess"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_import", TTRC("Open Import Dock"))); + set_default_slot(EditorDockManager::DOCK_SLOT_LEFT_UR); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); content = memnew(VBoxContainer); content->set_v_size_flags(SIZE_EXPAND_FILL); - add_child(content); + main_vb->add_child(content); content->hide(); imported = memnew(Label); @@ -819,7 +827,7 @@ ImportDock::ImportDock() { select_a_resource->set_v_size_flags(SIZE_EXPAND_FILL); select_a_resource->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); select_a_resource->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - add_child(select_a_resource); + main_vb->add_child(select_a_resource); } ImportDock::~ImportDock() { diff --git a/editor/docks/import_dock.h b/editor/docks/import_dock.h index 94a36841f7d..8f0b69ad70a 100644 --- a/editor/docks/import_dock.h +++ b/editor/docks/import_dock.h @@ -32,6 +32,7 @@ #include "core/io/config_file.h" #include "core/io/resource_importer.h" +#include "editor/docks/editor_dock.h" #include "editor/file_system/editor_file_system.h" #include "editor/inspector/editor_inspector.h" #include "scene/gui/box_container.h" @@ -41,8 +42,10 @@ #include "scene/gui/popup_menu.h" class ImportDockParameters; -class ImportDock : public VBoxContainer { - GDCLASS(ImportDock, VBoxContainer); +class VBoxContainer; + +class ImportDock : public EditorDock { + GDCLASS(ImportDock, EditorDock); Label *imported = nullptr; OptionButton *import_as = nullptr; diff --git a/editor/docks/inspector_dock.cpp b/editor/docks/inspector_dock.cpp index fd994121e59..2e5185b8e76 100644 --- a/editor/docks/inspector_dock.cpp +++ b/editor/docks/inspector_dock.cpp @@ -40,10 +40,10 @@ #include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_object_selector.h" #include "editor/script/script_editor_plugin.h" +#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_settings.h" #include "editor/themes/editor_scale.h" - -InspectorDock *InspectorDock::singleton = nullptr; +#include "scene/gui/box_container.h" void InspectorDock::_prepare_menu() { PopupMenu *menu = object_menu->get_popup(); @@ -707,14 +707,20 @@ void InspectorDock::shortcut_input(const Ref &p_event) { InspectorDock::InspectorDock(EditorData &p_editor_data) { singleton = this; - set_name("Inspector"); + set_name(TTRC("Inspector")); + set_icon_name("AnimationTrackList"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_inspector", TTRC("Open Inspector Dock"))); + set_default_slot(EditorDockManager::DOCK_SLOT_RIGHT_UL); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); editor_data = &p_editor_data; property_name_style = EditorPropertyNameProcessor::get_default_inspector_style(); HBoxContainer *general_options_hb = memnew(HBoxContainer); - add_child(general_options_hb); + main_vb->add_child(general_options_hb); resource_new_button = memnew(Button); resource_new_button->set_theme_type_variation("FlatMenuButton"); @@ -782,7 +788,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { history_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_select_history)); HBoxContainer *subresource_hb = memnew(HBoxContainer); - add_child(subresource_hb); + main_vb->add_child(subresource_hb); object_selector = memnew(EditorObjectSelector(EditorNode::get_singleton()->get_editor_selection_history())); object_selector->set_h_size_flags(Control::SIZE_EXPAND_FILL); subresource_hb->add_child(object_selector); @@ -801,7 +807,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { new_resource_dialog->connect("create", callable_mp(this, &InspectorDock::_resource_created)); HBoxContainer *property_tools_hb = memnew(HBoxContainer); - add_child(property_tools_hb); + main_vb->add_child(property_tools_hb); search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -818,14 +824,14 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { object_menu->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &InspectorDock::_menu_option)); info = memnew(Button); - add_child(info); + main_vb->add_child(info); info->set_clip_text(true); info->set_accessibility_name(TTRC("Information")); info->hide(); info->connect(SceneStringName(pressed), callable_mp(this, &InspectorDock::_info_pressed)); unique_resources_confirmation = memnew(ConfirmationDialog); - add_child(unique_resources_confirmation); + main_vb->add_child(unique_resources_confirmation); VBoxContainer *container = memnew(VBoxContainer); unique_resources_confirmation->add_child(container); @@ -852,12 +858,12 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { EditorNode::get_singleton()->get_gui_base()->add_child(info_dialog); load_resource_dialog = memnew(EditorFileDialog); - add_child(load_resource_dialog); + main_vb->add_child(load_resource_dialog); load_resource_dialog->set_current_dir("res://"); load_resource_dialog->connect("file_selected", callable_mp(this, &InspectorDock::_resource_file_selected)); inspector = memnew(EditorInspector); - add_child(inspector); + main_vb->add_child(inspector); inspector->set_autoclear(true); inspector->set_show_categories(true, true); inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/docks/inspector_dock.h b/editor/docks/inspector_dock.h index 3627d23963b..55eff2a4f1a 100644 --- a/editor/docks/inspector_dock.h +++ b/editor/docks/inspector_dock.h @@ -30,6 +30,7 @@ #pragma once +#include "editor/docks/editor_dock.h" #include "editor/editor_data.h" #include "editor/gui/create_dialog.h" #include "editor/inspector/editor_inspector.h" @@ -43,8 +44,8 @@ class EditorFileDialog; class EditorObjectSelector; -class InspectorDock : public VBoxContainer { - GDCLASS(InspectorDock, VBoxContainer); +class InspectorDock : public EditorDock { + GDCLASS(InspectorDock, EditorDock); enum MenuOptions { RESOURCE_LOAD, @@ -136,7 +137,7 @@ class InspectorDock : public VBoxContainer { virtual void shortcut_input(const Ref &p_event) override; private: - static InspectorDock *singleton; + static inline InspectorDock *singleton = nullptr; public: static InspectorDock *get_singleton() { return singleton; } diff --git a/editor/docks/node_dock.cpp b/editor/docks/node_dock.cpp index 12bcbcda3f0..1f02d87e57b 100644 --- a/editor/docks/node_dock.cpp +++ b/editor/docks/node_dock.cpp @@ -32,6 +32,7 @@ #include "core/io/config_file.h" #include "editor/scene/connections_dialog.h" +#include "editor/settings/editor_command_palette.h" #include "editor/themes/editor_scale.h" void NodeDock::show_groups() { @@ -48,12 +49,12 @@ void NodeDock::show_connections() { connections->show(); } -void NodeDock::_save_layout_to_config(Ref p_layout, const String &p_section) const { - p_layout->set_value(p_section, "dock_node_current_tab", int(groups_button->is_pressed())); +void NodeDock::save_layout_to_config(Ref &p_layout, const String &p_section) const { + p_layout->set_value(p_section, "current_tab", int(groups_button->is_pressed())); } -void NodeDock::_load_layout_from_config(Ref p_layout, const String &p_section) { - const int current_tab = p_layout->get_value(p_section, "dock_node_current_tab", 0); +void NodeDock::load_layout_from_config(const Ref &p_layout, const String &p_section) { + const int current_tab = p_layout->get_value(p_section, "current_tab", 0); if (select_a_node->is_visible()) { if (current_tab == 0) { groups_button->set_pressed_no_signal(false); @@ -78,11 +79,6 @@ void NodeDock::_notification(int p_what) { } } -void NodeDock::_bind_methods() { - ClassDB::bind_method(D_METHOD("_save_layout_to_config"), &NodeDock::_save_layout_to_config); - ClassDB::bind_method(D_METHOD("_load_layout_from_config"), &NodeDock::_load_layout_from_config); -} - void NodeDock::update_lists() { connections->update_tree(); } @@ -110,10 +106,16 @@ void NodeDock::set_node(Node *p_node) { NodeDock::NodeDock() { singleton = this; + set_name(TTRC("Node")); + set_icon_name("Object"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_node", TTRC("Open Node Dock"))); + set_default_slot(EditorDockManager::DOCK_SLOT_RIGHT_UL); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); - set_name("Node"); mode_hb = memnew(HBoxContainer); - add_child(mode_hb); + main_vb->add_child(mode_hb); mode_hb->hide(); connections_button = memnew(Button); @@ -137,12 +139,12 @@ NodeDock::NodeDock() { groups_button->connect(SceneStringName(pressed), callable_mp(this, &NodeDock::show_groups)); connections = memnew(ConnectionsDock); - add_child(connections); + main_vb->add_child(connections); connections->set_v_size_flags(SIZE_EXPAND_FILL); connections->hide(); groups = memnew(GroupsEditor); - add_child(groups); + main_vb->add_child(groups); groups->set_v_size_flags(SIZE_EXPAND_FILL); groups->hide(); @@ -154,7 +156,7 @@ NodeDock::NodeDock() { select_a_node->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); select_a_node->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); select_a_node->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); - add_child(select_a_node); + main_vb->add_child(select_a_node); } NodeDock::~NodeDock() { diff --git a/editor/docks/node_dock.h b/editor/docks/node_dock.h index c27de1cd2b5..cf7a67cb39d 100644 --- a/editor/docks/node_dock.h +++ b/editor/docks/node_dock.h @@ -30,13 +30,14 @@ #pragma once +#include "editor/docks/editor_dock.h" #include "groups_editor.h" class ConfigFile; class ConnectionsDock; -class NodeDock : public VBoxContainer { - GDCLASS(NodeDock, VBoxContainer); +class NodeDock : public EditorDock { + GDCLASS(NodeDock, EditorDock); Button *connections_button = nullptr; Button *groups_button = nullptr; @@ -48,9 +49,6 @@ class NodeDock : public VBoxContainer { Label *select_a_node = nullptr; - void _save_layout_to_config(Ref p_layout, const String &p_section) const; - void _load_layout_from_config(Ref p_layout, const String &p_section); - private: inline static NodeDock *singleton = nullptr; @@ -59,7 +57,9 @@ public: protected: void _notification(int p_what); - static void _bind_methods(); + + virtual void save_layout_to_config(Ref &p_layout, const String &p_section) const override; + virtual void load_layout_from_config(const Ref &p_layout, const String &p_section) override; public: void set_node(Node *p_node); diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index fe9502b5a01..d4a66f0425c 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -55,6 +55,7 @@ #include "editor/scene/rename_dialog.h" #include "editor/scene/reparent_dialog.h" #include "editor/script/script_editor_plugin.h" +#include "editor/settings/editor_command_palette.h" #include "editor/settings/editor_feature_profile.h" #include "editor/settings/editor_settings.h" #include "editor/shader/shader_create_dialog.h" @@ -62,6 +63,7 @@ #include "scene/2d/node_2d.h" #include "scene/animation/animation_tree.h" #include "scene/audio/audio_stream_player.h" +#include "scene/gui/box_container.h" #include "scene/gui/check_box.h" #include "scene/property_utils.h" #include "scene/resources/packed_scene.h" @@ -4689,13 +4691,18 @@ void SceneTreeDock::_update_configuration_warning() { } SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data) { + set_name(TTRC("Scene")); + set_icon_name("PackedScene"); + set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_scene", TTRC("Open Scene Dock"))); + set_default_slot(EditorDockManager::DOCK_SLOT_LEFT_UR); + singleton = this; - set_name("Scene"); editor_data = &p_editor_data; editor_selection = p_editor_selection; scene_root = p_scene_root; - VBoxContainer *vbc = this; + VBoxContainer *vbc = memnew(VBoxContainer); + add_child(vbc); HBoxContainer *filter_hbc = memnew(HBoxContainer); filter_hbc->add_theme_constant_override("separate", 0); diff --git a/editor/docks/scene_tree_dock.h b/editor/docks/scene_tree_dock.h index 4425a895c92..9804189a2e5 100644 --- a/editor/docks/scene_tree_dock.h +++ b/editor/docks/scene_tree_dock.h @@ -30,22 +30,24 @@ #pragma once +#include "editor/docks/editor_dock.h" #include "editor/scene/scene_tree_editor.h" #include "editor/script/script_create_dialog.h" -#include "scene/gui/box_container.h" #include "scene/resources/animation.h" class CheckBox; class EditorData; class EditorSelection; +class HBoxContainer; class MenuButton; class RenameDialog; class ReparentDialog; class ShaderCreateDialog; class TextureRect; +class VBoxContainer; -class SceneTreeDock : public VBoxContainer { - GDCLASS(SceneTreeDock, VBoxContainer); +class SceneTreeDock : public EditorDock { + GDCLASS(SceneTreeDock, EditorDock); enum Tool { TOOL_NEW, diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e268872beb8..bc35e8556d8 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6070,9 +6070,14 @@ void EditorNode::_update_layouts_menu() { } Vector layouts = config->get_sections(); + const String default_layout_name = TTR("Default"); for (const String &layout : layouts) { - if (layout == TTR("Default")) { + if (layout.contains_char('/')) { + continue; + } + + if (layout == default_layout_name) { editor_layouts->remove_item(editor_layouts->get_item_index(LAYOUT_DEFAULT)); overridden_default_layout = editor_layouts->get_item_count(); } @@ -8383,36 +8388,26 @@ EditorNode::EditorNode() { // Instantiate and place editor docks. memnew(SceneTreeDock(scene_root, editor_selection, editor_data)); - memnew(FileSystemDock); - memnew(InspectorDock(editor_data)); - memnew(ImportDock); - memnew(NodeDock); + editor_dock_manager->add_dock(SceneTreeDock::get_singleton()); - FileSystemDock *filesystem_dock = FileSystemDock::get_singleton(); + memnew(ImportDock); + editor_dock_manager->add_dock(ImportDock::get_singleton()); + + FileSystemDock *filesystem_dock = memnew(FileSystemDock); filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request)); filesystem_dock->connect("instantiate", callable_mp(this, &EditorNode::_instantiate_request)); filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_editor_layout)); get_project_settings()->connect_filesystem_dock_signals(filesystem_dock); + editor_dock_manager->add_dock(filesystem_dock); + + memnew(InspectorDock(editor_data)); + editor_dock_manager->add_dock(InspectorDock::get_singleton()); + + memnew(NodeDock); + editor_dock_manager->add_dock(NodeDock::get_singleton()); history_dock = memnew(HistoryDock); - - // Scene: Top left. - editor_dock_manager->add_dock(SceneTreeDock::get_singleton(), TTRC("Scene"), EditorDockManager::DOCK_SLOT_LEFT_UR, ED_SHORTCUT_AND_COMMAND("docks/open_scene", TTRC("Open Scene Dock")), "PackedScene"); - - // Import: Top left, behind Scene. - editor_dock_manager->add_dock(ImportDock::get_singleton(), TTRC("Import"), EditorDockManager::DOCK_SLOT_LEFT_UR, ED_SHORTCUT_AND_COMMAND("docks/open_import", TTRC("Open Import Dock")), "FileAccess"); - - // FileSystem: Bottom left. - editor_dock_manager->add_dock(FileSystemDock::get_singleton(), TTRC("FileSystem"), EditorDockManager::DOCK_SLOT_LEFT_BR, ED_SHORTCUT_AND_COMMAND("docks/open_filesystem", TTRC("Open FileSystem Dock"), KeyModifierMask::ALT | Key::F), "Folder"); - - // Inspector: Full height right. - editor_dock_manager->add_dock(InspectorDock::get_singleton(), TTRC("Inspector"), EditorDockManager::DOCK_SLOT_RIGHT_UL, ED_SHORTCUT_AND_COMMAND("docks/open_inspector", TTRC("Open Inspector Dock")), "AnimationTrackList"); - - // Node: Full height right, behind Inspector. - editor_dock_manager->add_dock(NodeDock::get_singleton(), TTRC("Node"), EditorDockManager::DOCK_SLOT_RIGHT_UL, ED_SHORTCUT_AND_COMMAND("docks/open_node", TTRC("Open Node Dock")), "Object"); - - // History: Full height right, behind Node. - editor_dock_manager->add_dock(history_dock, TTRC("History"), EditorDockManager::DOCK_SLOT_RIGHT_UL, ED_SHORTCUT_AND_COMMAND("docks/open_history", TTRC("Open History Dock")), "History"); + editor_dock_manager->add_dock(history_dock); // Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize. left_r_hsplit->set_split_offset(270 * EDSCALE); diff --git a/editor/plugins/editor_plugin.cpp b/editor/plugins/editor_plugin.cpp index e2567221363..bab001ba9cf 100644 --- a/editor/plugins/editor_plugin.cpp +++ b/editor/plugins/editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/editor_debugger_plugin.h" +#include "editor/docks/editor_dock.h" #include "editor/docks/editor_dock_manager.h" #include "editor/docks/inspector_dock.h" #include "editor/docks/scene_tree_dock.h" @@ -84,24 +85,48 @@ Button *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const Stri return EditorNode::get_bottom_panel()->add_item(p_title, p_control, p_shortcut); } +#ifndef DISABLE_DEPRECATED void EditorPlugin::add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref &p_shortcut) { ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->add_dock(p_control, String(), EditorDockManager::DockSlot(p_slot), p_shortcut); + ERR_FAIL_COND(legacy_docks.has(p_control)); + + EditorDock *dock = memnew(EditorDock); + dock->set_title(p_control->get_name()); + dock->set_dock_shortcut(p_shortcut); + dock->set_default_slot((EditorDockManager::DockSlot)p_slot); + dock->add_child(p_control); + legacy_docks[p_control] = dock; + + EditorDockManager::get_singleton()->add_dock(dock); } void EditorPlugin::remove_control_from_docks(Control *p_control) { ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->remove_dock(p_control); + ERR_FAIL_COND(!legacy_docks.has(p_control)); + + EditorDockManager::get_singleton()->remove_dock(legacy_docks[p_control]); + legacy_docks[p_control]->queue_free(); + legacy_docks.erase(p_control); } +void EditorPlugin::set_dock_tab_icon(Control *p_control, const Ref &p_icon) { + ERR_FAIL_NULL(p_control); + ERR_FAIL_COND(!legacy_docks.has(p_control)); + legacy_docks[p_control]->set_dock_icon(p_icon); +} +#endif + void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) { ERR_FAIL_NULL(p_control); EditorNode::get_bottom_panel()->remove_item(p_control); } -void EditorPlugin::set_dock_tab_icon(Control *p_control, const Ref &p_icon) { - ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->set_dock_tab_icon(p_control, p_icon); +void EditorPlugin::add_dock(EditorDock *p_dock) { + EditorDockManager::get_singleton()->add_dock(p_dock); +} + +void EditorPlugin::remove_dock(EditorDock *p_dock) { + EditorDockManager::get_singleton()->remove_dock(p_dock); } void EditorPlugin::add_control_to_container(CustomControlContainer p_location, Control *p_control) { @@ -588,13 +613,12 @@ void EditorPlugin::_notification(int p_what) { } void EditorPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_dock", "dock"), &EditorPlugin::add_dock); + ClassDB::bind_method(D_METHOD("remove_dock", "dock"), &EditorPlugin::remove_dock); ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container); ClassDB::bind_method(D_METHOD("add_control_to_bottom_panel", "control", "title", "shortcut"), &EditorPlugin::add_control_to_bottom_panel, DEFVAL(Ref())); - ClassDB::bind_method(D_METHOD("add_control_to_dock", "slot", "control", "shortcut"), &EditorPlugin::add_control_to_dock, DEFVAL(Ref())); - ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks); ClassDB::bind_method(D_METHOD("remove_control_from_bottom_panel", "control"), &EditorPlugin::remove_control_from_bottom_panel); ClassDB::bind_method(D_METHOD("remove_control_from_container", "container", "control"), &EditorPlugin::remove_control_from_container); - ClassDB::bind_method(D_METHOD("set_dock_tab_icon", "control", "icon"), &EditorPlugin::set_dock_tab_icon); ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "callable"), &EditorPlugin::add_tool_menu_item); ClassDB::bind_method(D_METHOD("add_tool_submenu_item", "name", "submenu"), &EditorPlugin::add_tool_submenu_item); ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"), &EditorPlugin::remove_tool_menu_item); @@ -602,6 +626,12 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_custom_type", "type", "base", "script", "icon"), &EditorPlugin::add_custom_type); ClassDB::bind_method(D_METHOD("remove_custom_type", "type"), &EditorPlugin::remove_custom_type); +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("add_control_to_dock", "slot", "control", "shortcut"), &EditorPlugin::add_control_to_dock, DEFVAL(Ref())); + ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks); + ClassDB::bind_method(D_METHOD("set_dock_tab_icon", "control", "icon"), &EditorPlugin::set_dock_tab_icon); +#endif + ClassDB::bind_method(D_METHOD("add_autoload_singleton", "name", "path"), &EditorPlugin::add_autoload_singleton); ClassDB::bind_method(D_METHOD("remove_autoload_singleton", "name"), &EditorPlugin::remove_autoload_singleton); @@ -688,6 +718,7 @@ void EditorPlugin::_bind_methods() { BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT); BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT); + BIND_ENUM_CONSTANT(DOCK_SLOT_NONE); BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UL); BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_BL); BIND_ENUM_CONSTANT(DOCK_SLOT_LEFT_UR); diff --git a/editor/plugins/editor_plugin.h b/editor/plugins/editor_plugin.h index 70e247f0bdb..2f1396e5648 100644 --- a/editor/plugins/editor_plugin.h +++ b/editor/plugins/editor_plugin.h @@ -31,6 +31,7 @@ #pragma once #include "core/io/config_file.h" +#include "editor/docks/editor_dock_manager.h" #include "editor/inspector/editor_context_menu_plugin.h" #include "scene/3d/camera_3d.h" #include "scene/gui/control.h" @@ -39,6 +40,7 @@ class Node3D; class Button; class PopupMenu; class EditorDebuggerPlugin; +class EditorDock; class EditorExport; class EditorExportPlugin; class EditorExportPlatform; @@ -65,6 +67,8 @@ class EditorPlugin : public Node { String plugin_version; #ifndef DISABLE_DEPRECATED + static inline HashMap legacy_docks; + void _editor_project_settings_changed(); #endif @@ -85,15 +89,16 @@ public: }; enum DockSlot { - DOCK_SLOT_LEFT_UL, - DOCK_SLOT_LEFT_BL, - DOCK_SLOT_LEFT_UR, - DOCK_SLOT_LEFT_BR, - DOCK_SLOT_RIGHT_UL, - DOCK_SLOT_RIGHT_BL, - DOCK_SLOT_RIGHT_UR, - DOCK_SLOT_RIGHT_BR, - DOCK_SLOT_MAX + DOCK_SLOT_NONE = EditorDockManager::DOCK_SLOT_NONE, + DOCK_SLOT_LEFT_UL = EditorDockManager::DOCK_SLOT_LEFT_UL, + DOCK_SLOT_LEFT_BL = EditorDockManager::DOCK_SLOT_LEFT_BL, + DOCK_SLOT_LEFT_UR = EditorDockManager::DOCK_SLOT_LEFT_UR, + DOCK_SLOT_LEFT_BR = EditorDockManager::DOCK_SLOT_LEFT_BR, + DOCK_SLOT_RIGHT_UL = EditorDockManager::DOCK_SLOT_RIGHT_UL, + DOCK_SLOT_RIGHT_BL = EditorDockManager::DOCK_SLOT_RIGHT_BL, + DOCK_SLOT_RIGHT_UR = EditorDockManager::DOCK_SLOT_RIGHT_UR, + DOCK_SLOT_RIGHT_BR = EditorDockManager::DOCK_SLOT_RIGHT_BR, + DOCK_SLOT_MAX = EditorDockManager::DOCK_SLOT_MAX }; enum AfterGUIInput { @@ -140,6 +145,10 @@ protected: Button *_add_control_to_bottom_panel_compat_88081(Control *p_control, const String &p_title); void _add_control_to_dock_compat_88081(DockSlot p_slot, Control *p_control); static void _bind_compatibility_methods(); + + void add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref &p_shortcut = nullptr); + void remove_control_from_docks(Control *p_control); + void set_dock_tab_icon(Control *p_control, const Ref &p_icon); #endif public: @@ -148,11 +157,10 @@ public: void add_control_to_container(CustomControlContainer p_location, Control *p_control); void remove_control_from_container(CustomControlContainer p_location, Control *p_control); Button *add_control_to_bottom_panel(Control *p_control, const String &p_title, const Ref &p_shortcut = nullptr); - void add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref &p_shortcut = nullptr); - void remove_control_from_docks(Control *p_control); void remove_control_from_bottom_panel(Control *p_control); - void set_dock_tab_icon(Control *p_control, const Ref &p_icon); + void add_dock(EditorDock *p_dock); + void remove_dock(EditorDock *p_dock); void add_tool_menu_item(const String &p_name, const Callable &p_callable); void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index f3e1aa86980..1029ec28eb6 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -146,6 +146,7 @@ void register_editor_types() { GDREGISTER_CLASS(EditorTranslationParserPlugin); GDREGISTER_CLASS(EditorImportPlugin); GDREGISTER_CLASS(EditorScript); + GDREGISTER_CLASS(EditorDock); GDREGISTER_CLASS(EditorSelection); GDREGISTER_CLASS(EditorFileDialog); GDREGISTER_CLASS(EditorSettings); diff --git a/editor/settings/editor_layouts_dialog.cpp b/editor/settings/editor_layouts_dialog.cpp index 46c0e2b9a93..44db265e0b4 100644 --- a/editor/settings/editor_layouts_dialog.cpp +++ b/editor/settings/editor_layouts_dialog.cpp @@ -98,7 +98,9 @@ void EditorLayoutsDialog::_post_popup() { Vector layouts = config->get_sections(); for (const String &E : layouts) { - layout_names->add_item(E); + if (!E.contains_char('/')) { + layout_names->add_item(E); + } } if (name->is_visible()) { name->grab_focus(); diff --git a/editor/version_control/version_control_editor_plugin.cpp b/editor/version_control/version_control_editor_plugin.cpp index 6d7f4a0beef..b9b44313ccf 100644 --- a/editor/version_control/version_control_editor_plugin.cpp +++ b/editor/version_control/version_control_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "core/os/keyboard.h" #include "core/os/time.h" +#include "editor/docks/editor_dock.h" #include "editor/docks/editor_dock_manager.h" #include "editor/docks/filesystem_dock.h" #include "editor/editor_interface.h" @@ -907,7 +908,7 @@ void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() { } void VersionControlEditorPlugin::register_editor() { - EditorDockManager::get_singleton()->add_dock(version_commit_dock, "", EditorDockManager::DOCK_SLOT_RIGHT_UL, ED_SHORTCUT_AND_COMMAND("docks/open_version_control", TTRC("Open Version Control Dock"))); + EditorDockManager::get_singleton()->add_dock(version_commit_dock); version_control_dock_button = EditorNode::get_bottom_panel()->add_item(TTRC("Version Control"), version_control_dock, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_version_control_bottom_panel", TTRC("Toggle Version Control Bottom Panel"))); @@ -1144,14 +1145,21 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { set_up_warning_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); set_up_settings_vbc->add_child(set_up_warning_text); - version_commit_dock = memnew(VBoxContainer); + version_commit_dock = memnew(EditorDock); version_commit_dock->set_visible(false); - version_commit_dock->set_name(TTR("Commit")); + version_commit_dock->set_name(TTRC("Commit")); + version_commit_dock->set_layout_key("VersionCommit"); + version_commit_dock->set_icon_name("VcsBranches"); + version_commit_dock->set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("docks/open_version_control", TTRC("Open Version Control Dock"))); + version_commit_dock->set_default_slot(EditorDockManager::DOCK_SLOT_RIGHT_UL); + + VBoxContainer *dock_vb = memnew(VBoxContainer); + version_commit_dock->add_child(dock_vb); VBoxContainer *unstage_area = memnew(VBoxContainer); unstage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL); unstage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL); - version_commit_dock->add_child(unstage_area); + dock_vb->add_child(unstage_area); HBoxContainer *unstage_title = memnew(HBoxContainer); unstage_area->add_child(unstage_title); @@ -1178,7 +1186,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { discard_all_confirm->set_hide_on_ok(true); discard_all_confirm->set_ok_button_text(TTR("Permanentally delete my changes")); discard_all_confirm->add_cancel_button(); - version_commit_dock->add_child(discard_all_confirm); + dock_vb->add_child(discard_all_confirm); discard_all_confirm->get_ok_button()->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_discard_all)); @@ -1210,7 +1218,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { VBoxContainer *stage_area = memnew(VBoxContainer); stage_area->set_v_size_flags(Control::SIZE_EXPAND_FILL); stage_area->set_h_size_flags(Control::SIZE_EXPAND_FILL); - version_commit_dock->add_child(stage_area); + dock_vb->add_child(stage_area); HBoxContainer *stage_title = memnew(HBoxContainer); stage_area->add_child(stage_title); @@ -1242,10 +1250,10 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { unstage_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(staged_files)); stage_all_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_move_all).bind(unstaged_files)); - version_commit_dock->add_child(memnew(HSeparator)); + dock_vb->add_child(memnew(HSeparator)); VBoxContainer *commit_area = memnew(VBoxContainer); - version_commit_dock->add_child(commit_area); + dock_vb->add_child(commit_area); Label *commit_label = memnew(Label); commit_label->set_text(TTR("Commit Message")); @@ -1271,10 +1279,10 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { commit_button->connect(SceneStringName(pressed), callable_mp(this, &VersionControlEditorPlugin::_commit)); commit_area->add_child(commit_button); - version_commit_dock->add_child(memnew(HSeparator)); + dock_vb->add_child(memnew(HSeparator)); HBoxContainer *commit_list_hbc = memnew(HBoxContainer); - version_commit_dock->add_child(commit_list_hbc); + dock_vb->add_child(commit_list_hbc); Label *commit_list_label = memnew(Label); commit_list_label->set_text(TTR("Commit List")); @@ -1304,14 +1312,14 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { commit_list->set_column_custom_minimum_width(1, 20); commit_list->set_theme_type_variation("TreeSecondary"); commit_list->connect(SceneStringName(item_selected), callable_mp(this, &VersionControlEditorPlugin::_load_diff).bind(commit_list)); - version_commit_dock->add_child(commit_list); + dock_vb->add_child(commit_list); - version_commit_dock->add_child(memnew(HSeparator)); + dock_vb->add_child(memnew(HSeparator)); HFlowContainer *menu_bar = memnew(HFlowContainer); menu_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); menu_bar->set_v_size_flags(Control::SIZE_FILL); - version_commit_dock->add_child(menu_bar); + dock_vb->add_child(menu_bar); branch_select = memnew(OptionButton); branch_select->set_tooltip_text(TTR("Branches")); diff --git a/editor/version_control/version_control_editor_plugin.h b/editor/version_control/version_control_editor_plugin.h index 0e7319c8f0e..017baaa096d 100644 --- a/editor/version_control/version_control_editor_plugin.h +++ b/editor/version_control/version_control_editor_plugin.h @@ -39,6 +39,8 @@ #include "scene/gui/text_edit.h" #include "scene/gui/tree.h" +class EditorDock; + class VersionControlEditorPlugin : public EditorPlugin { GDCLASS(VersionControlEditorPlugin, EditorPlugin) @@ -98,7 +100,7 @@ private: HashMap change_type_to_color; HashMap> change_type_to_icon; - VBoxContainer *version_commit_dock = nullptr; + EditorDock *version_commit_dock = nullptr; Tree *staged_files = nullptr; Tree *unstaged_files = nullptr; Tree *commit_list = nullptr;