From dc46163b121993229fedc7853000bd9bcb9ec2de Mon Sep 17 00:00:00 2001 From: Hendrik Brucker Date: Thu, 11 May 2023 04:17:03 +0200 Subject: [PATCH] Improve editor state persistence --- doc/classes/EditorSettings.xml | 3 + doc/classes/TreeItem.xml | 20 +- editor/debugger/script_editor_debugger.cpp | 8 + editor/debugger/script_editor_debugger.h | 2 + editor/editor_data.cpp | 8 +- editor/editor_data.h | 4 +- editor/editor_node.cpp | 296 ++++++++++++++----- editor/editor_node.h | 19 +- editor/editor_plugin.cpp | 2 +- editor/editor_settings.cpp | 3 + editor/filesystem_dock.cpp | 196 ++++++------ editor/filesystem_dock.h | 10 +- editor/plugins/canvas_item_editor_plugin.cpp | 4 - editor/plugins/node_3d_editor_plugin.cpp | 57 ++-- editor/plugins/node_3d_editor_plugin.h | 15 +- editor/plugins/script_editor_plugin.cpp | 22 +- editor/plugins/shader_editor_plugin.cpp | 85 +++++- editor/plugins/shader_editor_plugin.h | 5 +- scene/gui/tree.cpp | 49 ++- scene/gui/tree.h | 8 +- 20 files changed, 557 insertions(+), 259 deletions(-) diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index b45e03dc384..6a27bff7631 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -416,6 +416,9 @@ If [code]true[/code], displays the polygon's previous shape in the 2D polygon editors with an opaque gray outline. This outline is displayed while dragging a point until the left mouse button is released. + + If [code]true[/code], reopens shader files that were open in the shader editor when the project was last closed. + If [code]true[/code], displays a grid while the TileMap editor is active. See also [member editors/tiles_editor/grid_color]. diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index b97b4bf17d4..6b6851daf19 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -226,11 +226,19 @@ Returns the next sibling TreeItem in the tree or a null object if there is none. + + + + + Returns the next TreeItem in the tree (in the context of a depth-first search) or a [code]null[/code] object if there is none. + If [param wrap] is enabled, the method will wrap around to the first element in the tree when called on the last element, otherwise it returns [code]null[/code]. + + - Returns the next visible sibling TreeItem in the tree or a null object if there is none. + Returns the next visible TreeItem in the tree (in the context of a depth-first search) or a [code]null[/code] object if there is none. If [param wrap] is enabled, the method will wrap around to the first visible element in the tree when called on the last visible element, otherwise it returns [code]null[/code]. @@ -246,11 +254,19 @@ Returns the previous sibling TreeItem in the tree or a null object if there is none. + + + + + Returns the previous TreeItem in the tree (in the context of a depth-first search) or a [code]null[/code] object if there is none. + If [param wrap] is enabled, the method will wrap around to the last element in the tree when called on the first visible element, otherwise it returns [code]null[/code]. + + - Returns the previous visible sibling TreeItem in the tree or a null object if there is none. + Returns the previous visible sibling TreeItem in the tree (in the context of a depth-first search) or a [code]null[/code] object if there is none. If [param wrap] is enabled, the method will wrap around to the last visible element in the tree when called on the first visible element, otherwise it returns [code]null[/code]. diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index a696e1ff1fc..b4ca499bcf1 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1704,6 +1704,14 @@ void ScriptEditorDebugger::remove_debugger_tab(Control *p_control) { p_control->queue_free(); } +int ScriptEditorDebugger::get_current_debugger_tab() const { + return tabs->get_current_tab(); +} + +void ScriptEditorDebugger::switch_to_debugger(int p_debugger_tab_idx) { + tabs->set_current_tab(p_debugger_tab_idx); +} + void ScriptEditorDebugger::send_message(const String &p_message, const Array &p_args) { _put_msg(p_message, p_args); } diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h index 1659bbee8da..336a1131634 100644 --- a/editor/debugger/script_editor_debugger.h +++ b/editor/debugger/script_editor_debugger.h @@ -284,6 +284,8 @@ public: void add_debugger_tab(Control *p_control); void remove_debugger_tab(Control *p_control); + int get_current_debugger_tab() const; + void switch_to_debugger(int p_debugger_tab_idx); void send_message(const String &p_message, const Array &p_args); void toggle_profiler(const String &p_profiler, bool p_enable, const Array &p_data); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 753f54b8075..5d3037b4ec9 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -300,7 +300,7 @@ void EditorData::get_editor_breakpoints(List *p_breakpoints) { } } -Dictionary EditorData::get_editor_states() const { +Dictionary EditorData::get_editor_plugin_states() const { Dictionary metadata; for (int i = 0; i < editor_plugins.size(); i++) { Dictionary state = editor_plugins[i]->get_state(); @@ -319,7 +319,7 @@ Dictionary EditorData::get_scene_editor_states(int p_idx) const { return es.editor_states; } -void EditorData::set_editor_states(const Dictionary &p_states) { +void EditorData::set_editor_plugin_states(const Dictionary &p_states) { if (p_states.is_empty()) { for (EditorPlugin *ep : editor_plugins) { ep->clear(); @@ -891,7 +891,7 @@ void EditorData::save_edited_scene_state(EditorSelection *p_selection, EditorSel es.selection = p_selection->get_full_selected_node_list(); es.history_current = p_history->current_elem_idx; es.history_stored = p_history->history; - es.editor_states = get_editor_states(); + es.editor_states = get_editor_plugin_states(); es.custom_state = p_custom; } @@ -907,7 +907,7 @@ Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection, for (Node *E : es.selection) { p_selection->add_node(E); } - set_editor_states(es.editor_states); + set_editor_plugin_states(es.editor_states); return es.custom_state; } diff --git a/editor/editor_data.h b/editor/editor_data.h index d4a2f534cdb..7ca04b56807 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -156,9 +156,9 @@ public: void copy_object_params(Object *p_object); void paste_object_params(Object *p_object); - Dictionary get_editor_states() const; + Dictionary get_editor_plugin_states() const; Dictionary get_scene_editor_states(int p_idx) const; - void set_editor_states(const Dictionary &p_states); + void set_editor_plugin_states(const Dictionary &p_states); void get_editor_breakpoints(List *p_breakpoints); void clear_editor_states(); void save_editor_external_data(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 7c85878d28b..6f763d59f4f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -67,6 +67,7 @@ #include "editor/audio_stream_preview.h" #include "editor/debugger/editor_debugger_node.h" +#include "editor/debugger/script_editor_debugger.h" #include "editor/dependency_editor.h" #include "editor/editor_about.h" #include "editor/editor_audio_buses.h" @@ -157,6 +158,8 @@ EditorNode *EditorNode::singleton = nullptr; // The metadata key used to store and retrieve the version text to copy to the clipboard. static const String META_TEXT_TO_COPY = "text_to_copy"; +static const String EDITOR_NODE_CONFIG_SECTION = "EditorNode"; + class AcceptDialogAutoReparent : public AcceptDialog { GDCLASS(AcceptDialogAutoReparent, AcceptDialog); @@ -1094,7 +1097,7 @@ void EditorNode::_sources_changed(bool p_exist) { EditorResourcePreview::get_singleton()->start(); } - _load_docks(); + _load_editor_layout(); if (!defer_load_scene.is_empty()) { Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene"); @@ -1463,39 +1466,28 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) { } } -void EditorNode::_get_scene_metadata(const String &p_file) { +void EditorNode::_load_editor_plugin_states_from_config(const Ref &p_config_file) { Node *scene = editor_data.get_edited_scene_root(); if (!scene) { return; } - String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); - - Ref cf; - cf.instantiate(); - - Error err = cf->load(path); - if (err != OK || !cf->has_section("editor_states")) { - // Must not exist. - return; - } - List esl; - cf->get_section_keys("editor_states", &esl); + p_config_file->get_section_keys("editor_states", &esl); Dictionary md; for (const String &E : esl) { - Variant st = cf->get_value("editor_states", E); + Variant st = p_config_file->get_value("editor_states", E); if (st.get_type() != Variant::NIL) { md[E] = st; } } - editor_data.set_editor_states(md); + editor_data.set_editor_plugin_states(md); } -void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { +void EditorNode::_save_editor_states(const String &p_file, int p_idx) { Node *scene = editor_data.get_edited_scene_root(p_idx); if (!scene) { @@ -1508,20 +1500,27 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { cf.instantiate(); Dictionary md; - if (p_idx < 0 || editor_data.get_edited_scene() == p_idx) { - md = editor_data.get_editor_states(); + md = editor_data.get_editor_plugin_states(); } else { md = editor_data.get_scene_editor_states(p_idx); } List keys; md.get_key_list(&keys); - for (const Variant &E : keys) { cf->set_value("editor_states", E, md[E]); } + // Save the currently selected nodes. + + List selection = editor_selection->get_full_selected_node_list(); + TypedArray selection_paths; + for (Node *selected_node : selection) { + selection_paths.push_back(selected_node->get_path()); + } + cf->set_value("editor_states", "selected_nodes", selection_paths); + Error err = cf->save(path); ERR_FAIL_COND_MSG(err != OK, "Cannot save config file to '" + path + "'."); } @@ -1813,7 +1812,7 @@ void EditorNode::_save_scene(String p_file, int idx) { _reset_animation_players(scene, &anim_backups); save_default_environment(); - _set_scene_metadata(p_file, idx); + _save_editor_states(p_file, idx); Ref sdata; @@ -2025,7 +2024,7 @@ void EditorNode::_dialog_action(String p_file) { save_default_environment(); _save_scene_with_preview(p_file, scene_idx); _add_to_recent_scenes(p_file); - save_layout(); + save_editor_layout_delayed(); if (scene_idx != -1) { _discard_changes(); @@ -2605,7 +2604,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (scene_idx != -1) { _discard_changes(); } - save_layout(); + save_editor_layout_delayed(); } else { show_save_accept(vformat(TTR("%s no longer exists! Please specify a new save location."), scene->get_scene_file_path().get_base_dir()), TTR("OK")); } @@ -3084,7 +3083,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { void EditorNode::_exit_editor(int p_exit_code) { exiting = true; resource_preview->stop(); // Stop early to avoid crashes. - _save_docks(); + _save_editor_layout(); // Dim the editor window while it's quitting to make it clearer that it's busy. dim_editor(true); @@ -3753,7 +3752,14 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b new_scene->set_scene_instance_state(Ref()); set_edited_scene(new_scene); - _get_scene_metadata(p_scene); + + String config_file_path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_scene.get_file() + "-editstate-" + p_scene.md5_text() + ".cfg"); + Ref editor_state_cf; + editor_state_cf.instantiate(); + Error editor_state_cf_err = editor_state_cf->load(config_file_path); + if (editor_state_cf_err == OK || editor_state_cf->has_section("editor_states")) { + _load_editor_plugin_states_from_config(editor_state_cf); + } _update_title(); _update_scene_tabs(); @@ -3774,8 +3780,20 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b push_item(new_scene); + // Load the selected nodes. + if (editor_state_cf->has_section_key("editor_states", "selected_nodes")) { + TypedArray selected_node_list = editor_state_cf->get_value("editor_states", "selected_nodes", TypedArray()); + + for (int i = 0; i < selected_node_list.size(); i++) { + Node *selected_node = new_scene->get_node_or_null(selected_node_list[i]); + if (selected_node) { + editor_selection->add_node(selected_node); + } + } + } + if (!restoring_scenes) { - save_layout(); + save_editor_layout_delayed(); } return OK; @@ -4609,7 +4627,7 @@ void EditorNode::_dock_select_input(const Ref &p_input) { _update_dock_containers(); _edit_current(); - _save_docks(); + _save_editor_layout(); } } } @@ -4635,7 +4653,7 @@ void EditorNode::_dock_move_left() { dock_slot[dock_popup_selected_idx]->move_child(current_ctl, prev_ctl->get_index(false)); dock_select->queue_redraw(); _edit_current(); - _save_docks(); + _save_editor_layout(); } void EditorNode::_dock_move_right() { @@ -4647,7 +4665,7 @@ void EditorNode::_dock_move_right() { dock_slot[dock_popup_selected_idx]->move_child(next_ctl, current_ctl->get_index(false)); dock_select->queue_redraw(); _edit_current(); - _save_docks(); + _save_editor_layout(); } void EditorNode::_dock_select_draw() { @@ -4736,7 +4754,7 @@ void EditorNode::_dock_select_draw() { } } -void EditorNode::_save_docks() { +void EditorNode::_save_editor_layout() { if (waiting_for_first_scan) { return; // Scanning, do not touch docks. } @@ -4746,7 +4764,8 @@ void EditorNode::_save_docks() { config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); _save_docks_to_config(config, "docks"); - _save_open_scenes_to_config(config, "EditorNode"); + _save_open_scenes_to_config(config); + _save_central_editor_layout_to_config(config); editor_data.get_plugin_window_layout(config); config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); @@ -4772,6 +4791,11 @@ void EditorNode::_save_docks_to_config(Ref p_layout, const String &p if (!names.is_empty()) { p_layout->set_value(p_section, config_key, names); } + + int selected_tab_idx = dock_slot[i]->get_current_tab(); + if (selected_tab_idx >= 0) { + p_layout->set_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx", selected_tab_idx); + } } Dictionary floating_docks_dump; @@ -4803,11 +4827,6 @@ void EditorNode::_save_docks_to_config(Ref p_layout, const String &p p_layout->set_value(p_section, "dock_floating", floating_docks_dump); - p_layout->set_value(p_section, "dock_filesystem_split", FileSystemDock::get_singleton()->get_split_offset()); - p_layout->set_value(p_section, "dock_filesystem_display_mode", FileSystemDock::get_singleton()->get_display_mode()); - p_layout->set_value(p_section, "dock_filesystem_file_sort", FileSystemDock::get_singleton()->get_file_sort()); - p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", FileSystemDock::get_singleton()->get_file_list_display_mode()); - for (int i = 0; i < vsplits.size(); i++) { if (vsplits[i]->is_visible_in_tree()) { p_layout->set_value(p_section, "dock_split_" + itos(i + 1), vsplits[i]->get_split_offset()); @@ -4817,10 +4836,21 @@ void EditorNode::_save_docks_to_config(Ref p_layout, const String &p for (int i = 0; i < hsplits.size(); i++) { p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), hsplits[i]->get_split_offset()); } + + // Save FileSystemDock state. + + p_layout->set_value(p_section, "dock_filesystem_split", FileSystemDock::get_singleton()->get_split_offset()); + p_layout->set_value(p_section, "dock_filesystem_display_mode", FileSystemDock::get_singleton()->get_display_mode()); + p_layout->set_value(p_section, "dock_filesystem_file_sort", FileSystemDock::get_singleton()->get_file_sort()); + p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", FileSystemDock::get_singleton()->get_file_list_display_mode()); + PackedStringArray selected_files = FileSystemDock::get_singleton()->get_selected_paths(); + p_layout->set_value(p_section, "dock_filesystem_selected_paths", selected_files); + Vector uncollapsed_paths = FileSystemDock::get_singleton()->get_uncollapsed_paths(); + p_layout->set_value(p_section, "dock_filesystem_uncollapsed_paths", uncollapsed_paths); } -void EditorNode::_save_open_scenes_to_config(Ref p_layout, const String &p_section) { - Array scenes; +void EditorNode::_save_open_scenes_to_config(Ref p_layout) { + PackedStringArray scenes; for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { String path = editor_data.get_scene_path(i); if (path.is_empty()) { @@ -4828,18 +4858,21 @@ void EditorNode::_save_open_scenes_to_config(Ref p_layout, const Str } scenes.push_back(path); } - p_layout->set_value(p_section, "open_scenes", scenes); + p_layout->set_value(EDITOR_NODE_CONFIG_SECTION, "open_scenes", scenes); + + String currently_edited_scene_path = editor_data.get_scene_path(editor_data.get_edited_scene()); + p_layout->set_value(EDITOR_NODE_CONFIG_SECTION, "current_scene", currently_edited_scene_path); } -void EditorNode::save_layout() { - dock_drag_timer->start(); +void EditorNode::save_editor_layout_delayed() { + editor_layout_save_delay_timer->start(); } void EditorNode::_dock_split_dragged(int ofs) { - dock_drag_timer->start(); + editor_layout_save_delay_timer->start(); } -void EditorNode::_load_docks() { +void EditorNode::_load_editor_layout() { Ref config; config.instantiate(); Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); @@ -4852,7 +4885,8 @@ void EditorNode::_load_docks() { } _load_docks_from_config(config, "docks"); - _load_open_scenes_from_config(config, "EditorNode"); + _load_open_scenes_from_config(config); + _load_central_editor_layout_from_config(config); editor_data.set_plugin_window_layout(config); } @@ -5031,26 +5065,15 @@ void EditorNode::_load_docks_from_config(Ref p_layout, const String _dock_floating_close_request(wrapper); } } - } - if (p_layout->has_section_key(p_section, "dock_filesystem_split")) { - int fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); - FileSystemDock::get_singleton()->set_split_offset(fs_split_ofs); - } + if (!p_layout->has_section_key(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx")) { + continue; + } - if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { - FileSystemDock::DisplayMode dock_filesystem_display_mode = FileSystemDock::DisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_display_mode"))); - FileSystemDock::get_singleton()->set_display_mode(dock_filesystem_display_mode); - } - - if (p_layout->has_section_key(p_section, "dock_filesystem_file_sort")) { - FileSystemDock::FileSortOption dock_filesystem_file_sort = FileSystemDock::FileSortOption(int(p_layout->get_value(p_section, "dock_filesystem_file_sort"))); - FileSystemDock::get_singleton()->set_file_sort(dock_filesystem_file_sort); - } - - if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) { - FileSystemDock::FileListDisplayMode dock_filesystem_file_list_display_mode = FileSystemDock::FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode"))); - FileSystemDock::get_singleton()->set_file_list_display_mode(dock_filesystem_file_list_display_mode); + int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx"); + if (selected_tab_idx >= 0 && selected_tab_idx < dock_slot[i]->get_tab_count()) { + dock_slot[i]->call_deferred("set_current_tab", selected_tab_idx); + } } for (int i = 0; i < vsplits.size(); i++) { @@ -5090,24 +5113,141 @@ void EditorNode::_load_docks_from_config(Ref p_layout, const String dock_slot[i]->set_current_tab(0); } } + + // FileSystemDock. + + if (p_layout->has_section_key(p_section, "dock_filesystem_split")) { + int fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); + FileSystemDock::get_singleton()->set_split_offset(fs_split_ofs); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { + FileSystemDock::DisplayMode dock_filesystem_display_mode = FileSystemDock::DisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_display_mode"))); + FileSystemDock::get_singleton()->set_display_mode(dock_filesystem_display_mode); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_file_sort")) { + FileSystemDock::FileSortOption dock_filesystem_file_sort = FileSystemDock::FileSortOption(int(p_layout->get_value(p_section, "dock_filesystem_file_sort"))); + FileSystemDock::get_singleton()->set_file_sort(dock_filesystem_file_sort); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) { + FileSystemDock::FileListDisplayMode dock_filesystem_file_list_display_mode = FileSystemDock::FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode"))); + FileSystemDock::get_singleton()->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"); + for (int i = 0; i < dock_filesystem_selected_paths.size(); i++) { + FileSystemDock::get_singleton()->select_file(dock_filesystem_selected_paths[i]); + } + } + + // Restore collapsed state of FileSystemDock. + if (p_layout->has_section_key(p_section, "dock_filesystem_uncollapsed_paths")) { + PackedStringArray uncollapsed_tis = p_layout->get_value(p_section, "dock_filesystem_uncollapsed_paths"); + for (int i = 0; i < uncollapsed_tis.size(); i++) { + TreeItem *uncollapsed_ti = FileSystemDock::get_singleton()->get_tree_control()->get_item_with_metadata(uncollapsed_tis[i], 0); + if (uncollapsed_ti) { + uncollapsed_ti->set_collapsed(false); + } + } + FileSystemDock::get_singleton()->get_tree_control()->queue_redraw(); + } } -void EditorNode::_load_open_scenes_from_config(Ref p_layout, const String &p_section) { +void EditorNode::_save_central_editor_layout_to_config(Ref p_config_file) { + // Bottom panel. + + int center_split_offset = center_split->get_split_offset(); + p_config_file->set_value(EDITOR_NODE_CONFIG_SECTION, "center_split_offset", center_split_offset); + + int selected_bottom_panel_item_idx = -1; + for (int i = 0; i < bottom_panel_items.size(); i++) { + if (bottom_panel_items[i].button->is_pressed()) { + selected_bottom_panel_item_idx = i; + break; + } + } + if (selected_bottom_panel_item_idx != -1) { + p_config_file->set_value(EDITOR_NODE_CONFIG_SECTION, "selected_bottom_panel_item", selected_bottom_panel_item_idx); + } + + // Debugger tab. + + int selected_default_debugger_tab_idx = EditorDebuggerNode::get_singleton()->get_default_debugger()->get_current_debugger_tab(); + p_config_file->set_value(EDITOR_NODE_CONFIG_SECTION, "selected_default_debugger_tab_idx", selected_default_debugger_tab_idx); + + // Main editor (plugin). + + int selected_main_editor_idx = -1; + for (int i = 0; i < main_editor_buttons.size(); i++) { + if (main_editor_buttons[i]->is_pressed()) { + selected_main_editor_idx = i; + break; + } + } + if (selected_main_editor_idx != -1) { + p_config_file->set_value(EDITOR_NODE_CONFIG_SECTION, "selected_main_editor_idx", selected_main_editor_idx); + } +} + +void EditorNode::_load_central_editor_layout_from_config(Ref p_config_file) { + // Bottom panel. + + if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "center_split_offset")) { + int center_split_offset = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "center_split_offset"); + center_split->set_split_offset(center_split_offset); + } + + if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "selected_bottom_panel_item")) { + int selected_bottom_panel_item_idx = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "selected_bottom_panel_item"); + if (selected_bottom_panel_item_idx >= 0 && selected_bottom_panel_item_idx < bottom_panel_items.size()) { + _bottom_panel_switch(true, selected_bottom_panel_item_idx); + } + } + + // Debugger tab. + + if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "selected_default_debugger_tab_idx")) { + int selected_default_debugger_tab_idx = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "selected_default_debugger_tab_idx"); + EditorDebuggerNode::get_singleton()->get_default_debugger()->switch_to_debugger(selected_default_debugger_tab_idx); + } + + // Main editor (plugin). + + if (p_config_file->has_section_key(EDITOR_NODE_CONFIG_SECTION, "selected_main_editor_idx")) { + int selected_main_editor_idx = p_config_file->get_value(EDITOR_NODE_CONFIG_SECTION, "selected_main_editor_idx"); + if (selected_main_editor_idx >= 0 && selected_main_editor_idx < main_editor_buttons.size()) { + callable_mp(this, &EditorNode::editor_select).call_deferred(selected_main_editor_idx); + } + } +} + +void EditorNode::_load_open_scenes_from_config(Ref p_layout) { if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) { return; } - if (!p_layout->has_section(p_section) || !p_layout->has_section_key(p_section, "open_scenes")) { + if (!p_layout->has_section(EDITOR_NODE_CONFIG_SECTION) || + !p_layout->has_section_key(EDITOR_NODE_CONFIG_SECTION, "open_scenes")) { return; } restoring_scenes = true; - Array scenes = p_layout->get_value(p_section, "open_scenes"); + PackedStringArray scenes = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "open_scenes"); for (int i = 0; i < scenes.size(); i++) { load_scene(scenes[i]); } - save_layout(); + + if (p_layout->has_section_key(EDITOR_NODE_CONFIG_SECTION, "current_scene")) { + String current_scene = p_layout->get_value(EDITOR_NODE_CONFIG_SECTION, "current_scene"); + int current_scene_idx = scenes.find(current_scene); + set_current_scene(current_scene_idx); + } + + save_editor_layout_delayed(); restoring_scenes = false; } @@ -5122,10 +5262,10 @@ bool EditorNode::has_scenes_in_session() { if (err != OK) { return false; } - if (!config->has_section("EditorNode") || !config->has_section_key("EditorNode", "open_scenes")) { + if (!config->has_section(EDITOR_NODE_CONFIG_SECTION) || !config->has_section_key(EDITOR_NODE_CONFIG_SECTION, "open_scenes")) { return false; } - Array scenes = config->get_value("EditorNode", "open_scenes"); + Array scenes = config->get_value(EDITOR_NODE_CONFIG_SECTION, "open_scenes"); return !scenes.is_empty(); } @@ -5251,7 +5391,7 @@ void EditorNode::_layout_menu_option(int p_id) { } break; case SETTINGS_LAYOUT_DEFAULT: { _load_docks_from_config(default_layout, "docks"); - _save_docks(); + _save_editor_layout(); } break; default: { Ref config; @@ -5262,7 +5402,7 @@ void EditorNode::_layout_menu_option(int p_id) { } _load_docks_from_config(config, editor_layouts->get_item_text(p_id)); - _save_docks(); + _save_editor_layout(); } } } @@ -5334,7 +5474,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int p_option) { _discard_changes(); } - save_layout(); + save_editor_layout_delayed(); _update_scene_tabs(); } @@ -5835,7 +5975,7 @@ void EditorNode::reload_scene(const String &p_path) { if (current_tab == scene_idx) { editor_data.apply_changes_in_editors(); - _set_scene_metadata(p_path); + _save_editor_states(p_path); } // Reload scene. @@ -6918,11 +7058,11 @@ EditorNode::EditorNode() { dock_slot[i]->set_use_hidden_tabs_for_min_size(true); } - dock_drag_timer = memnew(Timer); - add_child(dock_drag_timer); - dock_drag_timer->set_wait_time(0.5); - dock_drag_timer->set_one_shot(true); - dock_drag_timer->connect("timeout", callable_mp(this, &EditorNode::_save_docks)); + editor_layout_save_delay_timer = memnew(Timer); + add_child(editor_layout_save_delay_timer); + editor_layout_save_delay_timer->set_wait_time(0.5); + editor_layout_save_delay_timer->set_one_shot(true); + editor_layout_save_delay_timer->connect("timeout", callable_mp(this, &EditorNode::_save_editor_layout)); top_split = memnew(VSplitContainer); center_split->add_child(top_split); @@ -7403,7 +7543,7 @@ EditorNode::EditorNode() { 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_docks)); + filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_editor_layout)); get_project_settings()->connect_filesystem_dock_signals(filesystem_dock); history_dock = memnew(HistoryDock); diff --git a/editor/editor_node.h b/editor/editor_node.h index c6fe70fc8df..9917fa16bc6 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -430,7 +430,7 @@ private: PopupPanel *dock_select_popup = nullptr; Rect2 dock_select_rect[DOCK_SLOT_MAX]; TabContainer *dock_slot[DOCK_SLOT_MAX]; - Timer *dock_drag_timer = nullptr; + Timer *editor_layout_save_delay_timer = nullptr; bool docks_visible = true; int dock_popup_selected_idx = -1; int dock_select_rect_over_idx = -1; @@ -559,8 +559,8 @@ private: void _node_renamed(); void _editor_select_next(); void _editor_select_prev(); - void _set_scene_metadata(const String &p_file, int p_idx = -1); - void _get_scene_metadata(const String &p_file); + void _save_editor_states(const String &p_file, int p_idx = -1); + void _load_editor_plugin_states_from_config(const Ref &p_config_file); void _update_title(); void _update_scene_tabs(); void _version_control_menu_option(int p_idx); @@ -648,16 +648,19 @@ private: int _get_current_main_editor(); - void _save_docks(); - void _load_docks(); + void _save_editor_layout(); + void _load_editor_layout(); void _save_docks_to_config(Ref p_layout, const String &p_section); void _restore_floating_dock(const Dictionary &p_dock_dump, Control *p_wrapper, int p_slot_index); void _load_docks_from_config(Ref p_layout, const String &p_section); void _update_dock_slots_visibility(bool p_keep_selected_tabs = false); void _dock_tab_changed(int p_tab); - void _save_open_scenes_to_config(Ref p_layout, const String &p_section); - void _load_open_scenes_from_config(Ref p_layout, const String &p_section); + void _save_central_editor_layout_to_config(Ref p_config_file); + void _load_central_editor_layout_from_config(Ref p_config_file); + + void _save_open_scenes_to_config(Ref p_layout); + void _load_open_scenes_from_config(Ref p_layout); void _update_layouts_menu(); void _layout_menu_option(int p_id); @@ -884,7 +887,7 @@ public: bool is_scene_in_use(const String &p_path); - void save_layout(); + void save_editor_layout_delayed(); void save_default_environment(); void open_export_template_manager(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 442524d5792..9e22a0ead6f 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -471,7 +471,7 @@ bool EditorPlugin::build() { } void EditorPlugin::queue_save_layout() { - EditorNode::get_singleton()->save_layout(); + EditorNode::get_singleton()->save_editor_layout_delayed(); } void EditorPlugin::make_bottom_panel_item_visible(Control *p_item) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 5de2a47e0e3..0eb76c6011e 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -714,6 +714,9 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0)); _initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0)); + // Shader editor + _initial_set("editors/shader_editor/behavior/files/restore_shaders_on_load", true); + // Visual editors EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01") diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 169e78c0f5d..8695caafde0 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -87,14 +87,14 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_selectable(0, true); String lpath = p_dir->get_path(); subdirectory_item->set_metadata(0, lpath); - if (!p_select_in_favorites && (path == lpath || ((display_mode == DISPLAY_MODE_SPLIT) && path.get_base_dir() == lpath))) { + if (!p_select_in_favorites && (current_path == lpath || ((display_mode == DISPLAY_MODE_SPLIT) && current_path.get_base_dir() == lpath))) { subdirectory_item->select(0); // Keep select an item when re-created a tree // To prevent crashing when nothing is selected. subdirectory_item->set_as_cursor(0); } - if (p_unfold_path && path.begins_with(lpath) && path != lpath) { + if (p_unfold_path && current_path.begins_with(lpath) && current_path != lpath) { subdirectory_item->set_collapsed(false); } else { subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0); @@ -155,7 +155,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type)); String file_metadata = lpath.path_join(fi.name); file_item->set_metadata(0, file_metadata); - if (!p_select_in_favorites && path == file_metadata) { + if (!p_select_in_favorites && current_path == file_metadata) { file_item->select(0); file_item->set_as_cursor(0); } @@ -168,7 +168,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, this, "_tree_thumbnail_done", udata); } } else if (display_mode == DISPLAY_MODE_SPLIT) { - if (lpath.get_base_dir() == path.get_base_dir()) { + if (lpath.get_base_dir() == current_path.get_base_dir()) { subdirectory_item->select(0); subdirectory_item->set_as_cursor(0); } @@ -186,8 +186,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory return parent_should_expand; } -Vector FileSystemDock::_compute_uncollapsed_paths() { - // Register currently collapsed paths. +Vector FileSystemDock::get_uncollapsed_paths() const { Vector uncollapsed_paths; TreeItem *root = tree->get_root(); if (root) { @@ -196,21 +195,24 @@ Vector FileSystemDock::_compute_uncollapsed_paths() { uncollapsed_paths.push_back(favorites_item->get_metadata(0)); } - TreeItem *resTree = root->get_first_child()->get_next(); - if (resTree) { - Vector needs_check; - needs_check.push_back(resTree); + // BFS to find all uncollapsed paths of the resource directory. + TreeItem *res_subtree = root->get_first_child()->get_next(); + if (res_subtree) { + List queue; + queue.push_back(res_subtree); - while (needs_check.size()) { - if (!needs_check[0]->is_collapsed()) { - uncollapsed_paths.push_back(needs_check[0]->get_metadata(0)); - TreeItem *child = needs_check[0]->get_first_child(); - while (child) { - needs_check.push_back(child); - child = child->get_next(); + while (!queue.is_empty()) { + TreeItem *ti = queue.back()->get(); + queue.pop_back(); + if (!ti->is_collapsed() && ti->get_child_count() > 0) { + Variant path = ti->get_metadata(0); + if (path) { + uncollapsed_paths.push_back(path); } } - needs_check.remove_at(0); + for (int i = 0; i < ti->get_child_count(); i++) { + queue.push_back(ti->get_child(i)); + } } } } @@ -286,7 +288,7 @@ void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, boo ti->set_tooltip_text(0, favorite); ti->set_selectable(0, true); ti->set_metadata(0, favorite); - if (p_select_in_favorites && favorite == path) { + if (p_select_in_favorites && favorite == current_path) { ti->select(0); ti->set_as_cursor(0); } @@ -329,7 +331,7 @@ void FileSystemDock::_update_display_mode(bool p_force) { toolbar2_hbc->hide(); } - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); file_list_vb->hide(); break; @@ -338,7 +340,7 @@ void FileSystemDock::_update_display_mode(bool p_force) { tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->ensure_cursor_is_visible(); toolbar2_hbc->hide(); - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); file_list_vb->show(); _update_file_list(true); @@ -388,7 +390,7 @@ void FileSystemDock::_notification(int p_what) { file_list_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_list_rmb_option)); tree_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); - current_path->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path).bind(false)); + current_path_line_edit->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path).bind(false)); always_show_folders = bool(EDITOR_GET("docks/filesystem/always_show_folders")); @@ -502,14 +504,14 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s TreeItem *favorites_item = tree->get_root()->get_first_child(); if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) { // Go to the favorites if we click in the favorites and the path has changed. - path = "Favorites"; + current_path = "Favorites"; } else { - path = selected->get_metadata(0); + current_path = selected->get_metadata(0); // Note: the "Favorites" item also leads to this path. } - // Set the current path. - _set_current_path_text(path); + // Display the current path. + _set_current_path_line_edit_text(current_path); _push_to_history(); // Update the file list. @@ -523,28 +525,28 @@ Vector FileSystemDock::get_selected_paths() const { } String FileSystemDock::get_current_path() const { - return path; + return current_path; } String FileSystemDock::get_current_directory() const { - if (path.ends_with("/")) { - return path; + if (current_path.ends_with("/")) { + return current_path; } else { - return path.get_base_dir(); + return current_path.get_base_dir(); } } -void FileSystemDock::_set_current_path_text(const String &p_path) { +void FileSystemDock::_set_current_path_line_edit_text(const String &p_path) { if (p_path == "Favorites") { - current_path->set_text(TTR("Favorites")); + current_path_line_edit->set_text(TTR("Favorites")); } else { - current_path->set_text(path); + current_path_line_edit->set_text(current_path); } } void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_favorites) { if (p_path == "Favorites") { - path = p_path; + current_path = p_path; } else { String target_path = p_path; // If the path is a file, do not only go to the directory in the tree, also select the file in the file list. @@ -553,18 +555,18 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa } Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(p_path)) { - path = target_path; + current_path = target_path; } else if (da->dir_exists(p_path)) { - path = target_path + "/"; + current_path = target_path + "/"; } else { ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path)); } } - _set_current_path_text(path); + _set_current_path_line_edit_text(current_path); _push_to_history(); - _update_tree(_compute_uncollapsed_paths(), false, p_select_in_favorites, true); + _update_tree(get_uncollapsed_paths(), false, p_select_in_favorites, true); if (display_mode == DISPLAY_MODE_SPLIT) { _update_file_list(false); files->get_v_scroll_bar()->set_value(0); @@ -588,7 +590,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) { } void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) { - if ((file_list_vb->is_visible_in_tree() || path == p_path.get_base_dir()) && p_preview.is_valid()) { + if ((file_list_vb->is_visible_in_tree() || current_path == p_path.get_base_dir()) && p_preview.is_valid()) { Array uarr = p_udata; int idx = uarr[0]; String file = uarr[1]; @@ -749,9 +751,9 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->clear(); - _set_current_path_text(path); + _set_current_path_line_edit_text(current_path); - String directory = path; + String directory = current_path; String file = ""; int thumbnail_size = EDITOR_GET("docks/filesystem/thumbnail_size"); @@ -793,7 +795,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { // Build the FileInfo list. List file_list; - if (path == "Favorites") { + if (current_path == "Favorites") { // Display the favorites. Vector favorites_list = EditorSettings::get_singleton()->get_favorites(); for (const String &favorite : favorites_list) { @@ -842,8 +844,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { } EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory); if (!efd) { - directory = path.get_base_dir(); - file = path.get_file(); + directory = current_path.get_base_dir(); + file = current_path.get_file(); efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory); } if (!efd) { @@ -1084,7 +1086,7 @@ void FileSystemDock::_file_list_activate_file(int p_idx) { } void FileSystemDock::_preview_invalidated(const String &p_path) { - if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == path && searched_string.length() == 0 && file_list_vb->is_visible_in_tree()) { + if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == current_path && searched_string.length() == 0 && file_list_vb->is_visible_in_tree()) { for (int i = 0; i < files->get_item_count(); i++) { if (files->get_item_metadata(i) == p_path) { // Re-request preview. @@ -1106,7 +1108,7 @@ void FileSystemDock::_fs_changed() { split_box->show(); if (tree->is_visible()) { - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); } if (file_list_vb->is_visible()) { @@ -1146,11 +1148,11 @@ void FileSystemDock::_bw_history() { } void FileSystemDock::_update_history() { - path = history[history_pos]; - _set_current_path_text(path); + current_path = history[history_pos]; + _set_current_path_line_edit_text(current_path); if (tree->is_visible()) { - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); tree->grab_focus(); tree->ensure_cursor_is_visible(); } @@ -1164,9 +1166,9 @@ void FileSystemDock::_update_history() { } void FileSystemDock::_push_to_history() { - if (history[history_pos] != path) { + if (history[history_pos] != current_path) { history.resize(history_pos + 1); - history.push_back(path); + history.push_back(current_path); history_pos++; if (history.size() > history_max_size) { @@ -1255,7 +1257,7 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ for (int j = 0; j < ed->get_edited_scene_count(); j++) { if (ed->get_scene_path(j) == file_changed_paths[i]) { ed->get_edited_scene_root(j)->set_scene_file_path(new_item_path); - EditorNode::get_singleton()->save_layout(); + EditorNode::get_singleton()->save_editor_layout_delayed(); break; } } @@ -1292,7 +1294,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.") + "\n" + old_path + "\n"); return; } - const_cast(this)->path = new_path; + const_cast(this)->current_path = new_path; Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); @@ -1532,27 +1534,27 @@ void FileSystemDock::_file_removed(String p_file) { emit_signal(SNAME("file_removed"), p_file); // Find the closest parent directory available, in case multiple items were deleted along the same path. - path = p_file.get_base_dir(); + current_path = p_file.get_base_dir(); Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - while (!da->dir_exists(path)) { - path = path.get_base_dir(); + while (!da->dir_exists(current_path)) { + current_path = current_path.get_base_dir(); } - current_path->set_text(path); + current_path_line_edit->set_text(current_path); } void FileSystemDock::_folder_removed(String p_folder) { emit_signal(SNAME("folder_removed"), p_folder); // Find the closest parent directory available, in case multiple items were deleted along the same path. - path = p_folder.get_base_dir(); + current_path = p_folder.get_base_dir(); Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - while (!da->dir_exists(path)) { - path = path.get_base_dir(); + while (!da->dir_exists(current_path)) { + current_path = current_path.get_base_dir(); } - current_path->set_text(path); - EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(path); + current_path_line_edit->set_text(current_path); + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(current_path); if (efd) { efd->force_update(); } @@ -1614,8 +1616,8 @@ void FileSystemDock::_rename_operation_confirm() { print_verbose("FileSystem: saving moved scenes."); _save_scenes_after_move(file_renames); - path = new_path; - current_path->set_text(path); + current_path = new_path; + current_path_line_edit->set_text(current_path); } void FileSystemDock::_duplicate_operation_confirm() { @@ -1758,8 +1760,8 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop print_verbose("FileSystem: saving moved scenes."); _save_scenes_after_move(file_renames); - path = p_to_path; - current_path->set_text(path); + current_path = p_to_path; + current_path_line_edit->set_text(current_path); } } } @@ -1840,8 +1842,8 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected switch (p_option) { case FILE_SHOW_IN_EXPLORER: { // Show the file/folder in the OS explorer. - String fpath = path; - if (path == "Favorites") { + String fpath = current_path; + if (current_path == "Favorites") { fpath = p_selected[0]; } @@ -1850,8 +1852,8 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } break; case FILE_OPEN_EXTERNAL: { - String fpath = path; - if (path == "Favorites") { + String fpath = current_path; + if (current_path == "Favorites") { fpath = p_selected[0]; } @@ -1914,7 +1916,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected if (p_selected.size() == 1) { ProjectSettings::get_singleton()->set("application/run/main_scene", p_selected[0]); ProjectSettings::get_singleton()->save(); - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); _update_file_list(true); } } break; @@ -1942,7 +1944,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } } EditorSettings::get_singleton()->set_favorites(favorites_list); - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); } break; case FILE_REMOVE_FAVORITE: { @@ -1952,8 +1954,8 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected favorites_list.erase(p_selected[i]); } EditorSettings::get_singleton()->set_favorites(favorites_list); - _update_tree(_compute_uncollapsed_paths()); - if (path == "Favorites") { + _update_tree(get_uncollapsed_paths()); + if (current_path == "Favorites") { _update_file_list(true); } } break; @@ -2069,7 +2071,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } break; case FILE_NEW_FOLDER: { - String directory = path; + String directory = current_path; if (!directory.ends_with("/")) { directory = directory.get_base_dir(); } @@ -2078,7 +2080,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } break; case FILE_NEW_SCENE: { - String directory = path; + String directory = current_path; if (!directory.ends_with("/")) { directory = directory.get_base_dir(); } @@ -2087,7 +2089,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } break; case FILE_NEW_SCRIPT: { - String fpath = path; + String fpath = current_path; if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } @@ -2116,7 +2118,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected new_resource_dialog->popup_create(true); } break; case FILE_NEW_TEXTFILE: { - String fpath = path; + String fpath = current_path; if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } @@ -2127,7 +2129,7 @@ void FileSystemDock::_file_option(int p_option, const Vector &p_selected } void FileSystemDock::_resource_created() { - String fpath = path; + String fpath = current_path; if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } @@ -2168,7 +2170,7 @@ void FileSystemDock::_resource_created() { void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) { if (searched_string.length() == 0) { // Register the uncollapsed paths before they change. - uncollapsed_paths_before_search = _compute_uncollapsed_paths(); + uncollapsed_paths_before_search = get_uncollapsed_paths(); } searched_string = p_text.to_lower(); @@ -2179,7 +2181,7 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from tree_search_box->set_text(searched_string); } - bool unfold_path = (p_text.is_empty() && !path.is_empty()); + bool unfold_path = (p_text.is_empty() && !current_path.is_empty()); switch (display_mode) { case DISPLAY_MODE_TREE_ONLY: { _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector(), false, false, unfold_path); @@ -2417,9 +2419,9 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, } EditorSettings::get_singleton()->set_favorites(dirs); - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); - if (display_mode == DISPLAY_MODE_SPLIT && path == "Favorites") { + if (display_mode == DISPLAY_MODE_SPLIT && current_path == "Favorites") { _update_file_list(true); } return; @@ -2467,7 +2469,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, } } EditorSettings::get_singleton()->set_favorites(favorites_list); - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); } } @@ -2491,7 +2493,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori } String ltarget = files->get_item_metadata(pos); - target = ltarget.ends_with("/") ? ltarget : path.get_base_dir(); + target = ltarget.ends_with("/") ? ltarget : current_path.get_base_dir(); return; } @@ -2674,7 +2676,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vectorclear(); tree_popup->reset_size(); tree_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER); @@ -2763,7 +2765,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton return; } - path = current_path->get_text(); + current_path = current_path_line_edit->get_text(); file_list_popup->clear(); file_list_popup->reset_size(); @@ -2791,9 +2793,9 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) { if (current == p_index) { String fpath = files->get_item_metadata(current); if (!fpath.ends_with("/")) { - path = fpath; + current_path = fpath; if (display_mode == DISPLAY_MODE_SPLIT) { - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); } } } @@ -3076,7 +3078,7 @@ void FileSystemDock::set_file_sort(FileSortOption p_file_sort) { file_sort = p_file_sort; // Update everything needed. - _update_tree(_compute_uncollapsed_paths()); + _update_tree(get_uncollapsed_paths()); _update_file_list(true); } @@ -3127,7 +3129,7 @@ void FileSystemDock::_bind_methods() { FileSystemDock::FileSystemDock() { singleton = this; set_name("FileSystem"); - path = "res://"; + current_path = "res://"; // `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts. ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C); @@ -3163,11 +3165,11 @@ FileSystemDock::FileSystemDock() { button_hist_next->set_tooltip_text(TTR("Go to next selected folder/file.")); toolbar_hbc->add_child(button_hist_next); - current_path = memnew(LineEdit); - current_path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); - current_path->set_h_size_flags(SIZE_EXPAND_FILL); - _set_current_path_text(path); - toolbar_hbc->add_child(current_path); + current_path_line_edit = memnew(LineEdit); + current_path_line_edit->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); + current_path_line_edit->set_h_size_flags(SIZE_EXPAND_FILL); + _set_current_path_line_edit_text(current_path); + toolbar_hbc->add_child(current_path_line_edit); button_reload = memnew(Button); button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan)); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index e47178d294d..37e325c8730 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -125,7 +125,7 @@ private: Button *button_file_list_display_mode = nullptr; Button *button_hist_next = nullptr; Button *button_hist_prev = nullptr; - LineEdit *current_path = nullptr; + LineEdit *current_path_line_edit = nullptr; HBoxContainer *toolbar2_hbc = nullptr; LineEdit *tree_search_box = nullptr; @@ -185,7 +185,7 @@ private: int history_pos; int history_max_size; - String path; + String current_path; bool initialized = false; @@ -204,7 +204,6 @@ private: Ref _get_tree_item_icon(bool p_is_valid, String p_file_type); bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false); - Vector _compute_uncollapsed_paths(); void _update_tree(const Vector &p_uncollapsed_paths = Vector(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false); void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false); @@ -295,7 +294,7 @@ private: void _search(EditorFileSystemDirectory *p_path, List *matches, int p_max_items); - void _set_current_path_text(const String &p_path); + void _set_current_path_line_edit_text(const String &p_path); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -327,6 +326,7 @@ protected: public: Vector get_selected_paths() const; + Vector get_uncollapsed_paths() const; String get_current_path() const; String get_current_directory() const; @@ -351,6 +351,8 @@ public: void set_file_list_display_mode(FileListDisplayMode p_mode); FileListDisplayMode get_file_list_display_mode() { return file_list_display_mode; }; + Tree *get_tree_control() { return tree; } + FileSystemDock(); ~FileSystemDock(); }; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f9ab37dce22..05a024f913b 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3981,10 +3981,6 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { Array selection = editor_selection->get_selected_nodes(); if (selection.size() != 1 || Object::cast_to(selection[0]) != p_canvas_item) { _reset_drag(); - - // Clear the selection - editor_selection->clear(); //_clear_canvas_items(); - editor_selection->add_node(p_canvas_item); } } diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index a726ab09d58..1e577b77374 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -3299,6 +3299,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { orthogonal = false; auto_orthogonal = false; call_deferred(SNAME("update_transform_gizmo_view")); + _update_camera(0); _update_name(); } break; @@ -3308,8 +3309,8 @@ void Node3DEditorViewport::_menu_option(int p_option) { orthogonal = true; auto_orthogonal = false; call_deferred(SNAME("update_transform_gizmo_view")); + _update_camera(0); _update_name(); - } break; case VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL: { _menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL); @@ -3402,7 +3403,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { case VIEW_DISPLAY_NORMAL: case VIEW_DISPLAY_WIREFRAME: case VIEW_DISPLAY_OVERDRAW: - case VIEW_DISPLAY_SHADELESS: + case VIEW_DISPLAY_UNSHADED: case VIEW_DISPLAY_LIGHTING: case VIEW_DISPLAY_NORMAL_BUFFER: case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS: @@ -3429,7 +3430,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, - VIEW_DISPLAY_SHADELESS, + VIEW_DISPLAY_UNSHADED, VIEW_DISPLAY_LIGHTING, VIEW_DISPLAY_NORMAL_BUFFER, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, @@ -3778,15 +3779,9 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { if (p_state.has("distance")) { cursor.distance = p_state["distance"]; } - - if (p_state.has("use_orthogonal")) { - bool orth = p_state["use_orthogonal"]; - - if (orth) { - _menu_option(VIEW_ORTHOGONAL); - } else { - _menu_option(VIEW_PERSPECTIVE); - } + if (p_state.has("orthogonal")) { + bool orth = p_state["orthogonal"]; + _menu_option(orth ? VIEW_ORTHOGONAL : VIEW_PERSPECTIVE); } if (p_state.has("view_type")) { view_type = ViewType(p_state["view_type"].operator int()); @@ -3804,8 +3799,13 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { int display = p_state["display_mode"]; int idx = view_menu->get_popup()->get_item_index(display); - if (!view_menu->get_popup()->is_item_checked(idx)) { + if (idx != -1 && !view_menu->get_popup()->is_item_checked(idx)) { _menu_option(display); + } else { + idx = display_submenu->get_item_index(display); + if (idx != -1 && !display_submenu->is_item_checked(idx)) { + _menu_option(display); + } } } if (p_state.has("lock_rotation")) { @@ -3864,6 +3864,7 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION); view_menu->get_popup()->set_item_checked(idx, half_res); + _update_shrink(); } if (p_state.has("cinematic_preview")) { previewing_cinema = p_state["cinematic_preview"]; @@ -3896,19 +3897,27 @@ Dictionary Node3DEditorViewport::get_state() const { d["y_rotation"] = cursor.y_rot; d["distance"] = cursor.distance; d["use_environment"] = camera->get_environment().is_valid(); - d["use_orthogonal"] = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; + d["orthogonal"] = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL; d["view_type"] = view_type; d["auto_orthogonal"] = auto_orthogonal; d["auto_orthogonal_enabled"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL)); - if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL))) { - d["display_mode"] = VIEW_DISPLAY_NORMAL; - } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME))) { - d["display_mode"] = VIEW_DISPLAY_WIREFRAME; - } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW))) { - d["display_mode"] = VIEW_DISPLAY_OVERDRAW; - } else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) { - d["display_mode"] = VIEW_DISPLAY_SHADELESS; + + // Find selected display mode. + int display_mode = VIEW_DISPLAY_NORMAL; + for (int i = VIEW_DISPLAY_NORMAL; i < VIEW_DISPLAY_ADVANCED; i++) { + if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(i))) { + display_mode = i; + break; + } } + for (int i = VIEW_DISPLAY_ADVANCED + 1; i < VIEW_DISPLAY_MAX; i++) { + if (display_submenu->is_item_checked(display_submenu->get_item_index(i))) { + display_mode = i; + break; + } + } + d["display_mode"] = display_mode; + d["listener"] = viewport->is_audio_listener_3d(); d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); @@ -5005,7 +5014,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW); view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_lighting", TTR("Display Lighting")), VIEW_DISPLAY_LIGHTING); - view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS); + view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_UNSHADED); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true); display_submenu->set_hide_on_checkable_item_selection(false); display_submenu->add_radio_check_item(TTR("Directional Shadow Splits"), VIEW_DISPLAY_DEBUG_PSSM_SPLITS); @@ -5074,7 +5083,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL); const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME); const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW); - const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS); + const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_UNSHADED); const String unsupported_tooltip = TTR("Not available when using the OpenGL renderer."); view_menu->get_popup()->set_item_disabled(normal_idx, true); diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index c4e1070d840..24a70680b73 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -125,25 +125,28 @@ class Node3DEditorViewport : public Control { VIEW_GIZMOS, VIEW_INFORMATION, VIEW_FRAME_TIME, + + // < Keep in sync with menu. VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_OVERDRAW, - VIEW_DISPLAY_SHADELESS, VIEW_DISPLAY_LIGHTING, + VIEW_DISPLAY_UNSHADED, VIEW_DISPLAY_ADVANCED, + // Advanced menu: + VIEW_DISPLAY_DEBUG_PSSM_SPLITS, VIEW_DISPLAY_NORMAL_BUFFER, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, + VIEW_DISPLAY_DEBUG_DECAL_ATLAS, VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO, VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING, VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION, + VIEW_DISPLAY_DEBUG_SDFGI, + VIEW_DISPLAY_DEBUG_SDFGI_PROBES, VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, VIEW_DISPLAY_DEBUG_SSAO, VIEW_DISPLAY_DEBUG_SSIL, - VIEW_DISPLAY_DEBUG_PSSM_SPLITS, - VIEW_DISPLAY_DEBUG_DECAL_ATLAS, - VIEW_DISPLAY_DEBUG_SDFGI, - VIEW_DISPLAY_DEBUG_SDFGI_PROBES, VIEW_DISPLAY_DEBUG_GI_BUFFER, VIEW_DISPLAY_DEBUG_DISABLE_LOD, VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS, @@ -152,6 +155,8 @@ class Node3DEditorViewport : public Control { VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES, VIEW_DISPLAY_DEBUG_OCCLUDERS, VIEW_DISPLAY_MOTION_VECTORS, + VIEW_DISPLAY_MAX, + // > Keep in sync with menu. VIEW_LOCK_ROTATION, VIEW_CINEMATIC_PREVIEW, diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index ac9b2a692df..51550acb949 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2325,7 +2325,6 @@ bool ScriptEditor::edit(const Ref &p_resource, int p_line, int p_col, if (tab_container->get_current_tab() != i) { _go_to_tab(i); - _update_script_names(); } if (is_visible_in_tree()) { se->ensure_focus(); @@ -2707,7 +2706,7 @@ void ScriptEditor::_save_layout() { return; } - EditorNode::get_singleton()->save_layout(); + EditorNode::get_singleton()->save_editor_layout_delayed(); } void ScriptEditor::_editor_settings_changed() { @@ -3251,12 +3250,24 @@ void ScriptEditor::set_window_layout(Ref p_layout) { restoring_layout = false; _update_script_names(); + + if (p_layout->has_section_key("ScriptEditor", "selected_script")) { + String selected_script = p_layout->get_value("ScriptEditor", "selected_script"); + // If the selected script is not in the list of open scripts, select nothing. + for (int i = 0; i < tab_container->get_tab_count(); i++) { + ScriptEditorBase *se = Object::cast_to(tab_container->get_tab_control(i)); + if (se && se->get_edited_resource()->get_path() == selected_script) { + _go_to_tab(i); + break; + } + } + } } void ScriptEditor::get_window_layout(Ref p_layout) { Array scripts; Array helps; - + String selected_script; for (int i = 0; i < tab_container->get_tab_count(); i++) { ScriptEditorBase *se = Object::cast_to(tab_container->get_tab_control(i)); if (se) { @@ -3265,6 +3276,10 @@ void ScriptEditor::get_window_layout(Ref p_layout) { continue; } + if (tab_container->get_current_tab_control() == tab_container->get_tab_control(i)) { + selected_script = path; + } + _save_editor_state(se); scripts.push_back(path); } @@ -3277,6 +3292,7 @@ void ScriptEditor::get_window_layout(Ref p_layout) { } p_layout->set_value("ScriptEditor", "open_scripts", scripts); + p_layout->set_value("ScriptEditor", "selected_script", selected_script); p_layout->set_value("ScriptEditor", "open_help", helps); p_layout->set_value("ScriptEditor", "script_split_offset", script_split->get_split_offset()); p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset()); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index abbd61ad894..e7d2d7a11f8 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -180,6 +180,24 @@ void ShaderEditorPlugin::make_visible(bool p_visible) { void ShaderEditorPlugin::selected_notify() { } +TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref &p_for_shader) { + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader == p_for_shader) { + return edited_shader.shader_editor; + } + } + return nullptr; +} + +VisualShaderEditor *ShaderEditorPlugin::get_visual_shader_editor(const Ref &p_for_shader) { + for (EditedShader &edited_shader : edited_shaders) { + if (edited_shader.shader == p_for_shader) { + return edited_shader.visual_shader_editor; + } + } + return nullptr; +} + void ShaderEditorPlugin::set_window_layout(Ref p_layout) { if (EDITOR_GET("interface/multi_window/restore_windows_on_load") && window_wrapper->is_window_available() && p_layout->has_section_key("ShaderEditor", "window_rect")) { window_wrapper->restore_window_from_saved_position( @@ -189,6 +207,38 @@ void ShaderEditorPlugin::set_window_layout(Ref p_layout) { } else { window_wrapper->set_window_enabled(false); } + + if (!bool(EDITOR_GET("editors/shader_editor/behavior/files/restore_shaders_on_load"))) { + return; + } + if (!p_layout->has_section("ShaderEditor")) { + return; + } + if (!p_layout->has_section_key("ShaderEditor", "open_shaders") || + !p_layout->has_section_key("ShaderEditor", "selected_shader")) { + return; + } + + Array shaders = p_layout->get_value("ShaderEditor", "open_shaders"); + int selected_shader_idx = 0; + String selected_shader = p_layout->get_value("ShaderEditor", "selected_shader"); + for (int i = 0; i < shaders.size(); i++) { + String path = shaders[i]; + Ref res = ResourceLoader::load(path); + if (res.is_valid()) { + edit(res.ptr()); + } + if (selected_shader == path) { + selected_shader_idx = i; + } + } + + if (p_layout->has_section_key("ShaderEditor", "split_offset")) { + main_split->set_split_offset(p_layout->get_value("ShaderEditor", "split_offset")); + } + + _update_shader_list(); + _shader_selected(selected_shader_idx); } void ShaderEditorPlugin::get_window_layout(Ref p_layout) { @@ -209,24 +259,25 @@ void ShaderEditorPlugin::get_window_layout(Ref p_layout) { p_layout->erase_section_key("ShaderEditor", "window_screen_rect"); } } -} -TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref &p_for_shader) { - for (EditedShader &edited_shader : edited_shaders) { - if (edited_shader.shader == p_for_shader) { - return edited_shader.shader_editor; + Array shaders; + String selected_shader; + for (int i = 0; i < shader_tabs->get_tab_count(); i++) { + EditedShader edited_shader = edited_shaders[i]; + if (edited_shader.shader_editor || edited_shader.visual_shader_editor) { + shaders.push_back(edited_shader.shader->get_path()); + + TextShaderEditor *shader_editor = Object::cast_to(shader_tabs->get_current_tab_control()); + VisualShaderEditor *visual_shader_editor = Object::cast_to(shader_tabs->get_current_tab_control()); + + if ((shader_editor && edited_shader.shader_editor == shader_editor) || (visual_shader_editor && edited_shader.visual_shader_editor == visual_shader_editor)) { + selected_shader = edited_shader.shader->get_path(); + } } } - return nullptr; -} - -VisualShaderEditor *ShaderEditorPlugin::get_visual_shader_editor(const Ref &p_for_shader) { - for (EditedShader &edited_shader : edited_shaders) { - if (edited_shader.shader == p_for_shader) { - return edited_shader.visual_shader_editor; - } - } - return nullptr; + p_layout->set_value("ShaderEditor", "open_shaders", shaders); + p_layout->set_value("ShaderEditor", "split_offset", main_split->get_split_offset()); + p_layout->set_value("ShaderEditor", "selected_shader", selected_shader); } void ShaderEditorPlugin::save_external_data() { @@ -247,6 +298,10 @@ void ShaderEditorPlugin::apply_changes() { } void ShaderEditorPlugin::_shader_selected(int p_index) { + if (p_index >= (int)edited_shaders.size()) { + return; + } + if (edited_shaders[p_index].shader_editor) { edited_shaders[p_index].shader_editor->validate_script(); } diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index bc508976ca6..45b48a2f91c 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -108,12 +108,13 @@ public: virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; virtual void selected_notify() override; - virtual void set_window_layout(Ref p_layout) override; - virtual void get_window_layout(Ref p_layout) override; TextShaderEditor *get_shader_editor(const Ref &p_for_shader); VisualShaderEditor *get_visual_shader_editor(const Ref &p_for_shader); + virtual void set_window_layout(Ref p_layout) override; + virtual void get_window_layout(Ref p_layout) override; + virtual void save_external_data() override; virtual void apply_changes() override; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index f09acb11c6e..5f515040aef 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -748,7 +748,7 @@ TreeItem *TreeItem::get_first_child() const { return first_child; } -TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { +TreeItem *TreeItem::_get_prev_in_tree(bool p_wrap, bool p_include_invisible) { TreeItem *current = this; TreeItem *prev_item = current->get_prev(); @@ -771,7 +771,7 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { } } else { current = prev_item; - while (!current->collapsed && current->first_child) { + while ((!current->collapsed || p_include_invisible) && current->first_child) { //go to the very end current = current->first_child; @@ -786,9 +786,9 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) { TreeItem *TreeItem::get_prev_visible(bool p_wrap) { TreeItem *loop = this; - TreeItem *prev_item = this->_get_prev_visible(p_wrap); + TreeItem *prev_item = this->_get_prev_in_tree(p_wrap); while (prev_item && !prev_item->is_visible()) { - prev_item = prev_item->_get_prev_visible(p_wrap); + prev_item = prev_item->_get_prev_in_tree(p_wrap); if (prev_item == loop) { // Check that we haven't looped all the way around to the start. prev_item = nullptr; @@ -798,10 +798,10 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) { return prev_item; } -TreeItem *TreeItem::_get_next_visible(bool p_wrap) { +TreeItem *TreeItem::_get_next_in_tree(bool p_wrap, bool p_include_invisible) { TreeItem *current = this; - if (!current->collapsed && current->first_child) { + if ((!current->collapsed || p_include_invisible) && current->first_child) { current = current->first_child; } else if (current->next) { @@ -827,9 +827,9 @@ TreeItem *TreeItem::_get_next_visible(bool p_wrap) { TreeItem *TreeItem::get_next_visible(bool p_wrap) { TreeItem *loop = this; - TreeItem *next_item = this->_get_next_visible(p_wrap); + TreeItem *next_item = this->_get_next_in_tree(p_wrap); while (next_item && !next_item->is_visible()) { - next_item = next_item->_get_next_visible(p_wrap); + next_item = next_item->_get_next_in_tree(p_wrap); if (next_item == loop) { // Check that we haven't looped all the way around to the start. next_item = nullptr; @@ -839,6 +839,16 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) { return next_item; } +TreeItem *TreeItem::get_prev_in_tree(bool p_wrap) { + TreeItem *prev_item = this->_get_prev_in_tree(p_wrap, true); + return prev_item; +} + +TreeItem *TreeItem::get_next_in_tree(bool p_wrap) { + TreeItem *next_item = this->_get_next_in_tree(p_wrap, true); + return next_item; +} + TreeItem *TreeItem::get_child(int p_index) { _create_children_cache(); @@ -1539,6 +1549,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent"), &TreeItem::get_parent); ClassDB::bind_method(D_METHOD("get_first_child"), &TreeItem::get_first_child); + ClassDB::bind_method(D_METHOD("get_next_in_tree", "wrap"), &TreeItem::get_next_in_tree, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_prev_in_tree", "wrap"), &TreeItem::get_prev_in_tree, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false)); @@ -4995,6 +5008,26 @@ TreeItem *Tree::get_item_with_text(const String &p_find) const { return nullptr; } +TreeItem *Tree::get_item_with_metadata(const Variant &p_find, int p_column) const { + if (p_column < 0) { + for (TreeItem *current = root; current; current = current->get_next_in_tree()) { + for (int i = 0; i < columns.size(); i++) { + if (current->get_metadata(i) == p_find) { + return current; + } + } + } + return nullptr; + } + + for (TreeItem *current = root; current; current = current->get_next_in_tree()) { + if (current->get_metadata(p_column) == p_find) { + return current; + } + } + return nullptr; +} + void Tree::_do_incr_search(const String &p_add) { uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec uint64_t diff = time - last_keypress; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 27d89493707..63b5df4623f 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -217,8 +217,8 @@ private: void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal); void _propagate_check_through_parents(int p_column, bool p_emit_signal); - TreeItem *_get_prev_visible(bool p_wrap = false); - TreeItem *_get_next_visible(bool p_wrap = false); + TreeItem *_get_prev_in_tree(bool p_wrap = false, bool p_include_invisible = false); + TreeItem *_get_next_in_tree(bool p_wrap = false, bool p_include_invisible = false); public: void set_text(int p_column, String p_text); @@ -344,6 +344,9 @@ public: TreeItem *get_parent() const; TreeItem *get_first_child() const; + TreeItem *get_prev_in_tree(bool p_wrap = false); + TreeItem *get_next_in_tree(bool p_wrap = false); + TreeItem *get_prev_visible(bool p_wrap = false); TreeItem *get_next_visible(bool p_wrap = false); @@ -731,6 +734,7 @@ public: TreeItem *search_item_text(const String &p_find, int *r_col = nullptr, bool p_selectable = false); // First item that matches the whole text, from the first item down. TreeItem *get_item_with_text(const String &p_find) const; + TreeItem *get_item_with_metadata(const Variant &p_find, int p_column = -1) const; Point2 get_scroll() const; void scroll_to_item(TreeItem *p_item, bool p_center_on_item = false);