diff --git a/doc/classes/EditorDock.xml b/doc/classes/EditorDock.xml index cffb3b3bb5e2..888109d34a7b 100644 --- a/doc/classes/EditorDock.xml +++ b/doc/classes/EditorDock.xml @@ -155,8 +155,11 @@ Allows making the dock floating (opened as a separate window). + + Allows using the dock as main screen. + - Allows placing the dock in all available slots. + Allows placing the dock in all available slots, except in main screen. The dock is closed. @@ -194,7 +197,10 @@ Dock slot at the bottom, below bottom panel, on the right side. - + + The editor's main screen. + + Represents the size of the [enum DockSlot] enum. diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 656f81b80c89..3d81ef076af6 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -90,6 +90,13 @@ Returns the current path being viewed in the [FileSystemDock]. + + + + + Returns an [EditorDock] with the specified [param name]. [param name] must match the original (untranslated) title of the tab in question exactly (e.g., [code]2D[/code], [code]Scene[/code], [code]Audio[/code]). Returns [code]null[/code] if the dock was not found. + + @@ -102,12 +109,10 @@ Returns the language currently used for the editor interface. - + - Returns the editor control responsible for main screen plugins and tools. Use it with plugins that implement [method EditorPlugin._has_main_screen]. - [b]Note:[/b] This node is a [VBoxContainer], which means that if you add a [Control] child to it, you need to set the child's [member Control.size_flags_vertical] to [constant Control.SIZE_EXPAND_FILL] to make it use the full available space. - [b]Warning:[/b] Removing and freeing this node will render a part of the editor useless and may cause a crash. + Returns the editor control responsible for legacy main screen plugins and tools. @@ -509,7 +514,7 @@ [b]Note:[/b] The feature profile that gets activated must be located in the [code]feature_profiles[/code] directory, as a file with the [code].profile[/code] extension. If a profile could not be found, an error occurs. The editor configuration folder can be found by using [method EditorPaths.get_config_dir]. - + diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 54f9bc48bafe..6ca1aabd767f 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -230,7 +230,7 @@ This is for editors that edit script-based objects. You can return a list of breakpoints in the format ([code]script:line[/code]), for example: [code]res://path_to_script.gd:25[/code]. - + Override this method in your plugin to return a [Texture2D] in order to give it an icon. @@ -261,6 +261,7 @@ Override this method in your plugin to provide the name of the plugin when displayed in the Godot editor. For main screen plugins, this appears at the top of the screen, to the right of the "2D", "3D", "Script", "Game", and "Asset Store" buttons. + [b]Note:[/b] Main screen plugins should instead use [member EditorDock.title] of a main screen dock. @@ -326,32 +327,11 @@ [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handles more types of objects and they are edited at the same time, it will result in errors. - + - Returns [code]true[/code] if this is a main screen editor plugin (it goes in the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b], [b]Game[/b], and [b]Asset Store[/b]). - When the plugin's workspace is selected, other main screen plugins will be hidden, but your plugin will not appear automatically. It needs to be added as a child of [method EditorInterface.get_editor_main_screen] and made visible inside [method _make_visible]. - Use [method _get_plugin_name] and [method _get_plugin_icon] to customize the plugin button's appearance. - [codeblock] - var plugin_control - - func _enter_tree(): - plugin_control = preload("my_plugin_control.tscn").instantiate() - EditorInterface.get_editor_main_screen().add_child(plugin_control) - plugin_control.hide() - - func _has_main_screen(): - return true - - func _make_visible(visible): - plugin_control.visible = visible - - func _get_plugin_name(): - return "My Super Cool Plugin 3000" - - func _get_plugin_icon(): - return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") - [/codeblock] + Return [code]true[/code] if this is a main screen editor plugin (it goes in the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b], [b]Game[/b], and [b]Asset Store[/b]). + You can add a main screen dock by using [EditorDock] with [constant EditorDock.DOCK_LAYOUT_MAIN_SCREEN] as available layout. @@ -424,7 +404,7 @@ [b]Note:[/b] A plugin instance can belong only to a single context menu slot. - + diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 19882493a953..bf238a460936 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -1055,6 +1055,9 @@ Tab style of editor docks, except bottom docks. + + Tab style of editor docks located at the editor's main screen. + The font to use for the script editor. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file. diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml index 4f26f1cf500b..056c2916bac7 100644 --- a/doc/classes/ScriptEditor.xml +++ b/doc/classes/ScriptEditor.xml @@ -1,5 +1,5 @@ - + Godot editor's script editor. diff --git a/editor/asset_library/asset_library_editor_plugin.cpp b/editor/asset_library/asset_library_editor_plugin.cpp index 806eb6668f7d..46a6607f9e08 100644 --- a/editor/asset_library/asset_library_editor_plugin.cpp +++ b/editor/asset_library/asset_library_editor_plugin.cpp @@ -39,6 +39,7 @@ #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/version.h" +#include "editor/docks/editor_dock_manager.h" #include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_string_names.h" @@ -1047,6 +1048,12 @@ void EditorAssetLibrary::_notification(int p_what) { case NOTIFICATION_READY: { add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("bg"), SNAME("AssetLib"))); error_label->move_to_front(); + + if (EditorNode::get_singleton()) { + EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorAssetLibrary::_update_margins)); + } else if (ProjectManager::get_singleton()) { + ProjectManager::get_singleton()->connect(SceneStringName(theme_changed), callable_mp(this, &EditorAssetLibrary::_update_margins)); + } } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -1069,7 +1076,7 @@ void EditorAssetLibrary::_notification(int p_what) { // Focus the search box automatically when switching to the Templates tab (in the Project Manager) // or switching to the AssetLib tab (in the editor). // The Project Manager's project filter box is automatically focused in the project manager code. - filter->grab_focus(); + callable_mp((Control *)filter, &Control::grab_focus).call_deferred(false); #endif if (initial_loading) { @@ -1167,6 +1174,10 @@ void EditorAssetLibrary::_update_repository_options() { } } +void EditorAssetLibrary::_update_margins() { + update_layout(get_current_layout(), get_current_slot()); +} + void EditorAssetLibrary::shortcut_input(const Ref &p_event) { ERR_FAIL_COND(p_event.is_null()); @@ -1181,6 +1192,21 @@ void EditorAssetLibrary::shortcut_input(const Ref &p_event) { } } +void EditorAssetLibrary::update_layout(EditorDock::DockLayout p_layout, int p_slot) { + begin_bulk_theme_override(); + if (p_layout == DOCK_LAYOUT_FLOATING) { + remove_theme_constant_override("margin_left"); + remove_theme_constant_override("margin_right"); + remove_theme_constant_override("margin_bottom"); + } else { + int margin = EditorNode::get_singleton()->get_editor_theme()->get_constant("base_margin", EditorStringName(Editor)); + add_theme_constant_override("margin_left", margin); + add_theme_constant_override("margin_right", margin); + add_theme_constant_override("margin_bottom", margin); + } + end_bulk_theme_override(); +} + void EditorAssetLibrary::_install_asset(const String &p_asset_id, const String &p_version, const String &p_download_url, const String &p_sha256) { ERR_FAIL_NULL(description); @@ -2136,6 +2162,13 @@ void EditorAssetLibrary::_bind_methods() { } EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { + set_name(TTRC("Asset Store")); + set_icon_name("AssetStore"); + set_available_layouts(EditorDock::DOCK_LAYOUT_MAIN_SCREEN | EditorDock::DOCK_LAYOUT_FLOATING); + set_default_slot(EditorDock::DOCK_SLOT_MAIN_SCREEN); + if (!Engine::get_singleton()->is_project_manager_hint()) { + set_dock_shortcut(ED_GET_SHORTCUT("editor/editor_asset_store")); + } templates_only = p_templates_only; loading_blocked = ((int)EDITOR_GET("network/connection/network_mode") == EditorSettings::NETWORK_OFFLINE); @@ -2342,10 +2375,6 @@ bool AssetLibraryEditorPlugin::is_available() { #endif } -const Ref AssetLibraryEditorPlugin::get_plugin_icon() const { - return EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("AssetStore"), EditorStringName(EditorIcons)); -} - void AssetLibraryEditorPlugin::make_visible(bool p_visible) { if (p_visible) { addon_library->show(); @@ -2357,7 +2386,7 @@ void AssetLibraryEditorPlugin::make_visible(bool p_visible) { AssetLibraryEditorPlugin::AssetLibraryEditorPlugin() { addon_library = memnew(EditorAssetLibrary); addon_library->set_v_size_flags(Control::SIZE_EXPAND_FILL); - EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(addon_library); + EditorDockManager::get_singleton()->add_dock(addon_library); addon_library->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); addon_library->hide(); } diff --git a/editor/asset_library/asset_library_editor_plugin.h b/editor/asset_library/asset_library_editor_plugin.h index a7cd71289b26..53f05fd257d1 100644 --- a/editor/asset_library/asset_library_editor_plugin.h +++ b/editor/asset_library/asset_library_editor_plugin.h @@ -31,6 +31,7 @@ #pragma once #include "editor/asset_library/editor_asset_installer.h" +#include "editor/docks/editor_dock.h" #include "editor/plugins/editor_plugin.h" #include "scene/gui/box_container.h" #include "scene/gui/grid_container.h" @@ -249,8 +250,8 @@ class EditorAssetLibraryItemDownload : public MarginContainer { EditorAssetLibraryItemDownload(); }; -class EditorAssetLibrary : public PanelContainer { - GDCLASS(EditorAssetLibrary, PanelContainer); +class EditorAssetLibrary : public EditorDock { + GDCLASS(EditorAssetLibrary, EditorDock); String host; @@ -260,6 +261,7 @@ class EditorAssetLibrary : public PanelContainer { void _asset_open(); void _asset_file_selected(const String &p_file); void _update_repository_options(); + void _update_margins(); MarginContainer *library_mc = nullptr; ScrollContainer *library_scroll = nullptr; @@ -400,6 +402,7 @@ class EditorAssetLibrary : public PanelContainer { static void _bind_methods(); void _notification(int p_what); virtual void shortcut_input(const Ref &p_event) override; + virtual void update_layout(EditorDock::DockLayout p_layout, int p_slot) override; public: EditorAssetLibrary(bool p_templates_only = false); @@ -408,14 +411,13 @@ class EditorAssetLibrary : public PanelContainer { class AssetLibraryEditorPlugin : public EditorPlugin { GDCLASS(AssetLibraryEditorPlugin, EditorPlugin); - EditorAssetLibrary *addon_library = nullptr; + static inline EditorAssetLibrary *addon_library = nullptr; public: static bool is_available(); + static EditorAssetLibrary *get_library() { return addon_library; } - virtual String get_plugin_name() const override { return TTRC("Asset Store"); } - virtual const Ref get_plugin_icon() const override; - bool has_main_screen() const override { return true; } + virtual String get_plugin_name() const override { return "Asset Store"; } virtual void edit(Object *p_object) override {} virtual bool handles(Object *p_object) const override { return false; } virtual void make_visible(bool p_visible) override; diff --git a/editor/doc/editor_help.cpp b/editor/doc/editor_help.cpp index cf0f2d267366..763fc7536215 100644 --- a/editor/doc/editor_help.cpp +++ b/editor/doc/editor_help.cpp @@ -48,7 +48,6 @@ #include "core/version.h" #include "editor/doc/doc_data_compressed.gen.h" #include "editor/docks/filesystem_dock.h" -#include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_string_names.h" #include "editor/file_system/editor_file_system.h" @@ -2355,7 +2354,7 @@ void EditorHelp::_update_doc() { void EditorHelp::_request_help(const String &p_string) { Error err = _goto_desc(p_string, false); if (err == OK) { - EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); + ScriptEditor::get_singleton()->focus_editor(); } } @@ -4360,7 +4359,7 @@ void EditorHelpBit::_go_to_url(const String &p_what) { void EditorHelpBit::_go_to_help(const String &p_what) { if (ScriptEditor::get_singleton()) { - EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); + ScriptEditor::get_singleton()->focus_editor(); ScriptEditor::get_singleton()->goto_help(p_what); } else { _go_to_url(p_what); diff --git a/editor/doc/editor_help_search.cpp b/editor/doc/editor_help_search.cpp index fe30b336f210..70bfdf1ae531 100644 --- a/editor/doc/editor_help_search.cpp +++ b/editor/doc/editor_help_search.cpp @@ -33,10 +33,10 @@ #include "core/object/callable_mp.h" #include "core/object/class_db.h" #include "core/os/os.h" -#include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_string_names.h" #include "editor/gui/filter_line_edit.h" +#include "editor/script/script_editor_plugin.h" #include "editor/settings/editor_feature_profile.h" #include "editor/settings/editor_settings.h" #include "editor/themes/editor_scale.h" @@ -189,7 +189,7 @@ void EditorHelpSearch::_confirmed() { } // Activate the script editor and emit the signal with the documentation link to display. - EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); + ScriptEditor::get_singleton()->focus_editor(); emit_signal(SNAME("go_to_help"), item->get_metadata(0)); diff --git a/editor/docks/dock_tab_container.cpp b/editor/docks/dock_tab_container.cpp index 0d8c6314d7d4..e5f49f5bdbfb 100644 --- a/editor/docks/dock_tab_container.cpp +++ b/editor/docks/dock_tab_container.cpp @@ -46,7 +46,7 @@ bool EditorDockDragHint::can_drop_data(const Point2 &p_point, const Variant &p_d void EditorDockDragHint::drop_data(const Point2 &p_point, const Variant &p_data) { // Drop dock into last spot if not over tabbar. if (mouse_inside_tabbar) { - drop_tabbar->_handle_drop_data("tab_container_tab", p_point, p_data, callable_mp(this, &EditorDockDragHint::_drag_move_tab), callable_mp(this, &EditorDockDragHint::_drag_move_tab_from)); + drop_tabbar->_handle_drop_data("tab_container_tab", p_point - (drop_tabbar->get_global_position() - get_global_position()), p_data, callable_mp(this, &EditorDockDragHint::_drag_move_tab), callable_mp(this, &EditorDockDragHint::_drag_move_tab_from)); } else { EditorDockManager *dock_manager = EditorDockManager::get_singleton(); if (mouse_margin_index == -1) { @@ -77,7 +77,7 @@ void EditorDockDragHint::gui_input(const Ref &p_event) { queue_redraw(); } const Point2 pos = mm->get_position(); - mouse_inside_tabbar = drop_tabbar_parent->get_rect().has_point(pos); + mouse_inside_tabbar = drop_tabbar_parent->get_global_rect().has_point(mm->get_global_position()); if (mouse_inside_tabbar) { mouse_margin_index = -1; @@ -194,7 +194,7 @@ void EditorDockDragHint::_notification(int p_what) { // Only display tabbar hint if the mouse is over the tabbar. if (mouse_inside_tabbar) { - draw_set_transform(drop_tabbar_parent->get_position()); // The TabBar isn't always on top. + draw_set_transform(Vector2(drop_tabbar->get_global_position().x - get_global_position().x, drop_tabbar_parent->get_position().y)); // The TabBar isn't always on top. drop_tabbar->_draw_tab_drop(get_canvas_item()); } } break; @@ -317,11 +317,22 @@ EditorDock *DockTabContainer::get_dock(int p_idx) const { return Object::cast_to(get_tab_control(p_idx)); } +EditorDock *DockTabContainer::get_dock_by_name(const String &p_name) const { + for (int i = 0; i < get_tab_count(); i++) { + EditorDock *dock = get_dock(i); + ERR_CONTINUE(!dock); + if (dock->get_display_title() == p_name) { + return dock; + } + } + return nullptr; +} + void DockTabContainer::show_drag_hint() { if (!is_visible_in_tree()) { return; } - drag_hint->set_rect(get_global_rect()); + drag_hint->set_rect(get_drag_hint_rect()); drag_hint->show(); } diff --git a/editor/docks/dock_tab_container.h b/editor/docks/dock_tab_container.h index 67e5084d3789..d8b116938d15 100644 --- a/editor/docks/dock_tab_container.h +++ b/editor/docks/dock_tab_container.h @@ -107,6 +107,7 @@ class DockTabContainer : public TabContainer { virtual TabStyle get_tab_style() const; virtual bool can_switch_dock() const; virtual Rect2 get_floating_dock_rect(EditorDock *p_dock) { return DockTabContainer::get_default_floating_dock_rect(p_dock); } + virtual Rect2 get_drag_hint_rect() const { return get_global_rect(); } void add_margin_valid_drop(int p_margin, int p_target_dock_slot); int get_margin_drop_slot(int p_margin) const; @@ -120,6 +121,7 @@ class DockTabContainer : public TabContainer { void set_dock_context_popup(DockContextPopup *p_popup); EditorDock *get_dock(int p_idx) const; + EditorDock *get_dock_by_name(const String &p_name) const; void show_drag_hint(); EditorDockDragHint *get_drag_hint() const { return drag_hint; } diff --git a/editor/docks/editor_dock.cpp b/editor/docks/editor_dock.cpp index 9a9a1198500d..de81d71896fc 100644 --- a/editor/docks/editor_dock.cpp +++ b/editor/docks/editor_dock.cpp @@ -114,11 +114,11 @@ void EditorDock::_bind_methods() { 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", PROPERTY_HINT_ENUM, "None:-1,Left Side Upper-Left,Left Side Bottom-Left,Left Side Upper-Right,Left Side Bottom-Right,Right Side Upper-Left,Right Side Bottom-Left,Right Side Upper-Right,Right Side Bottom-Right,Bottom"), "set_default_slot", "get_default_slot"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_slot", PROPERTY_HINT_ENUM, "None:-1,Left Side Upper-Left,Left Side Bottom-Left,Left Side Upper-Right,Left Side Bottom-Right,Right Side Upper-Left,Right Side Bottom-Left,Right Side Upper-Right,Right Side Bottom-Right,Bottom,Bottom Left,Bottom Right,Main Screen"), "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,Floating:4"), "set_available_layouts", "get_available_layouts"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "available_layouts", PROPERTY_HINT_FLAGS, "Vertical:1,Horizontal:2,Floating:4,Main Screen:8"), "set_available_layouts", "get_available_layouts"); ADD_SIGNAL(MethodInfo("opened")); ADD_SIGNAL(MethodInfo("closed")); @@ -127,6 +127,7 @@ void EditorDock::_bind_methods() { BIND_BITFIELD_FLAG(DOCK_LAYOUT_VERTICAL); BIND_BITFIELD_FLAG(DOCK_LAYOUT_HORIZONTAL); BIND_BITFIELD_FLAG(DOCK_LAYOUT_FLOATING); + BIND_BITFIELD_FLAG(DOCK_LAYOUT_MAIN_SCREEN); BIND_BITFIELD_FLAG(DOCK_LAYOUT_ALL); BIND_ENUM_CONSTANT(DOCK_SLOT_NONE); @@ -141,6 +142,7 @@ void EditorDock::_bind_methods() { BIND_ENUM_CONSTANT(DOCK_SLOT_BOTTOM); BIND_ENUM_CONSTANT(DOCK_SLOT_BOTTOM_L); BIND_ENUM_CONSTANT(DOCK_SLOT_BOTTOM_R); + BIND_ENUM_CONSTANT(DOCK_SLOT_MAIN_SCREEN); BIND_ENUM_CONSTANT(DOCK_SLOT_MAX); GDVIRTUAL_BIND(_update_layout_and_slot, "layout", "slot"); diff --git a/editor/docks/editor_dock.h b/editor/docks/editor_dock.h index f37104d1e125..b9195abca503 100644 --- a/editor/docks/editor_dock.h +++ b/editor/docks/editor_dock.h @@ -45,6 +45,7 @@ class EditorDock : public MarginContainer { DOCK_LAYOUT_VERTICAL = 1, DOCK_LAYOUT_HORIZONTAL = 2, DOCK_LAYOUT_FLOATING = 4, + DOCK_LAYOUT_MAIN_SCREEN = 8, DOCK_LAYOUT_ALL = DOCK_LAYOUT_VERTICAL | DOCK_LAYOUT_HORIZONTAL | DOCK_LAYOUT_FLOATING, }; @@ -61,6 +62,7 @@ class EditorDock : public MarginContainer { DOCK_SLOT_BOTTOM, DOCK_SLOT_BOTTOM_L, DOCK_SLOT_BOTTOM_R, + DOCK_SLOT_MAIN_SCREEN, DOCK_SLOT_MAX }; diff --git a/editor/docks/editor_dock_manager.cpp b/editor/docks/editor_dock_manager.cpp index 62e75ce7e82e..6adffeb64729 100644 --- a/editor/docks/editor_dock_manager.cpp +++ b/editor/docks/editor_dock_manager.cpp @@ -33,6 +33,7 @@ #include "core/object/callable_mp.h" #include "editor/docks/dock_tab_container.h" #include "editor/docks/editor_dock.h" +#include "editor/editor_main_screen.h" #include "editor/editor_node.h" #include "editor/editor_string_names.h" #include "editor/gui/window_wrapper.h" @@ -152,14 +153,7 @@ EditorDock *EditorDockManager::_get_dock_tab_dragged() { const String tab_type = dock_drop_data.get("tab_type", ""); if (tab_type == "tab_container_tab") { Node *source_tab_bar = EditorNode::get_singleton()->get_node(dock_drop_data["from_path"]); - if (!source_tab_bar) { - return nullptr; - } - HBoxContainer *parent = Object::cast_to(source_tab_bar->get_parent()); // The internal container. - if (!parent) { - return nullptr; - } - DockTabContainer *source_tab_container = Object::cast_to(parent->get_parent()); + DockTabContainer *source_tab_container = Object::cast_to(TabContainer::get_tab_bar_container(Object::cast_to(source_tab_bar))); if (!source_tab_container) { return nullptr; } @@ -200,6 +194,15 @@ DockTabContainer *EditorDockManager::get_dock_container(int p_slot) const { return dock_slots[p_slot]; } +EditorDock *EditorDockManager::get_dock_by_name(const String &p_name) const { + for (EditorDock *dock : all_docks) { + if (dock->get_display_title() == p_name) { + return dock; + } + } + return nullptr; +} + void EditorDockManager::update_docks_menu() { docks_menu->clear(); docks_menu->reset_size(); @@ -1046,17 +1049,6 @@ void DockSlotGrid::_update_rect_cache() { rect.size = rect.size * CELL_SIZE * EDSCALE + (rect.size - Vector2i(1, 1)) * MARGINS * EDSCALE; rect_cache[i] = rect; } - - // Temporarily hard-coded, until main screen is registered as a slot. - { - Rect2 rect = Rect2i(2, 0, 4, 4); - if (is_layout_rtl()) { - rect.position.x = GRID_SIZE.x - rect.position.x - rect.size.x; - } - rect.position = rect.position * CELL_SIZE * EDSCALE + (rect.position + Vector2i(0, 1)) * MARGINS * EDSCALE; - rect.size = rect.size * CELL_SIZE * EDSCALE + (rect.size - Vector2i(1, 1)) * MARGINS * EDSCALE; - main_screen_rect = rect; - } } void DockSlotGrid::_bind_methods() { @@ -1129,7 +1121,6 @@ void DockSlotGrid::_notification(int p_what) { } } } - draw_rect(main_screen_rect, unusable_dock_color); } break; case NOTIFICATION_MOUSE_EXIT: { diff --git a/editor/docks/editor_dock_manager.h b/editor/docks/editor_dock_manager.h index 5c30536924f7..4eb76abfcaba 100644 --- a/editor/docks/editor_dock_manager.h +++ b/editor/docks/editor_dock_manager.h @@ -132,6 +132,7 @@ class EditorDockManager : public Object { static EditorDockManager *get_singleton() { return singleton; } DockTabContainer *get_dock_container(int p_slot) const; + EditorDock *get_dock_by_name(const String &p_name) const; void update_docks_menu(); void update_tab_styles(); @@ -177,7 +178,6 @@ class DockSlotGrid : public Control { int hovered_slot = -1; Rect2 rect_cache[EditorDock::DOCK_SLOT_MAX]; - Rect2 main_screen_rect; bool rect_cache_dirty = true; void _update_rect_cache(); diff --git a/editor/docks/inspector_dock.cpp b/editor/docks/inspector_dock.cpp index 2bc104101d06..3a66f5064688 100644 --- a/editor/docks/inspector_dock.cpp +++ b/editor/docks/inspector_dock.cpp @@ -111,7 +111,7 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { case OBJECT_REQUEST_HELP: { if (current) { - EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); + ScriptEditor::get_singleton()->focus_editor(); emit_signal(SNAME("request_help"), current->get_class()); } } break; diff --git a/editor/docks/scene_tree_dock.cpp b/editor/docks/scene_tree_dock.cpp index da29213f027a..c223a672796d 100644 --- a/editor/docks/scene_tree_dock.cpp +++ b/editor/docks/scene_tree_dock.cpp @@ -1323,7 +1323,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { ScriptEditor::get_singleton()->goto_help("class_name:" + class_name); } - EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT); + ScriptEditor::get_singleton()->focus_editor(); } break; case TOOL_AUTO_EXPAND: { scene_tree->set_auto_expand_selected(!EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), true); diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp index 3013152c70b9..ac90d389c162 100644 --- a/editor/editor_interface.cpp +++ b/editor/editor_interface.cpp @@ -36,6 +36,7 @@ #include "core/io/resource_loader.h" #include "core/object/callable_mp.h" #include "core/object/class_db.h" +#include "editor/docks/editor_dock_manager.h" #include "editor/docks/filesystem_dock.h" #include "editor/docks/inspector_dock.h" #include "editor/editor_main_screen.h" @@ -421,9 +422,11 @@ Control *EditorInterface::get_base_control() const { return EditorNode::get_singleton()->get_gui_base(); } +#ifndef DISABLE_DEPRECATED VBoxContainer *EditorInterface::get_editor_main_screen() const { return EditorNode::get_singleton()->get_editor_main_screen()->get_control(); } +#endif ScriptEditor *EditorInterface::get_script_editor() const { return ScriptEditor::get_singleton(); @@ -438,8 +441,16 @@ SubViewport *EditorInterface::get_editor_viewport_3d(int p_idx) const { return Node3DEditor::get_singleton()->get_editor_viewport(p_idx)->get_viewport_node(); } +#ifndef DISABLE_DEPRECATED void EditorInterface::set_main_screen_editor(const String &p_name) { - EditorNode::get_singleton()->get_editor_main_screen()->select_by_name(p_name); + EditorDock *dock = EditorNode::get_singleton()->get_editor_main_screen()->get_dock_by_name(p_name); + ERR_FAIL_NULL_MSG(dock, "The editor name '" + p_name + "' was not found."); + EditorDockManager::get_singleton()->focus_dock(dock); +} +#endif + +EditorDock *EditorInterface::get_dock_by_name(const String &p_name) { + return EditorDockManager::get_singleton()->get_dock_by_name(p_name); } void EditorInterface::set_distraction_free_mode(bool p_enter) { @@ -836,11 +847,14 @@ bool EditorInterface::is_movie_maker_enabled() const { void EditorInterface::get_argument_options(const StringName &p_function, int p_idx, List *r_options) const { const String pf = p_function; if (p_idx == 0) { +#ifndef DISABLE_DEPRECATED if (pf == "set_main_screen_editor") { - for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"Game\"", "\"AssetLib\"" }) { + for (String E : { "\"2D\"", "\"3D\"", "\"Script\"", "\"Game\"", "\"Asset Store\"" }) { r_options->push_back(E); } - } else if (pf == "get_editor_viewport_3d") { + } +#endif + if (pf == "get_editor_viewport_3d") { for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) { r_options->push_back(String::num_int64(i)); } @@ -876,12 +890,15 @@ void EditorInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_editor_theme"), &EditorInterface::get_editor_theme); ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control); - ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen); ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor); ClassDB::bind_method(D_METHOD("get_editor_viewport_2d"), &EditorInterface::get_editor_viewport_2d); ClassDB::bind_method(D_METHOD("get_editor_viewport_3d", "idx"), &EditorInterface::get_editor_viewport_3d, DEFVAL(0)); +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen); ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor); +#endif + ClassDB::bind_method(D_METHOD("get_dock_by_name", "name"), &EditorInterface::get_dock_by_name); ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode); ClassDB::bind_method(D_METHOD("is_distraction_free_mode_enabled"), &EditorInterface::is_distraction_free_mode_enabled); ClassDB::bind_method(D_METHOD("is_multi_window_enabled"), &EditorInterface::is_multi_window_enabled); diff --git a/editor/editor_interface.h b/editor/editor_interface.h index 64b808cc0c5f..49d729e0729a 100644 --- a/editor/editor_interface.h +++ b/editor/editor_interface.h @@ -37,6 +37,7 @@ class Control; class CreateDialog; class EditorCommandPalette; +class EditorDock; class EditorFileSystem; class EditorInspector; class EditorPaths; @@ -122,12 +123,17 @@ class EditorInterface : public Object { Ref get_editor_theme() const; Control *get_base_control() const; +#ifndef DISABLE_DEPRECATED VBoxContainer *get_editor_main_screen() const; +#endif ScriptEditor *get_script_editor() const; SubViewport *get_editor_viewport_2d() const; SubViewport *get_editor_viewport_3d(int p_idx = 0) const; +#ifndef DISABLE_DEPRECATED void set_main_screen_editor(const String &p_name); +#endif + EditorDock *get_dock_by_name(const String &p_name); void set_distraction_free_mode(bool p_enter); bool is_distraction_free_mode_enabled() const; bool is_multi_window_enabled() const; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index f9decd6b6495..51c3cb2ff193 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -222,6 +222,7 @@ void EditorLog::_meta_clicked(const String &p_meta) { // Avoid re-editing the current script without the clicked line number. editor_node->push_item(res.ptr(), "", true); } + ScriptEditor::get_singleton()->focus_script_editor(res); } } else if (path.has_extension("cpp") || path.has_extension("h") || path.has_extension("mm") || path.has_extension("hpp")) { // Godot source file. Try to open it in external editor. diff --git a/editor/editor_main_screen.cpp b/editor/editor_main_screen.cpp index aad79076e65d..a311761a16f2 100644 --- a/editor/editor_main_screen.cpp +++ b/editor/editor_main_screen.cpp @@ -30,296 +30,207 @@ #include "editor_main_screen.h" -#include "core/io/config_file.h" #include "core/object/callable_mp.h" +#include "editor/docks/editor_dock.h" +#include "editor/docks/editor_dock_manager.h" #include "editor/editor_node.h" -#include "editor/editor_string_names.h" #include "editor/plugins/editor_plugin.h" +#include "editor/scene/3d/node_3d_editor_plugin.h" +#include "editor/script/script_editor_plugin.h" #include "editor/settings/editor_settings.h" -#include "scene/gui/box_container.h" -#include "scene/gui/button.h" +#include "editor/themes/editor_scale.h" -void EditorMainScreen::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - set_accessibility_region(true); - if (EDITOR_3D < buttons.size() && buttons[EDITOR_3D]->is_visible()) { - // If the 3D editor is enabled, use this as the default. - select(EDITOR_3D); - return; - } - - // Switch to the first main screen plugin that is enabled. Usually this is - // 2D, but may be subsequent ones if 2D is disabled in the feature profile. - for (int i = 0; i < buttons.size(); i++) { - Button *editor_button = buttons[i]; - if (editor_button->is_visible()) { - select(i); - return; - } - } - - select(-1); - } break; - case NOTIFICATION_THEME_CHANGED: { - for (int i = 0; i < buttons.size(); i++) { - Button *tb = buttons[i]; - EditorPlugin *p_editor = editor_table[i]; - Ref icon = p_editor->get_plugin_icon(); - - if (icon.is_valid()) { - tb->set_button_icon(icon); - } else if (has_theme_icon(p_editor->get_plugin_name(), EditorStringName(EditorIcons))) { - tb->set_button_icon(get_theme_icon(p_editor->get_plugin_name(), EditorStringName(EditorIcons))); - } - } - } break; +#ifndef DISABLE_DEPRECATED +void LegacyMainScreenContainer::_force_dock_visible(EditorDock *p_dock, CanvasItem *p_child) { + if (p_dock->is_visible_in_tree()) { + p_child->show(); } } -void EditorMainScreen::set_button_container(HBoxContainer *p_button_hb) { - button_hb = p_button_hb; -} - -void EditorMainScreen::save_layout_to_config(Ref p_config_file, const String &p_section) const { - int selected_main_editor_idx = -1; - for (int i = 0; i < buttons.size(); i++) { - if (buttons[i]->is_pressed()) { - selected_main_editor_idx = i; - break; - } - } - if (selected_main_editor_idx != -1) { - p_config_file->set_value(p_section, "selected_main_editor_idx", selected_main_editor_idx); - } else { - p_config_file->set_value(p_section, "selected_main_editor_idx", Variant()); - } -} - -void EditorMainScreen::load_layout_from_config(Ref p_config_file, const String &p_section) { - int selected_main_editor_idx = p_config_file->get_value(p_section, "selected_main_editor_idx", -1); - if (selected_main_editor_idx >= 0 && selected_main_editor_idx < buttons.size()) { - callable_mp(this, &EditorMainScreen::select).call_deferred(selected_main_editor_idx); +void LegacyMainScreenContainer::add_child_notify(Node *p_child) { + EditorMainScreen *ms = EditorNode::get_editor_main_screen(); + if (!ms->adding_plugin || !ms->adding_plugin->has_main_screen()) { + return; } -} -void EditorMainScreen::set_button_enabled(int p_index, bool p_enabled) { - ERR_FAIL_INDEX(p_index, buttons.size()); - buttons[p_index]->set_visible(p_enabled); - if (!p_enabled && buttons[p_index]->is_pressed()) { - select(EDITOR_2D); - } -} + EditorDock *dock = memnew(EditorDock); + dock->set_default_slot(EditorDock::DOCK_SLOT_MAIN_SCREEN); + dock->set_available_layouts(EditorDock::DOCK_LAYOUT_MAIN_SCREEN); + dock->set_title(ms->adding_plugin->get_plugin_name()); + dock->set_dock_icon(ms->adding_plugin->get_plugin_icon()); + dock->set_icon_name(ms->adding_plugin->get_plugin_name()); + EditorDockManager::get_singleton()->add_dock(dock); -bool EditorMainScreen::is_button_enabled(int p_index) const { - ERR_FAIL_INDEX_V(p_index, buttons.size(), false); - return buttons[p_index]->is_visible(); -} + ms->adding_plugin->set_meta("_dock", dock); -int EditorMainScreen::_get_current_main_editor() const { - for (int i = 0; i < editor_table.size(); i++) { - if (editor_table[i] == selected_plugin) { - return i; - } + CanvasItem *ci_child = Object::cast_to(p_child); + if (ci_child) { + ci_child->show(); + dock->connect(SceneStringName(visibility_changed), callable_mp(this, &LegacyMainScreenContainer::_force_dock_visible).bind(dock, ci_child)); } - return 0; + callable_mp(p_child, &Node::reparent).call_deferred(dock, false); } +#endif -void EditorMainScreen::select_next() { - int editor = _get_current_main_editor(); +void EditorMainScreen::_on_tab_changed(int p_tab) { + EditorNode::get_singleton()->update_distraction_free_mode(); - do { - if (editor == editor_table.size() - 1) { - editor = 0; - } else { - editor++; - } - } while (!buttons[editor]->is_visible()); + EditorDock *dock = get_dock(p_tab); + if (!dock) { + return; + } + const String new_main_screen = dock->get_display_title(); - select(editor); + EditorData &editor_data = EditorNode::get_editor_data(); + int plugin_count = editor_data.get_editor_plugin_count(); + for (int i = 0; i < plugin_count; i++) { + editor_data.get_editor_plugin(i)->notify_main_screen_changed(new_main_screen); + } } -void EditorMainScreen::select_prev() { - int editor = _get_current_main_editor(); - - do { - if (editor == 0) { - editor = editor_table.size() - 1; - } else { - editor--; - } - } while (!buttons[editor]->is_visible()); - - select(editor); -} +void EditorMainScreen::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + set_tab_alignment(TabBar::ALIGNMENT_CENTER); + get_internal_container()->set_alignment(BoxContainer::ALIGNMENT_CENTER); + connect("tab_changed", callable_mp(this, &EditorMainScreen::_on_tab_changed)); + } break; -void EditorMainScreen::select_by_name(const String &p_name) { - ERR_FAIL_COND(p_name.is_empty()); + case NOTIFICATION_READY: { + set_popup(nullptr); - for (int i = 0; i < buttons.size(); i++) { - if (buttons[i]->get_text() == p_name) { - select(i); - return; - } + for (int i = 0; i < get_tab_count(); i++) { + EditorDock *dock = get_dock(i); + if (dock == Node3DEditor::get_singleton()) { + dock->make_visible(); + break; + } + } + } break; } - - ERR_FAIL_MSG("The editor name '" + p_name + "' was not found."); } -void EditorMainScreen::select(int p_index) { - if (EditorNode::get_singleton()->is_changing_scene()) { - return; - } +DockTabContainer::TabStyle EditorMainScreen::get_tab_style() const { + return (TabStyle)EDITOR_GET("interface/editor/docks/main_screen_dock_tab_style").operator int(); +} - ERR_FAIL_INDEX(p_index, editor_table.size()); +Rect2 EditorMainScreen::get_drag_hint_rect() const { + const Rect2 tab_rect = get_internal_container()->get_global_rect(); + const Rect2 content_rect = get_global_rect(); + Rect2 final_rect = tab_rect.merge(content_rect); + float tab_x = get_tab_bar()->get_global_transform().xform(get_tab_bar()->get_tab_rect(0).position).x; + final_rect.position.x = MIN(tab_x, content_rect.position.x); + tab_x = get_tab_bar()->get_global_transform().xform(get_tab_bar()->get_tab_rect(-1).get_end()).x; + final_rect.set_end(Vector2(MAX(tab_x, content_rect.get_end().x), final_rect.get_end().y)); + return final_rect; +} - if (!buttons[p_index]->is_visible()) { // Button hidden, no editor. - return; +void EditorMainScreen::edit(Object *p_object) { + EditorPlugin *handling_plugin = EditorNode::get_editor_data().get_handling_main_editor(p_object); + if (selected_plugin) { + if (handling_plugin == selected_plugin) { + selected_plugin->edit(p_object); + } else { + selected_plugin->edit(nullptr); + if (handling_plugin) { + selected_plugin->make_visible(false); + } + } } - - for (int i = 0; i < buttons.size(); i++) { - buttons[i]->set_pressed_no_signal(i == p_index); + selected_plugin = handling_plugin; + if (selected_plugin) { + selected_plugin->edit(p_object); + selected_plugin->make_visible(true); } +} - EditorPlugin *new_editor = editor_table[p_index]; - ERR_FAIL_NULL(new_editor); - - if (selected_plugin == new_editor) { +void EditorMainScreen::select_next() { + if (get_tab_count() == 0) { return; } - - if (selected_plugin) { - selected_plugin->make_visible(false); - } - - selected_plugin = new_editor; - selected_plugin->make_visible(true); - selected_plugin->selected_notify(); - set_accessibility_name(selected_plugin->get_plugin_name()); - - EditorData &editor_data = EditorNode::get_editor_data(); - int plugin_count = editor_data.get_editor_plugin_count(); - for (int i = 0; i < plugin_count; i++) { - editor_data.get_editor_plugin(i)->notify_main_screen_changed(selected_plugin->get_plugin_name()); + if (get_current_tab() < get_tab_count() - 1) { + set_current_tab(get_current_tab() + 1); + } else { + set_current_tab(0); } - - EditorNode::get_singleton()->update_distraction_free_mode(); } -int EditorMainScreen::get_selected_index() const { - for (int i = 0; i < editor_table.size(); i++) { - if (selected_plugin == editor_table[i]) { - return i; - } +void EditorMainScreen::select_prev() { + if (get_tab_count() == 0) { + return; } - return -1; -} - -int EditorMainScreen::get_plugin_index(EditorPlugin *p_editor) const { - int screen = -1; - for (int i = 0; i < editor_table.size(); i++) { - if (p_editor == editor_table[i]) { - screen = i; - break; - } + if (get_current_tab() > 0) { + set_current_tab(get_current_tab() - 1); + } else { + set_current_tab(get_tab_count() - 1); } - return screen; } EditorPlugin *EditorMainScreen::get_selected_plugin() const { return selected_plugin; } -EditorPlugin *EditorMainScreen::get_plugin_by_name(const String &p_plugin_name) const { - ERR_FAIL_COND_V(!main_editor_plugins.has(p_plugin_name), nullptr); - return main_editor_plugins[p_plugin_name]; -} - bool EditorMainScreen::can_auto_switch_screens() const { if (selected_plugin == nullptr) { return true; } - // Only allow auto-switching if the selected button is to the left of the Script button. - for (int i = 0; i < button_hb->get_child_count(); i++) { - Button *button = Object::cast_to