Explorar o código

Merge pull request #89017 from kitbdev/add-close-docks

Allow docks to be closed and opened
Rémi Verschelde hai 1 ano
pai
achega
b5369ee3b3

+ 92 - 13
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<Texture2D> 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<Control *, DockInfo> &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<ConfigFile> 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<ConfigFile> 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<ConfigFile> 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<ConfigFile> 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<ConfigFile> 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<Shortcut> &p_shortcut) {
+void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref<Shortcut> &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);
 }

+ 13 - 4
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> shortcut;
 	};
 
@@ -100,6 +101,8 @@ private:
 	bool docks_visible = true;
 
 	DockContextPopup *dock_context_popup = nullptr;
+	PopupMenu *docks_menu = nullptr;
+	Vector<Control *> 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<ConfigFile> p_layout, const String &p_section) const;
 	void load_docks_from_config(Ref<ConfigFile> 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<Shortcut> &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<Shortcut> &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();
 

+ 8 - 6
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);

+ 2 - 2
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<Shortcut> &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) {

+ 2 - 2
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);