From 860bff926e34f5ff09560ff0e075724593d13058 Mon Sep 17 00:00:00 2001 From: kit Date: Sat, 28 Oct 2023 10:13:12 -0400 Subject: [PATCH] Allow docks to be closed --- editor/editor_dock_manager.cpp | 105 +++++++++++++++--- editor/editor_dock_manager.h | 17 ++- editor/editor_node.cpp | 14 ++- editor/editor_plugin.cpp | 4 +- .../plugins/version_control_editor_plugin.cpp | 4 +- 5 files changed, 117 insertions(+), 27 deletions(-) diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp index 3fba07f6860..b6250671ee1 100644 --- a/editor/editor_dock_manager.cpp +++ b/editor/editor_dock_manager.cpp @@ -149,17 +149,53 @@ void EditorDockManager::_update_layout() { } EditorNode::get_singleton()->edit_current(); dock_context_popup->docks_updated(); + _update_docks_menu(); EditorNode::get_singleton()->save_editor_layout_delayed(); } +void EditorDockManager::_update_docks_menu() { + docks_menu->clear(); + docks_menu->reset_size(); + + const Ref icon = docks_menu->get_editor_theme_icon(SNAME("Window")); + const Color closed_icon_color_mod = Color(1, 1, 1, 0.5); + + // Add docks. + docks_menu_docks.clear(); + int id = 0; + for (const KeyValue &dock : all_docks) { + if (dock.value.shortcut.is_valid()) { + docks_menu->add_shortcut(dock.value.shortcut, id); + docks_menu->set_item_text(id, dock.value.title); + } else { + docks_menu->add_item(dock.value.title, id); + } + docks_menu->set_item_icon(id, icon); + if (!dock.value.open) { + docks_menu->set_item_icon_modulate(id, closed_icon_color_mod); + } + docks_menu->set_item_disabled(id, !dock.value.enabled); + docks_menu_docks.push_back(dock.key); + id++; + } +} + +void EditorDockManager::_docks_menu_option(int p_id) { + focus_dock(docks_menu_docks[p_id]); +} + void EditorDockManager::_window_close_request(WindowWrapper *p_wrapper) { // Give the dock back to the original owner. Control *dock = _close_window(p_wrapper); ERR_FAIL_COND(!all_docks.has(dock)); - all_docks[dock].open = false; - open_dock(dock); - focus_dock(dock); + if (all_docks[dock].previous_at_bottom || all_docks[dock].dock_slot_index != DOCK_SLOT_NONE) { + all_docks[dock].open = false; + open_dock(dock); + focus_dock(dock); + } else { + close_dock(dock); + } } Control *EditorDockManager::_close_window(WindowWrapper *p_wrapper) { @@ -174,7 +210,7 @@ Control *EditorDockManager::_close_window(WindowWrapper *p_wrapper) { return dock; } -void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window) { +void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window, bool p_reset_size) { ERR_FAIL_NULL(p_dock); Size2 borders = Size2(4, 4) * EDSCALE; @@ -201,6 +237,12 @@ void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window if (p_show_window) { wrapper->restore_window(Rect2i(dock_screen_pos, dock_size), EditorNode::get_singleton()->get_gui_base()->get_window()->get_current_screen()); _update_layout(); + if (p_reset_size) { + // Use a default size of one third the current window size. + Size2i popup_size = EditorNode::get_singleton()->get_window()->get_size() / 3.0; + p_dock->get_window()->set_size(popup_size); + p_dock->get_window()->move_to_center(); + } p_dock->get_window()->grab_focus(); } } @@ -338,6 +380,10 @@ void EditorDockManager::save_docks_to_config(Ref p_layout, const Str p_layout->set_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx", selected_tab_idx); } } + if (p_layout->has_section_key(p_section, "dock_0")) { + // Clear the keys where the dock has no slot so it is overridden. + p_layout->erase_section_key(p_section, "dock_0"); + } // Save docks in windows. Dictionary floating_docks_dump; @@ -425,8 +471,8 @@ void EditorDockManager::load_docks_from_config(Ref p_layout, const S dock_map[dock.key->get_name()] = dock.key; } - // Load docks by slot. - for (int i = 0; i < DOCK_SLOT_MAX; i++) { + // Load docks by slot. Index -1 is for docks that have no slot. + for (int i = -1; i < DOCK_SLOT_MAX; i++) { if (!p_layout->has_section_key(p_section, "dock_" + itos(i + 1))) { continue; } @@ -450,7 +496,7 @@ void EditorDockManager::load_docks_from_config(Ref p_layout, const S _restore_dock_to_saved_window(dock, floating_docks_dump[name]); } else if (dock_bottom.has(name)) { _dock_move_to_bottom(dock); - } else { + } else if (i >= 0) { _move_dock(dock, dock_slot[i], 0); } @@ -465,7 +511,7 @@ void EditorDockManager::load_docks_from_config(Ref p_layout, const S } all_docks[dock].dock_slot_index = i; - all_docks[dock].previous_tab_index = j; + all_docks[dock].previous_tab_index = i >= 0 ? j : 0; } } @@ -500,6 +546,8 @@ void EditorDockManager::load_docks_from_config(Ref p_layout, const S } FileSystemDock::get_singleton()->load_layout_from_config(p_layout, p_section); + + _update_docks_menu(); } void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock) { @@ -564,13 +612,16 @@ void EditorDockManager::open_dock(Control *p_dock, bool p_set_current) { // Open dock to its previous location. if (all_docks[p_dock].previous_at_bottom) { _dock_move_to_bottom(p_dock); - } else { + } 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; if (tab_index < 0) { tab_index = slot->get_tab_count(); } _move_dock(p_dock, slot, tab_index, p_set_current); + } else { + _open_dock_in_window(p_dock, true, true); + return; } _update_layout(); @@ -615,9 +666,8 @@ void EditorDockManager::focus_dock(Control *p_dock) { tab_container->set_current_tab(tab_index); } -void EditorDockManager::add_control_to_dock(DockSlot p_slot, Control *p_dock, const String &p_title, const Ref &p_shortcut) { +void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref &p_shortcut) { ERR_FAIL_NULL(p_dock); - ERR_FAIL_INDEX(p_slot, DOCK_SLOT_MAX); ERR_FAIL_COND_MSG(all_docks.has(p_dock), vformat("Cannot add dock '%s', already added.", p_dock->get_name())); DockInfo dock_info; @@ -626,10 +676,17 @@ void EditorDockManager::add_control_to_dock(DockSlot p_slot, Control *p_dock, co dock_info.shortcut = p_shortcut; all_docks[p_dock] = dock_info; - open_dock(p_dock, false); + if (p_slot != DOCK_SLOT_NONE) { + ERR_FAIL_INDEX(p_slot, DOCK_SLOT_MAX); + open_dock(p_dock, false); + } else { + closed_dock_parent->add_child(p_dock); + p_dock->hide(); + _update_layout(); + } } -void EditorDockManager::remove_control_from_dock(Control *p_dock) { +void EditorDockManager::remove_dock(Control *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())); @@ -688,6 +745,10 @@ int EditorDockManager::get_vsplit_count() const { return vsplits.size(); } +PopupMenu *EditorDockManager::get_docks_menu() { + return docks_menu; +} + EditorDockManager::EditorDockManager() { singleton = this; @@ -695,6 +756,10 @@ EditorDockManager::EditorDockManager() { dock_context_popup = memnew(DockContextPopup); EditorNode::get_singleton()->get_gui_base()->add_child(dock_context_popup); + + docks_menu = memnew(PopupMenu); + docks_menu->connect("id_pressed", callable_mp(this, &EditorDockManager::_docks_menu_option)); + EditorNode::get_singleton()->get_gui_base()->connect("theme_changed", callable_mp(this, &EditorDockManager::_update_docks_menu)); } void DockContextPopup::_notification(int p_what) { @@ -715,6 +780,7 @@ void DockContextPopup::_notification(int p_what) { tab_move_right_button->set_tooltip_text(TTR("Move this dock right one tab.")); } dock_to_bottom_button->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide"))); + close_button->set_icon(get_editor_theme_icon(SNAME("Close"))); } break; } } @@ -741,6 +807,11 @@ void DockContextPopup::_tab_move_right() { dock_select->queue_redraw(); } +void DockContextPopup::_close_dock() { + hide(); + dock_manager->close_dock(context_dock); +} + void DockContextPopup::_float_dock() { hide(); dock_manager->_open_dock_in_window(context_dock); @@ -975,4 +1046,12 @@ DockContextPopup::DockContextPopup() { dock_to_bottom_button->connect("pressed", callable_mp(this, &DockContextPopup::_move_dock_to_bottom)); dock_to_bottom_button->hide(); dock_select_popup_vb->add_child(dock_to_bottom_button); + + close_button = memnew(Button); + close_button->set_text(TTR("Close")); + close_button->set_tooltip_text(TTR("Close this dock.")); + close_button->set_focus_mode(Control::FOCUS_NONE); + close_button->set_h_size_flags(Control::SIZE_EXPAND_FILL); + close_button->connect("pressed", callable_mp(this, &DockContextPopup::_close_dock)); + dock_select_popup_vb->add_child(close_button); } diff --git a/editor/editor_dock_manager.h b/editor/editor_dock_manager.h index 370c149967c..cbb076c8093 100644 --- a/editor/editor_dock_manager.h +++ b/editor/editor_dock_manager.h @@ -62,6 +62,7 @@ class EditorDockManager : public Object { public: enum DockSlot { + DOCK_SLOT_NONE = -1, DOCK_SLOT_LEFT_UL, DOCK_SLOT_LEFT_BL, DOCK_SLOT_LEFT_UR, @@ -84,7 +85,7 @@ private: int previous_tab_index = -1; bool previous_at_bottom = false; WindowWrapper *dock_window = nullptr; - int dock_slot_index = DOCK_SLOT_LEFT_UL; + int dock_slot_index = DOCK_SLOT_NONE; Ref shortcut; }; @@ -100,6 +101,8 @@ private: bool docks_visible = true; DockContextPopup *dock_context_popup = nullptr; + PopupMenu *docks_menu = nullptr; + Vector docks_menu_docks; Control *closed_dock_parent = nullptr; void _dock_split_dragged(int p_offset); @@ -108,9 +111,12 @@ private: void _dock_container_update_visibility(TabContainer *p_dock_container); void _update_layout(); + void _update_docks_menu(); + 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); + 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); void _dock_move_to_bottom(Control *p_dock); @@ -127,6 +133,7 @@ public: void add_hsplit(DockSplitContainer *p_split); void register_dock_slot(DockSlot p_dock_slot, TabContainer *p_tab_container); int get_vsplit_count() const; + PopupMenu *get_docks_menu(); 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); @@ -143,8 +150,8 @@ public: void set_docks_visible(bool p_show); bool are_docks_visible() const; - void add_control_to_dock(DockSlot p_slot, Control *p_dock, const String &p_title = "", const Ref &p_shortcut = nullptr); - void remove_control_from_dock(Control *p_dock); + void add_dock(Control *p_dock, const String &p_title = "", DockSlot p_slot = DOCK_SLOT_NONE, const Ref &p_shortcut = nullptr); + void remove_dock(Control *p_dock); EditorDockManager(); }; @@ -157,6 +164,7 @@ class DockContextPopup : public PopupPanel { Button *make_float_button = nullptr; Button *tab_move_left_button = nullptr; Button *tab_move_right_button = nullptr; + Button *close_button = nullptr; Button *dock_to_bottom_button = nullptr; Control *dock_select = nullptr; @@ -169,6 +177,7 @@ class DockContextPopup : public PopupPanel { void _tab_move_left(); void _tab_move_right(); + void _close_dock(); void _float_dock(); void _move_dock_to_bottom(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index edb6fee75c9..008fd7bc10c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6829,6 +6829,8 @@ EditorNode::EditorNode() { settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE); settings_menu->add_separator(); + settings_menu->add_submenu_node_item(TTR("Editor Docks"), editor_dock_manager->get_docks_menu()); + editor_layouts = memnew(PopupMenu); editor_layouts->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); settings_menu->add_submenu_node_item(TTR("Editor Layout"), editor_layouts); @@ -6998,22 +7000,22 @@ EditorNode::EditorNode() { history_dock = memnew(HistoryDock); // Scene: Top left. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_UR, SceneTreeDock::get_singleton(), TTR("Scene")); + editor_dock_manager->add_dock(SceneTreeDock::get_singleton(), TTR("Scene"), EditorDockManager::DOCK_SLOT_LEFT_UR); // Import: Top left, behind Scene. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_UR, ImportDock::get_singleton(), TTR("Import")); + editor_dock_manager->add_dock(ImportDock::get_singleton(), TTR("Import"), EditorDockManager::DOCK_SLOT_LEFT_UR); // FileSystem: Bottom left. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_BR, FileSystemDock::get_singleton(), TTR("FileSystem"), ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F)); + editor_dock_manager->add_dock(FileSystemDock::get_singleton(), TTR("FileSystem"), EditorDockManager::DOCK_SLOT_LEFT_BR, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F)); // Inspector: Full height right. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, InspectorDock::get_singleton(), TTR("Inspector")); + editor_dock_manager->add_dock(InspectorDock::get_singleton(), TTR("Inspector"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // Node: Full height right, behind Inspector. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, NodeDock::get_singleton(), TTR("Node")); + editor_dock_manager->add_dock(NodeDock::get_singleton(), TTR("Node"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // History: Full height right, behind Node. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, history_dock, TTR("History")); + editor_dock_manager->add_dock(history_dock, TTR("History"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // 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/editor_plugin.cpp b/editor/editor_plugin.cpp index 67fe0c2e28e..f42a1555a2a 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -87,12 +87,12 @@ Button *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const Stri 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_control_to_dock(EditorDockManager::DockSlot(p_slot), p_control, String(), p_shortcut); + EditorDockManager::get_singleton()->add_dock(p_control, String(), EditorDockManager::DockSlot(p_slot), p_shortcut); } void EditorPlugin::remove_control_from_docks(Control *p_control) { ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->remove_control_from_dock(p_control); + EditorDockManager::get_singleton()->remove_dock(p_control); } void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) { diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 1a602568fe0..91738384717 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -911,7 +911,7 @@ void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() { } void VersionControlEditorPlugin::register_editor() { - EditorDockManager::get_singleton()->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, version_commit_dock); + EditorDockManager::get_singleton()->add_dock(version_commit_dock, "", EditorDockManager::DOCK_SLOT_RIGHT_UL); version_control_dock_button = EditorNode::get_bottom_panel()->add_item(TTR("Version Control"), version_control_dock, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_version_control_bottom_panel", TTR("Toggle Version Control Bottom Panel"))); @@ -931,7 +931,7 @@ void VersionControlEditorPlugin::shut_down() { memdelete(EditorVCSInterface::get_singleton()); EditorVCSInterface::set_singleton(nullptr); - EditorDockManager::get_singleton()->remove_control_from_dock(version_commit_dock); + EditorDockManager::get_singleton()->remove_dock(version_commit_dock); EditorNode::get_bottom_panel()->remove_item(version_control_dock); _set_vcs_ui_state(false);