Merge pull request #72277 from Geometror/improve-editor-state-preservation

Improve editor state persistence
This commit is contained in:
Rémi Verschelde 2023-05-11 11:45:52 +02:00
commit f7070a64e0
No known key found for this signature in database
GPG Key ID: C3336907360768E1
20 changed files with 557 additions and 259 deletions

View File

@ -416,6 +416,9 @@
<member name="editors/polygon_editor/show_previous_outline" type="bool" setter="" getter=""> <member name="editors/polygon_editor/show_previous_outline" type="bool" setter="" getter="">
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], 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.
</member> </member>
<member name="editors/shader_editor/behavior/files/restore_shaders_on_load" type="bool" setter="" getter="">
If [code]true[/code], reopens shader files that were open in the shader editor when the project was last closed.
</member>
<member name="editors/tiles_editor/display_grid" type="bool" setter="" getter=""> <member name="editors/tiles_editor/display_grid" type="bool" setter="" getter="">
If [code]true[/code], displays a grid while the TileMap editor is active. See also [member editors/tiles_editor/grid_color]. If [code]true[/code], displays a grid while the TileMap editor is active. See also [member editors/tiles_editor/grid_color].
</member> </member>

View File

@ -226,11 +226,19 @@
Returns the next sibling TreeItem in the tree or a null object if there is none. Returns the next sibling TreeItem in the tree or a null object if there is none.
</description> </description>
</method> </method>
<method name="get_next_in_tree">
<return type="TreeItem" />
<param index="0" name="wrap" type="bool" default="false" />
<description>
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].
</description>
</method>
<method name="get_next_visible"> <method name="get_next_visible">
<return type="TreeItem" /> <return type="TreeItem" />
<param index="0" name="wrap" type="bool" default="false" /> <param index="0" name="wrap" type="bool" default="false" />
<description> <description>
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]. 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].
</description> </description>
</method> </method>
@ -246,11 +254,19 @@
Returns the previous sibling TreeItem in the tree or a null object if there is none. Returns the previous sibling TreeItem in the tree or a null object if there is none.
</description> </description>
</method> </method>
<method name="get_prev_in_tree">
<return type="TreeItem" />
<param index="0" name="wrap" type="bool" default="false" />
<description>
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].
</description>
</method>
<method name="get_prev_visible"> <method name="get_prev_visible">
<return type="TreeItem" /> <return type="TreeItem" />
<param index="0" name="wrap" type="bool" default="false" /> <param index="0" name="wrap" type="bool" default="false" />
<description> <description>
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]. 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].
</description> </description>
</method> </method>

View File

@ -1704,6 +1704,14 @@ void ScriptEditorDebugger::remove_debugger_tab(Control *p_control) {
p_control->queue_free(); 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) { void ScriptEditorDebugger::send_message(const String &p_message, const Array &p_args) {
_put_msg(p_message, p_args); _put_msg(p_message, p_args);
} }

View File

@ -284,6 +284,8 @@ public:
void add_debugger_tab(Control *p_control); void add_debugger_tab(Control *p_control);
void remove_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 send_message(const String &p_message, const Array &p_args);
void toggle_profiler(const String &p_profiler, bool p_enable, const Array &p_data); void toggle_profiler(const String &p_profiler, bool p_enable, const Array &p_data);

View File

@ -300,7 +300,7 @@ void EditorData::get_editor_breakpoints(List<String> *p_breakpoints) {
} }
} }
Dictionary EditorData::get_editor_states() const { Dictionary EditorData::get_editor_plugin_states() const {
Dictionary metadata; Dictionary metadata;
for (int i = 0; i < editor_plugins.size(); i++) { for (int i = 0; i < editor_plugins.size(); i++) {
Dictionary state = editor_plugins[i]->get_state(); 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; 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()) { if (p_states.is_empty()) {
for (EditorPlugin *ep : editor_plugins) { for (EditorPlugin *ep : editor_plugins) {
ep->clear(); 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.selection = p_selection->get_full_selected_node_list();
es.history_current = p_history->current_elem_idx; es.history_current = p_history->current_elem_idx;
es.history_stored = p_history->history; es.history_stored = p_history->history;
es.editor_states = get_editor_states(); es.editor_states = get_editor_plugin_states();
es.custom_state = p_custom; es.custom_state = p_custom;
} }
@ -907,7 +907,7 @@ Dictionary EditorData::restore_edited_scene_state(EditorSelection *p_selection,
for (Node *E : es.selection) { for (Node *E : es.selection) {
p_selection->add_node(E); p_selection->add_node(E);
} }
set_editor_states(es.editor_states); set_editor_plugin_states(es.editor_states);
return es.custom_state; return es.custom_state;
} }

View File

@ -156,9 +156,9 @@ public:
void copy_object_params(Object *p_object); void copy_object_params(Object *p_object);
void paste_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; 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<String> *p_breakpoints); void get_editor_breakpoints(List<String> *p_breakpoints);
void clear_editor_states(); void clear_editor_states();
void save_editor_external_data(); void save_editor_external_data();

View File

@ -67,6 +67,7 @@
#include "editor/audio_stream_preview.h" #include "editor/audio_stream_preview.h"
#include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/editor_debugger_node.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/dependency_editor.h" #include "editor/dependency_editor.h"
#include "editor/editor_about.h" #include "editor/editor_about.h"
#include "editor/editor_audio_buses.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. // 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 META_TEXT_TO_COPY = "text_to_copy";
static const String EDITOR_NODE_CONFIG_SECTION = "EditorNode";
class AcceptDialogAutoReparent : public AcceptDialog { class AcceptDialogAutoReparent : public AcceptDialog {
GDCLASS(AcceptDialogAutoReparent, AcceptDialog); GDCLASS(AcceptDialogAutoReparent, AcceptDialog);
@ -1094,7 +1097,7 @@ void EditorNode::_sources_changed(bool p_exist) {
EditorResourcePreview::get_singleton()->start(); EditorResourcePreview::get_singleton()->start();
} }
_load_docks(); _load_editor_layout();
if (!defer_load_scene.is_empty()) { if (!defer_load_scene.is_empty()) {
Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene"); 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<ConfigFile> &p_config_file) {
Node *scene = editor_data.get_edited_scene_root(); Node *scene = editor_data.get_edited_scene_root();
if (!scene) { if (!scene) {
return; return;
} }
String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
Ref<ConfigFile> cf;
cf.instantiate();
Error err = cf->load(path);
if (err != OK || !cf->has_section("editor_states")) {
// Must not exist.
return;
}
List<String> esl; List<String> esl;
cf->get_section_keys("editor_states", &esl); p_config_file->get_section_keys("editor_states", &esl);
Dictionary md; Dictionary md;
for (const String &E : esl) { 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) { if (st.get_type() != Variant::NIL) {
md[E] = st; 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); Node *scene = editor_data.get_edited_scene_root(p_idx);
if (!scene) { if (!scene) {
@ -1508,20 +1500,27 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) {
cf.instantiate(); cf.instantiate();
Dictionary md; Dictionary md;
if (p_idx < 0 || editor_data.get_edited_scene() == p_idx) { 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 { } else {
md = editor_data.get_scene_editor_states(p_idx); md = editor_data.get_scene_editor_states(p_idx);
} }
List<Variant> keys; List<Variant> keys;
md.get_key_list(&keys); md.get_key_list(&keys);
for (const Variant &E : keys) { for (const Variant &E : keys) {
cf->set_value("editor_states", E, md[E]); cf->set_value("editor_states", E, md[E]);
} }
// Save the currently selected nodes.
List<Node *> selection = editor_selection->get_full_selected_node_list();
TypedArray<NodePath> 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); Error err = cf->save(path);
ERR_FAIL_COND_MSG(err != OK, "Cannot save config file to '" + 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); _reset_animation_players(scene, &anim_backups);
save_default_environment(); save_default_environment();
_set_scene_metadata(p_file, idx); _save_editor_states(p_file, idx);
Ref<PackedScene> sdata; Ref<PackedScene> sdata;
@ -2025,7 +2024,7 @@ void EditorNode::_dialog_action(String p_file) {
save_default_environment(); save_default_environment();
_save_scene_with_preview(p_file, scene_idx); _save_scene_with_preview(p_file, scene_idx);
_add_to_recent_scenes(p_file); _add_to_recent_scenes(p_file);
save_layout(); save_editor_layout_delayed();
if (scene_idx != -1) { if (scene_idx != -1) {
_discard_changes(); _discard_changes();
@ -2605,7 +2604,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (scene_idx != -1) { if (scene_idx != -1) {
_discard_changes(); _discard_changes();
} }
save_layout(); save_editor_layout_delayed();
} else { } 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")); 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) { void EditorNode::_exit_editor(int p_exit_code) {
exiting = true; exiting = true;
resource_preview->stop(); // Stop early to avoid crashes. 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 the editor window while it's quitting to make it clearer that it's busy.
dim_editor(true); 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<SceneState>()); new_scene->set_scene_instance_state(Ref<SceneState>());
set_edited_scene(new_scene); 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<ConfigFile> 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_title();
_update_scene_tabs(); _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); push_item(new_scene);
// Load the selected nodes.
if (editor_state_cf->has_section_key("editor_states", "selected_nodes")) {
TypedArray<NodePath> selected_node_list = editor_state_cf->get_value("editor_states", "selected_nodes", TypedArray<String>());
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) { if (!restoring_scenes) {
save_layout(); save_editor_layout_delayed();
} }
return OK; return OK;
@ -4609,7 +4627,7 @@ void EditorNode::_dock_select_input(const Ref<InputEvent> &p_input) {
_update_dock_containers(); _update_dock_containers();
_edit_current(); _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_slot[dock_popup_selected_idx]->move_child(current_ctl, prev_ctl->get_index(false));
dock_select->queue_redraw(); dock_select->queue_redraw();
_edit_current(); _edit_current();
_save_docks(); _save_editor_layout();
} }
void EditorNode::_dock_move_right() { 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_slot[dock_popup_selected_idx]->move_child(next_ctl, current_ctl->get_index(false));
dock_select->queue_redraw(); dock_select->queue_redraw();
_edit_current(); _edit_current();
_save_docks(); _save_editor_layout();
} }
void EditorNode::_dock_select_draw() { 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) { if (waiting_for_first_scan) {
return; // Scanning, do not touch docks. 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")); config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
_save_docks_to_config(config, "docks"); _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); editor_data.get_plugin_window_layout(config);
config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); 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<ConfigFile> p_layout, const String &p
if (!names.is_empty()) { if (!names.is_empty()) {
p_layout->set_value(p_section, config_key, names); 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; Dictionary floating_docks_dump;
@ -4803,11 +4827,6 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p
p_layout->set_value(p_section, "dock_floating", floating_docks_dump); 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++) { for (int i = 0; i < vsplits.size(); i++) {
if (vsplits[i]->is_visible_in_tree()) { if (vsplits[i]->is_visible_in_tree()) {
p_layout->set_value(p_section, "dock_split_" + itos(i + 1), vsplits[i]->get_split_offset()); 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<ConfigFile> p_layout, const String &p
for (int i = 0; i < hsplits.size(); i++) { for (int i = 0; i < hsplits.size(); i++) {
p_layout->set_value(p_section, "dock_hsplit_" + itos(i + 1), hsplits[i]->get_split_offset()); 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<String> 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<ConfigFile> p_layout, const String &p_section) { void EditorNode::_save_open_scenes_to_config(Ref<ConfigFile> p_layout) {
Array scenes; PackedStringArray scenes;
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
String path = editor_data.get_scene_path(i); String path = editor_data.get_scene_path(i);
if (path.is_empty()) { if (path.is_empty()) {
@ -4828,18 +4858,21 @@ void EditorNode::_save_open_scenes_to_config(Ref<ConfigFile> p_layout, const Str
} }
scenes.push_back(path); 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() { void EditorNode::save_editor_layout_delayed() {
dock_drag_timer->start(); editor_layout_save_delay_timer->start();
} }
void EditorNode::_dock_split_dragged(int ofs) { 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<ConfigFile> config; Ref<ConfigFile> config;
config.instantiate(); config.instantiate();
Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg")); 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_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); editor_data.set_plugin_window_layout(config);
} }
@ -5031,26 +5065,15 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
_dock_floating_close_request(wrapper); _dock_floating_close_request(wrapper);
} }
} }
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_split")) { int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx");
int fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); if (selected_tab_idx >= 0 && selected_tab_idx < dock_slot[i]->get_tab_count()) {
FileSystemDock::get_singleton()->set_split_offset(fs_split_ofs); dock_slot[i]->call_deferred("set_current_tab", selected_tab_idx);
} }
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);
} }
for (int i = 0; i < vsplits.size(); i++) { for (int i = 0; i < vsplits.size(); i++) {
@ -5090,24 +5113,141 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
dock_slot[i]->set_current_tab(0); 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<ConfigFile> p_layout, const String &p_section) { void EditorNode::_save_central_editor_layout_to_config(Ref<ConfigFile> 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<ConfigFile> 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<ConfigFile> p_layout) {
if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) { if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) {
return; 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; return;
} }
restoring_scenes = true; 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++) { for (int i = 0; i < scenes.size(); i++) {
load_scene(scenes[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; restoring_scenes = false;
} }
@ -5122,10 +5262,10 @@ bool EditorNode::has_scenes_in_session() {
if (err != OK) { if (err != OK) {
return false; 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; 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(); return !scenes.is_empty();
} }
@ -5251,7 +5391,7 @@ void EditorNode::_layout_menu_option(int p_id) {
} break; } break;
case SETTINGS_LAYOUT_DEFAULT: { case SETTINGS_LAYOUT_DEFAULT: {
_load_docks_from_config(default_layout, "docks"); _load_docks_from_config(default_layout, "docks");
_save_docks(); _save_editor_layout();
} break; } break;
default: { default: {
Ref<ConfigFile> config; Ref<ConfigFile> 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)); _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(); _discard_changes();
} }
save_layout(); save_editor_layout_delayed();
_update_scene_tabs(); _update_scene_tabs();
} }
@ -5835,7 +5975,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (current_tab == scene_idx) { if (current_tab == scene_idx) {
editor_data.apply_changes_in_editors(); editor_data.apply_changes_in_editors();
_set_scene_metadata(p_path); _save_editor_states(p_path);
} }
// Reload scene. // Reload scene.
@ -6918,11 +7058,11 @@ EditorNode::EditorNode() {
dock_slot[i]->set_use_hidden_tabs_for_min_size(true); dock_slot[i]->set_use_hidden_tabs_for_min_size(true);
} }
dock_drag_timer = memnew(Timer); editor_layout_save_delay_timer = memnew(Timer);
add_child(dock_drag_timer); add_child(editor_layout_save_delay_timer);
dock_drag_timer->set_wait_time(0.5); editor_layout_save_delay_timer->set_wait_time(0.5);
dock_drag_timer->set_one_shot(true); editor_layout_save_delay_timer->set_one_shot(true);
dock_drag_timer->connect("timeout", callable_mp(this, &EditorNode::_save_docks)); editor_layout_save_delay_timer->connect("timeout", callable_mp(this, &EditorNode::_save_editor_layout));
top_split = memnew(VSplitContainer); top_split = memnew(VSplitContainer);
center_split->add_child(top_split); center_split->add_child(top_split);
@ -7403,7 +7543,7 @@ EditorNode::EditorNode() {
FileSystemDock *filesystem_dock = memnew(FileSystemDock); FileSystemDock *filesystem_dock = memnew(FileSystemDock);
filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request)); filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request));
filesystem_dock->connect("instantiate", callable_mp(this, &EditorNode::_instantiate_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); get_project_settings()->connect_filesystem_dock_signals(filesystem_dock);
history_dock = memnew(HistoryDock); history_dock = memnew(HistoryDock);

View File

@ -430,7 +430,7 @@ private:
PopupPanel *dock_select_popup = nullptr; PopupPanel *dock_select_popup = nullptr;
Rect2 dock_select_rect[DOCK_SLOT_MAX]; Rect2 dock_select_rect[DOCK_SLOT_MAX];
TabContainer *dock_slot[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; bool docks_visible = true;
int dock_popup_selected_idx = -1; int dock_popup_selected_idx = -1;
int dock_select_rect_over_idx = -1; int dock_select_rect_over_idx = -1;
@ -559,8 +559,8 @@ private:
void _node_renamed(); void _node_renamed();
void _editor_select_next(); void _editor_select_next();
void _editor_select_prev(); void _editor_select_prev();
void _set_scene_metadata(const String &p_file, int p_idx = -1); void _save_editor_states(const String &p_file, int p_idx = -1);
void _get_scene_metadata(const String &p_file); void _load_editor_plugin_states_from_config(const Ref<ConfigFile> &p_config_file);
void _update_title(); void _update_title();
void _update_scene_tabs(); void _update_scene_tabs();
void _version_control_menu_option(int p_idx); void _version_control_menu_option(int p_idx);
@ -648,16 +648,19 @@ private:
int _get_current_main_editor(); int _get_current_main_editor();
void _save_docks(); void _save_editor_layout();
void _load_docks(); void _load_editor_layout();
void _save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section); void _save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section);
void _restore_floating_dock(const Dictionary &p_dock_dump, Control *p_wrapper, int p_slot_index); void _restore_floating_dock(const Dictionary &p_dock_dump, Control *p_wrapper, int p_slot_index);
void _load_docks_from_config(Ref<ConfigFile> p_layout, const String &p_section); void _load_docks_from_config(Ref<ConfigFile> p_layout, const String &p_section);
void _update_dock_slots_visibility(bool p_keep_selected_tabs = false); void _update_dock_slots_visibility(bool p_keep_selected_tabs = false);
void _dock_tab_changed(int p_tab); void _dock_tab_changed(int p_tab);
void _save_open_scenes_to_config(Ref<ConfigFile> p_layout, const String &p_section); void _save_central_editor_layout_to_config(Ref<ConfigFile> p_config_file);
void _load_open_scenes_from_config(Ref<ConfigFile> p_layout, const String &p_section); void _load_central_editor_layout_from_config(Ref<ConfigFile> p_config_file);
void _save_open_scenes_to_config(Ref<ConfigFile> p_layout);
void _load_open_scenes_from_config(Ref<ConfigFile> p_layout);
void _update_layouts_menu(); void _update_layouts_menu();
void _layout_menu_option(int p_id); void _layout_menu_option(int p_id);
@ -884,7 +887,7 @@ public:
bool is_scene_in_use(const String &p_path); bool is_scene_in_use(const String &p_path);
void save_layout(); void save_editor_layout_delayed();
void save_default_environment(); void save_default_environment();
void open_export_template_manager(); void open_export_template_manager();

View File

@ -471,7 +471,7 @@ bool EditorPlugin::build() {
} }
void EditorPlugin::queue_save_layout() { 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) { void EditorPlugin::make_bottom_panel_item_visible(Control *p_item) {

View File

@ -714,6 +714,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0)); _initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0));
_initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 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 // 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/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") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01")

View File

@ -87,14 +87,14 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_selectable(0, true); subdirectory_item->set_selectable(0, true);
String lpath = p_dir->get_path(); String lpath = p_dir->get_path();
subdirectory_item->set_metadata(0, lpath); 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); subdirectory_item->select(0);
// Keep select an item when re-created a tree // Keep select an item when re-created a tree
// To prevent crashing when nothing is selected. // To prevent crashing when nothing is selected.
subdirectory_item->set_as_cursor(0); 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); subdirectory_item->set_collapsed(false);
} else { } else {
subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0); 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)); file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type));
String file_metadata = lpath.path_join(fi.name); String file_metadata = lpath.path_join(fi.name);
file_item->set_metadata(0, file_metadata); 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->select(0);
file_item->set_as_cursor(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); EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, this, "_tree_thumbnail_done", udata);
} }
} else if (display_mode == DISPLAY_MODE_SPLIT) { } 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->select(0);
subdirectory_item->set_as_cursor(0); subdirectory_item->set_as_cursor(0);
} }
@ -186,8 +186,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
return parent_should_expand; return parent_should_expand;
} }
Vector<String> FileSystemDock::_compute_uncollapsed_paths() { Vector<String> FileSystemDock::get_uncollapsed_paths() const {
// Register currently collapsed paths.
Vector<String> uncollapsed_paths; Vector<String> uncollapsed_paths;
TreeItem *root = tree->get_root(); TreeItem *root = tree->get_root();
if (root) { if (root) {
@ -196,21 +195,24 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
uncollapsed_paths.push_back(favorites_item->get_metadata(0)); uncollapsed_paths.push_back(favorites_item->get_metadata(0));
} }
TreeItem *resTree = root->get_first_child()->get_next(); // BFS to find all uncollapsed paths of the resource directory.
if (resTree) { TreeItem *res_subtree = root->get_first_child()->get_next();
Vector<TreeItem *> needs_check; if (res_subtree) {
needs_check.push_back(resTree); List<TreeItem *> queue;
queue.push_back(res_subtree);
while (needs_check.size()) { while (!queue.is_empty()) {
if (!needs_check[0]->is_collapsed()) { TreeItem *ti = queue.back()->get();
uncollapsed_paths.push_back(needs_check[0]->get_metadata(0)); queue.pop_back();
TreeItem *child = needs_check[0]->get_first_child(); if (!ti->is_collapsed() && ti->get_child_count() > 0) {
while (child) { Variant path = ti->get_metadata(0);
needs_check.push_back(child); if (path) {
child = child->get_next(); 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<String> &p_uncollapsed_paths, boo
ti->set_tooltip_text(0, favorite); ti->set_tooltip_text(0, favorite);
ti->set_selectable(0, true); ti->set_selectable(0, true);
ti->set_metadata(0, favorite); ti->set_metadata(0, favorite);
if (p_select_in_favorites && favorite == path) { if (p_select_in_favorites && favorite == current_path) {
ti->select(0); ti->select(0);
ti->set_as_cursor(0); ti->set_as_cursor(0);
} }
@ -329,7 +331,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
toolbar2_hbc->hide(); toolbar2_hbc->hide();
} }
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
file_list_vb->hide(); file_list_vb->hide();
break; break;
@ -338,7 +340,7 @@ void FileSystemDock::_update_display_mode(bool p_force) {
tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->set_v_size_flags(SIZE_EXPAND_FILL);
tree->ensure_cursor_is_visible(); tree->ensure_cursor_is_visible();
toolbar2_hbc->hide(); toolbar2_hbc->hide();
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
file_list_vb->show(); file_list_vb->show();
_update_file_list(true); _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)); 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)); 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")); 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(); TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) { 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. // Go to the favorites if we click in the favorites and the path has changed.
path = "Favorites"; current_path = "Favorites";
} else { } else {
path = selected->get_metadata(0); current_path = selected->get_metadata(0);
// Note: the "Favorites" item also leads to this path. // Note: the "Favorites" item also leads to this path.
} }
// Set the current path. // Display the current path.
_set_current_path_text(path); _set_current_path_line_edit_text(current_path);
_push_to_history(); _push_to_history();
// Update the file list. // Update the file list.
@ -523,28 +525,28 @@ Vector<String> FileSystemDock::get_selected_paths() const {
} }
String FileSystemDock::get_current_path() const { String FileSystemDock::get_current_path() const {
return path; return current_path;
} }
String FileSystemDock::get_current_directory() const { String FileSystemDock::get_current_directory() const {
if (path.ends_with("/")) { if (current_path.ends_with("/")) {
return path; return current_path;
} else { } 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") { if (p_path == "Favorites") {
current_path->set_text(TTR("Favorites")); current_path_line_edit->set_text(TTR("Favorites"));
} else { } 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) { void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_favorites) {
if (p_path == "Favorites") { if (p_path == "Favorites") {
path = p_path; current_path = p_path;
} else { } else {
String target_path = p_path; 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. // 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<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da->file_exists(p_path)) { if (da->file_exists(p_path)) {
path = target_path; current_path = target_path;
} else if (da->dir_exists(p_path)) { } else if (da->dir_exists(p_path)) {
path = target_path + "/"; current_path = target_path + "/";
} else { } else {
ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path)); 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(); _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) { if (display_mode == DISPLAY_MODE_SPLIT) {
_update_file_list(false); _update_file_list(false);
files->get_v_scroll_bar()->set_value(0); 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<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) { void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &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; Array uarr = p_udata;
int idx = uarr[0]; int idx = uarr[0];
String file = uarr[1]; String file = uarr[1];
@ -749,9 +751,9 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->clear(); files->clear();
_set_current_path_text(path); _set_current_path_line_edit_text(current_path);
String directory = path; String directory = current_path;
String file = ""; String file = "";
int thumbnail_size = EDITOR_GET("docks/filesystem/thumbnail_size"); 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. // Build the FileInfo list.
List<FileInfo> file_list; List<FileInfo> file_list;
if (path == "Favorites") { if (current_path == "Favorites") {
// Display the favorites. // Display the favorites.
Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites(); Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
for (const String &favorite : favorites_list) { 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); EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory);
if (!efd) { if (!efd) {
directory = path.get_base_dir(); directory = current_path.get_base_dir();
file = path.get_file(); file = current_path.get_file();
efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory); efd = EditorFileSystem::get_singleton()->get_filesystem_path(directory);
} }
if (!efd) { if (!efd) {
@ -1084,7 +1086,7 @@ void FileSystemDock::_file_list_activate_file(int p_idx) {
} }
void FileSystemDock::_preview_invalidated(const String &p_path) { 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++) { for (int i = 0; i < files->get_item_count(); i++) {
if (files->get_item_metadata(i) == p_path) { if (files->get_item_metadata(i) == p_path) {
// Re-request preview. // Re-request preview.
@ -1106,7 +1108,7 @@ void FileSystemDock::_fs_changed() {
split_box->show(); split_box->show();
if (tree->is_visible()) { if (tree->is_visible()) {
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
} }
if (file_list_vb->is_visible()) { if (file_list_vb->is_visible()) {
@ -1146,11 +1148,11 @@ void FileSystemDock::_bw_history() {
} }
void FileSystemDock::_update_history() { void FileSystemDock::_update_history() {
path = history[history_pos]; current_path = history[history_pos];
_set_current_path_text(path); _set_current_path_line_edit_text(current_path);
if (tree->is_visible()) { if (tree->is_visible()) {
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
tree->grab_focus(); tree->grab_focus();
tree->ensure_cursor_is_visible(); tree->ensure_cursor_is_visible();
} }
@ -1164,9 +1166,9 @@ void FileSystemDock::_update_history() {
} }
void FileSystemDock::_push_to_history() { void FileSystemDock::_push_to_history() {
if (history[history_pos] != path) { if (history[history_pos] != current_path) {
history.resize(history_pos + 1); history.resize(history_pos + 1);
history.push_back(path); history.push_back(current_path);
history_pos++; history_pos++;
if (history.size() > history_max_size) { 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++) { for (int j = 0; j < ed->get_edited_scene_count(); j++) {
if (ed->get_scene_path(j) == file_changed_paths[i]) { if (ed->get_scene_path(j) == file_changed_paths[i]) {
ed->get_edited_scene_root(j)->set_scene_file_path(new_item_path); 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; 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"); EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.") + "\n" + old_path + "\n");
return; return;
} }
const_cast<FileSystemDock *>(this)->path = new_path; const_cast<FileSystemDock *>(this)->current_path = new_path;
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
@ -1532,27 +1534,27 @@ void FileSystemDock::_file_removed(String p_file) {
emit_signal(SNAME("file_removed"), 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. // 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<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
while (!da->dir_exists(path)) { while (!da->dir_exists(current_path)) {
path = path.get_base_dir(); 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) { void FileSystemDock::_folder_removed(String p_folder) {
emit_signal(SNAME("folder_removed"), 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. // 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<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
while (!da->dir_exists(path)) { while (!da->dir_exists(current_path)) {
path = path.get_base_dir(); current_path = current_path.get_base_dir();
} }
current_path->set_text(path); current_path_line_edit->set_text(current_path);
EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(path); EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_filesystem_path(current_path);
if (efd) { if (efd) {
efd->force_update(); efd->force_update();
} }
@ -1614,8 +1616,8 @@ void FileSystemDock::_rename_operation_confirm() {
print_verbose("FileSystem: saving moved scenes."); print_verbose("FileSystem: saving moved scenes.");
_save_scenes_after_move(file_renames); _save_scenes_after_move(file_renames);
path = new_path; current_path = new_path;
current_path->set_text(path); current_path_line_edit->set_text(current_path);
} }
void FileSystemDock::_duplicate_operation_confirm() { 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."); print_verbose("FileSystem: saving moved scenes.");
_save_scenes_after_move(file_renames); _save_scenes_after_move(file_renames);
path = p_to_path; current_path = p_to_path;
current_path->set_text(path); current_path_line_edit->set_text(current_path);
} }
} }
} }
@ -1840,8 +1842,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
switch (p_option) { switch (p_option) {
case FILE_SHOW_IN_EXPLORER: { case FILE_SHOW_IN_EXPLORER: {
// Show the file/folder in the OS explorer. // Show the file/folder in the OS explorer.
String fpath = path; String fpath = current_path;
if (path == "Favorites") { if (current_path == "Favorites") {
fpath = p_selected[0]; fpath = p_selected[0];
} }
@ -1850,8 +1852,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break; } break;
case FILE_OPEN_EXTERNAL: { case FILE_OPEN_EXTERNAL: {
String fpath = path; String fpath = current_path;
if (path == "Favorites") { if (current_path == "Favorites") {
fpath = p_selected[0]; fpath = p_selected[0];
} }
@ -1914,7 +1916,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (p_selected.size() == 1) { if (p_selected.size() == 1) {
ProjectSettings::get_singleton()->set("application/run/main_scene", p_selected[0]); ProjectSettings::get_singleton()->set("application/run/main_scene", p_selected[0]);
ProjectSettings::get_singleton()->save(); ProjectSettings::get_singleton()->save();
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
_update_file_list(true); _update_file_list(true);
} }
} break; } break;
@ -1942,7 +1944,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} }
} }
EditorSettings::get_singleton()->set_favorites(favorites_list); EditorSettings::get_singleton()->set_favorites(favorites_list);
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
} break; } break;
case FILE_REMOVE_FAVORITE: { case FILE_REMOVE_FAVORITE: {
@ -1952,8 +1954,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
favorites_list.erase(p_selected[i]); favorites_list.erase(p_selected[i]);
} }
EditorSettings::get_singleton()->set_favorites(favorites_list); EditorSettings::get_singleton()->set_favorites(favorites_list);
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
if (path == "Favorites") { if (current_path == "Favorites") {
_update_file_list(true); _update_file_list(true);
} }
} break; } break;
@ -2069,7 +2071,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break; } break;
case FILE_NEW_FOLDER: { case FILE_NEW_FOLDER: {
String directory = path; String directory = current_path;
if (!directory.ends_with("/")) { if (!directory.ends_with("/")) {
directory = directory.get_base_dir(); directory = directory.get_base_dir();
} }
@ -2078,7 +2080,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break; } break;
case FILE_NEW_SCENE: { case FILE_NEW_SCENE: {
String directory = path; String directory = current_path;
if (!directory.ends_with("/")) { if (!directory.ends_with("/")) {
directory = directory.get_base_dir(); directory = directory.get_base_dir();
} }
@ -2087,7 +2089,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break; } break;
case FILE_NEW_SCRIPT: { case FILE_NEW_SCRIPT: {
String fpath = path; String fpath = current_path;
if (!fpath.ends_with("/")) { if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir(); fpath = fpath.get_base_dir();
} }
@ -2116,7 +2118,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
new_resource_dialog->popup_create(true); new_resource_dialog->popup_create(true);
} break; } break;
case FILE_NEW_TEXTFILE: { case FILE_NEW_TEXTFILE: {
String fpath = path; String fpath = current_path;
if (!fpath.ends_with("/")) { if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir(); fpath = fpath.get_base_dir();
} }
@ -2127,7 +2129,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} }
void FileSystemDock::_resource_created() { void FileSystemDock::_resource_created() {
String fpath = path; String fpath = current_path;
if (!fpath.ends_with("/")) { if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir(); 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) { void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) {
if (searched_string.length() == 0) { if (searched_string.length() == 0) {
// Register the uncollapsed paths before they change. // 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(); 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); 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) { switch (display_mode) {
case DISPLAY_MODE_TREE_ONLY: { case DISPLAY_MODE_TREE_ONLY: {
_update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path); _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), 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); 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); _update_file_list(true);
} }
return; 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); 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); 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; return;
} }
@ -2674,7 +2676,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
} }
#endif #endif
path = fpath; current_path = fpath;
} }
} }
@ -2702,7 +2704,7 @@ void FileSystemDock::_tree_empty_click(const Vector2 &p_pos, MouseButton p_butto
return; return;
} }
// Right click is pressed in the empty space of the tree. // Right click is pressed in the empty space of the tree.
path = "res://"; current_path = "res://";
tree_popup->clear(); tree_popup->clear();
tree_popup->reset_size(); tree_popup->reset_size();
tree_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER); 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; return;
} }
path = current_path->get_text(); current_path = current_path_line_edit->get_text();
file_list_popup->clear(); file_list_popup->clear();
file_list_popup->reset_size(); file_list_popup->reset_size();
@ -2791,9 +2793,9 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
if (current == p_index) { if (current == p_index) {
String fpath = files->get_item_metadata(current); String fpath = files->get_item_metadata(current);
if (!fpath.ends_with("/")) { if (!fpath.ends_with("/")) {
path = fpath; current_path = fpath;
if (display_mode == DISPLAY_MODE_SPLIT) { 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; file_sort = p_file_sort;
// Update everything needed. // Update everything needed.
_update_tree(_compute_uncollapsed_paths()); _update_tree(get_uncollapsed_paths());
_update_file_list(true); _update_file_list(true);
} }
@ -3127,7 +3129,7 @@ void FileSystemDock::_bind_methods() {
FileSystemDock::FileSystemDock() { FileSystemDock::FileSystemDock() {
singleton = this; singleton = this;
set_name("FileSystem"); set_name("FileSystem");
path = "res://"; current_path = "res://";
// `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts. // `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); 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.")); button_hist_next->set_tooltip_text(TTR("Go to next selected folder/file."));
toolbar_hbc->add_child(button_hist_next); toolbar_hbc->add_child(button_hist_next);
current_path = memnew(LineEdit); current_path_line_edit = memnew(LineEdit);
current_path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); current_path_line_edit->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
current_path->set_h_size_flags(SIZE_EXPAND_FILL); current_path_line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
_set_current_path_text(path); _set_current_path_line_edit_text(current_path);
toolbar_hbc->add_child(current_path); toolbar_hbc->add_child(current_path_line_edit);
button_reload = memnew(Button); button_reload = memnew(Button);
button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan)); button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));

View File

@ -125,7 +125,7 @@ private:
Button *button_file_list_display_mode = nullptr; Button *button_file_list_display_mode = nullptr;
Button *button_hist_next = nullptr; Button *button_hist_next = nullptr;
Button *button_hist_prev = nullptr; Button *button_hist_prev = nullptr;
LineEdit *current_path = nullptr; LineEdit *current_path_line_edit = nullptr;
HBoxContainer *toolbar2_hbc = nullptr; HBoxContainer *toolbar2_hbc = nullptr;
LineEdit *tree_search_box = nullptr; LineEdit *tree_search_box = nullptr;
@ -185,7 +185,7 @@ private:
int history_pos; int history_pos;
int history_max_size; int history_max_size;
String path; String current_path;
bool initialized = false; bool initialized = false;
@ -204,7 +204,6 @@ private:
Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, String p_file_type); Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, String p_file_type);
bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false); bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
Vector<String> _compute_uncollapsed_paths();
void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false); void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), 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); 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<FileInfo> *matches, int p_max_items); void _search(EditorFileSystemDirectory *p_path, List<FileInfo> *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); 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; bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@ -327,6 +326,7 @@ protected:
public: public:
Vector<String> get_selected_paths() const; Vector<String> get_selected_paths() const;
Vector<String> get_uncollapsed_paths() const;
String get_current_path() const; String get_current_path() const;
String get_current_directory() const; String get_current_directory() const;
@ -351,6 +351,8 @@ public:
void set_file_list_display_mode(FileListDisplayMode p_mode); void set_file_list_display_mode(FileListDisplayMode p_mode);
FileListDisplayMode get_file_list_display_mode() { return file_list_display_mode; }; FileListDisplayMode get_file_list_display_mode() { return file_list_display_mode; };
Tree *get_tree_control() { return tree; }
FileSystemDock(); FileSystemDock();
~FileSystemDock(); ~FileSystemDock();
}; };

View File

@ -3981,10 +3981,6 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
Array selection = editor_selection->get_selected_nodes(); Array selection = editor_selection->get_selected_nodes();
if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) { if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
_reset_drag(); _reset_drag();
// Clear the selection
editor_selection->clear(); //_clear_canvas_items();
editor_selection->add_node(p_canvas_item);
} }
} }

View File

@ -3299,6 +3299,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
orthogonal = false; orthogonal = false;
auto_orthogonal = false; auto_orthogonal = false;
call_deferred(SNAME("update_transform_gizmo_view")); call_deferred(SNAME("update_transform_gizmo_view"));
_update_camera(0);
_update_name(); _update_name();
} break; } break;
@ -3308,8 +3309,8 @@ void Node3DEditorViewport::_menu_option(int p_option) {
orthogonal = true; orthogonal = true;
auto_orthogonal = false; auto_orthogonal = false;
call_deferred(SNAME("update_transform_gizmo_view")); call_deferred(SNAME("update_transform_gizmo_view"));
_update_camera(0);
_update_name(); _update_name();
} break; } break;
case VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL: { case VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL: {
_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_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_NORMAL:
case VIEW_DISPLAY_WIREFRAME: case VIEW_DISPLAY_WIREFRAME:
case VIEW_DISPLAY_OVERDRAW: case VIEW_DISPLAY_OVERDRAW:
case VIEW_DISPLAY_SHADELESS: case VIEW_DISPLAY_UNSHADED:
case VIEW_DISPLAY_LIGHTING: case VIEW_DISPLAY_LIGHTING:
case VIEW_DISPLAY_NORMAL_BUFFER: case VIEW_DISPLAY_NORMAL_BUFFER:
case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS: case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS:
@ -3429,7 +3430,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_WIREFRAME,
VIEW_DISPLAY_OVERDRAW, VIEW_DISPLAY_OVERDRAW,
VIEW_DISPLAY_SHADELESS, VIEW_DISPLAY_UNSHADED,
VIEW_DISPLAY_LIGHTING, VIEW_DISPLAY_LIGHTING,
VIEW_DISPLAY_NORMAL_BUFFER, VIEW_DISPLAY_NORMAL_BUFFER,
VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
@ -3778,15 +3779,9 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) {
if (p_state.has("distance")) { if (p_state.has("distance")) {
cursor.distance = p_state["distance"]; cursor.distance = p_state["distance"];
} }
if (p_state.has("orthogonal")) {
if (p_state.has("use_orthogonal")) { bool orth = p_state["orthogonal"];
bool orth = p_state["use_orthogonal"]; _menu_option(orth ? VIEW_ORTHOGONAL : VIEW_PERSPECTIVE);
if (orth) {
_menu_option(VIEW_ORTHOGONAL);
} else {
_menu_option(VIEW_PERSPECTIVE);
}
} }
if (p_state.has("view_type")) { if (p_state.has("view_type")) {
view_type = ViewType(p_state["view_type"].operator int()); 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 display = p_state["display_mode"];
int idx = view_menu->get_popup()->get_item_index(display); 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); _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")) { 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); int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
view_menu->get_popup()->set_item_checked(idx, half_res); view_menu->get_popup()->set_item_checked(idx, half_res);
_update_shrink();
} }
if (p_state.has("cinematic_preview")) { if (p_state.has("cinematic_preview")) {
previewing_cinema = p_state["cinematic_preview"]; previewing_cinema = p_state["cinematic_preview"];
@ -3896,19 +3897,27 @@ Dictionary Node3DEditorViewport::get_state() const {
d["y_rotation"] = cursor.y_rot; d["y_rotation"] = cursor.y_rot;
d["distance"] = cursor.distance; d["distance"] = cursor.distance;
d["use_environment"] = camera->get_environment().is_valid(); 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["view_type"] = view_type;
d["auto_orthogonal"] = auto_orthogonal; 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)); 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; // Find selected display mode.
} else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME))) { int display_mode = VIEW_DISPLAY_NORMAL;
d["display_mode"] = VIEW_DISPLAY_WIREFRAME; for (int i = VIEW_DISPLAY_NORMAL; i < VIEW_DISPLAY_ADVANCED; i++) {
} else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW))) { if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(i))) {
d["display_mode"] = VIEW_DISPLAY_OVERDRAW; display_mode = i;
} else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS))) { break;
d["display_mode"] = VIEW_DISPLAY_SHADELESS;
} }
}
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["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["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)); 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_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_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_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); 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->set_hide_on_checkable_item_selection(false);
display_submenu->add_radio_check_item(TTR("Directional Shadow Splits"), VIEW_DISPLAY_DEBUG_PSSM_SPLITS); 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 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 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 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."); const String unsupported_tooltip = TTR("Not available when using the OpenGL renderer.");
view_menu->get_popup()->set_item_disabled(normal_idx, true); view_menu->get_popup()->set_item_disabled(normal_idx, true);

View File

@ -125,25 +125,28 @@ class Node3DEditorViewport : public Control {
VIEW_GIZMOS, VIEW_GIZMOS,
VIEW_INFORMATION, VIEW_INFORMATION,
VIEW_FRAME_TIME, VIEW_FRAME_TIME,
// < Keep in sync with menu.
VIEW_DISPLAY_NORMAL, VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_WIREFRAME,
VIEW_DISPLAY_OVERDRAW, VIEW_DISPLAY_OVERDRAW,
VIEW_DISPLAY_SHADELESS,
VIEW_DISPLAY_LIGHTING, VIEW_DISPLAY_LIGHTING,
VIEW_DISPLAY_UNSHADED,
VIEW_DISPLAY_ADVANCED, VIEW_DISPLAY_ADVANCED,
// Advanced menu:
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_NORMAL_BUFFER, VIEW_DISPLAY_NORMAL_BUFFER,
VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS,
VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO, VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO,
VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING, VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING,
VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION, VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION,
VIEW_DISPLAY_DEBUG_SDFGI,
VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO, VIEW_DISPLAY_DEBUG_SSAO,
VIEW_DISPLAY_DEBUG_SSIL, 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_GI_BUFFER,
VIEW_DISPLAY_DEBUG_DISABLE_LOD, VIEW_DISPLAY_DEBUG_DISABLE_LOD,
VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS, VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS,
@ -152,6 +155,8 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES, VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES,
VIEW_DISPLAY_DEBUG_OCCLUDERS, VIEW_DISPLAY_DEBUG_OCCLUDERS,
VIEW_DISPLAY_MOTION_VECTORS, VIEW_DISPLAY_MOTION_VECTORS,
VIEW_DISPLAY_MAX,
// > Keep in sync with menu.
VIEW_LOCK_ROTATION, VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW, VIEW_CINEMATIC_PREVIEW,

View File

@ -2325,7 +2325,6 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
if (tab_container->get_current_tab() != i) { if (tab_container->get_current_tab() != i) {
_go_to_tab(i); _go_to_tab(i);
_update_script_names();
} }
if (is_visible_in_tree()) { if (is_visible_in_tree()) {
se->ensure_focus(); se->ensure_focus();
@ -2707,7 +2706,7 @@ void ScriptEditor::_save_layout() {
return; return;
} }
EditorNode::get_singleton()->save_layout(); EditorNode::get_singleton()->save_editor_layout_delayed();
} }
void ScriptEditor::_editor_settings_changed() { void ScriptEditor::_editor_settings_changed() {
@ -3251,12 +3250,24 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
restoring_layout = false; restoring_layout = false;
_update_script_names(); _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<ScriptEditorBase>(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<ConfigFile> p_layout) { void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
Array scripts; Array scripts;
Array helps; Array helps;
String selected_script;
for (int i = 0; i < tab_container->get_tab_count(); i++) { for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i)); ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) { if (se) {
@ -3265,6 +3276,10 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
continue; continue;
} }
if (tab_container->get_current_tab_control() == tab_container->get_tab_control(i)) {
selected_script = path;
}
_save_editor_state(se); _save_editor_state(se);
scripts.push_back(path); scripts.push_back(path);
} }
@ -3277,6 +3292,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
} }
p_layout->set_value("ScriptEditor", "open_scripts", scripts); 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", "open_help", helps);
p_layout->set_value("ScriptEditor", "script_split_offset", script_split->get_split_offset()); 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()); p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());

View File

@ -180,6 +180,24 @@ void ShaderEditorPlugin::make_visible(bool p_visible) {
void ShaderEditorPlugin::selected_notify() { void ShaderEditorPlugin::selected_notify() {
} }
TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &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<Shader> &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<ConfigFile> p_layout) { void ShaderEditorPlugin::set_window_layout(Ref<ConfigFile> 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")) { 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( window_wrapper->restore_window_from_saved_position(
@ -189,6 +207,38 @@ void ShaderEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
} else { } else {
window_wrapper->set_window_enabled(false); 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<Resource> 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<ConfigFile> p_layout) { void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
@ -209,24 +259,25 @@ void ShaderEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->erase_section_key("ShaderEditor", "window_screen_rect"); p_layout->erase_section_key("ShaderEditor", "window_screen_rect");
} }
} }
}
TextShaderEditor *ShaderEditorPlugin::get_shader_editor(const Ref<Shader> &p_for_shader) { Array shaders;
for (EditedShader &edited_shader : edited_shaders) { String selected_shader;
if (edited_shader.shader == p_for_shader) { for (int i = 0; i < shader_tabs->get_tab_count(); i++) {
return edited_shader.shader_editor; EditedShader edited_shader = edited_shaders[i];
} if (edited_shader.shader_editor || edited_shader.visual_shader_editor) {
} shaders.push_back(edited_shader.shader->get_path());
return nullptr;
}
VisualShaderEditor *ShaderEditorPlugin::get_visual_shader_editor(const Ref<Shader> &p_for_shader) { TextShaderEditor *shader_editor = Object::cast_to<TextShaderEditor>(shader_tabs->get_current_tab_control());
for (EditedShader &edited_shader : edited_shaders) { VisualShaderEditor *visual_shader_editor = Object::cast_to<VisualShaderEditor>(shader_tabs->get_current_tab_control());
if (edited_shader.shader == p_for_shader) {
return edited_shader.visual_shader_editor; 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; }
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() { void ShaderEditorPlugin::save_external_data() {
@ -247,6 +298,10 @@ void ShaderEditorPlugin::apply_changes() {
} }
void ShaderEditorPlugin::_shader_selected(int p_index) { void ShaderEditorPlugin::_shader_selected(int p_index) {
if (p_index >= (int)edited_shaders.size()) {
return;
}
if (edited_shaders[p_index].shader_editor) { if (edited_shaders[p_index].shader_editor) {
edited_shaders[p_index].shader_editor->validate_script(); edited_shaders[p_index].shader_editor->validate_script();
} }

View File

@ -108,12 +108,13 @@ public:
virtual bool handles(Object *p_object) const override; virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override; virtual void make_visible(bool p_visible) override;
virtual void selected_notify() override; virtual void selected_notify() override;
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
TextShaderEditor *get_shader_editor(const Ref<Shader> &p_for_shader); TextShaderEditor *get_shader_editor(const Ref<Shader> &p_for_shader);
VisualShaderEditor *get_visual_shader_editor(const Ref<Shader> &p_for_shader); VisualShaderEditor *get_visual_shader_editor(const Ref<Shader> &p_for_shader);
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
virtual void save_external_data() override; virtual void save_external_data() override;
virtual void apply_changes() override; virtual void apply_changes() override;

View File

@ -748,7 +748,7 @@ TreeItem *TreeItem::get_first_child() const {
return first_child; 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 *current = this;
TreeItem *prev_item = current->get_prev(); TreeItem *prev_item = current->get_prev();
@ -771,7 +771,7 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
} }
} else { } else {
current = prev_item; current = prev_item;
while (!current->collapsed && current->first_child) { while ((!current->collapsed || p_include_invisible) && current->first_child) {
//go to the very end //go to the very end
current = current->first_child; 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 *TreeItem::get_prev_visible(bool p_wrap) {
TreeItem *loop = this; 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()) { 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) { if (prev_item == loop) {
// Check that we haven't looped all the way around to the start. // Check that we haven't looped all the way around to the start.
prev_item = nullptr; prev_item = nullptr;
@ -798,10 +798,10 @@ TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
return prev_item; 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; TreeItem *current = this;
if (!current->collapsed && current->first_child) { if ((!current->collapsed || p_include_invisible) && current->first_child) {
current = current->first_child; current = current->first_child;
} else if (current->next) { } 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 *TreeItem::get_next_visible(bool p_wrap) {
TreeItem *loop = this; 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()) { 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) { if (next_item == loop) {
// Check that we haven't looped all the way around to the start. // Check that we haven't looped all the way around to the start.
next_item = nullptr; next_item = nullptr;
@ -839,6 +839,16 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return next_item; 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) { TreeItem *TreeItem::get_child(int p_index) {
_create_children_cache(); _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_parent"), &TreeItem::get_parent);
ClassDB::bind_method(D_METHOD("get_first_child"), &TreeItem::get_first_child); 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_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_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; 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) { void Tree::_do_incr_search(const String &p_add) {
uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec uint64_t time = OS::get_singleton()->get_ticks_usec() / 1000; // convert to msec
uint64_t diff = time - last_keypress; uint64_t diff = time - last_keypress;

View File

@ -217,8 +217,8 @@ private:
void _propagate_check_through_children(int p_column, bool p_checked, bool p_emit_signal); 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); void _propagate_check_through_parents(int p_column, bool p_emit_signal);
TreeItem *_get_prev_visible(bool p_wrap = false); TreeItem *_get_prev_in_tree(bool p_wrap = false, bool p_include_invisible = false);
TreeItem *_get_next_visible(bool p_wrap = false); TreeItem *_get_next_in_tree(bool p_wrap = false, bool p_include_invisible = false);
public: public:
void set_text(int p_column, String p_text); void set_text(int p_column, String p_text);
@ -344,6 +344,9 @@ public:
TreeItem *get_parent() const; TreeItem *get_parent() const;
TreeItem *get_first_child() 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_prev_visible(bool p_wrap = false);
TreeItem *get_next_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); 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. // 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_text(const String &p_find) const;
TreeItem *get_item_with_metadata(const Variant &p_find, int p_column = -1) const;
Point2 get_scroll() const; Point2 get_scroll() const;
void scroll_to_item(TreeItem *p_item, bool p_center_on_item = false); void scroll_to_item(TreeItem *p_item, bool p_center_on_item = false);