summaryrefslogtreecommitdiffstats
path: root/editor/filesystem_dock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/filesystem_dock.cpp')
-rw-r--r--editor/filesystem_dock.cpp313
1 files changed, 216 insertions, 97 deletions
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 0f83e109fa..2e88540fc4 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -59,8 +59,6 @@
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/progress_bar.h"
-#include "scene/gui/texture_rect.h"
-#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
#include "servers/display_server.h"
@@ -81,6 +79,15 @@ Control *FileSystemList::make_custom_tooltip(const String &p_text) const {
}
void FileSystemList::_line_editor_submit(const String &p_text) {
+ if (popup_edit_commited) {
+ return; // Already processed by _text_editor_popup_modal_close
+ }
+
+ if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) {
+ return; // ESC pressed, app focus lost, or forced close from code.
+ }
+
+ popup_edit_commited = true; // End edit popup processing.
popup_editor->hide();
emit_signal(SNAME("item_edited"));
@@ -129,6 +136,7 @@ bool FileSystemList::edit_selected() {
line_editor->set_text(name);
line_editor->select(0, name.rfind("."));
+ popup_edit_commited = false; // Start edit popup processing.
popup_editor->popup();
popup_editor->child_controls_changed();
line_editor->grab_focus();
@@ -140,10 +148,12 @@ String FileSystemList::get_edit_text() {
}
void FileSystemList::_text_editor_popup_modal_close() {
- if (Input::get_singleton()->is_key_pressed(Key::ESCAPE) ||
- Input::get_singleton()->is_key_pressed(Key::KP_ENTER) ||
- Input::get_singleton()->is_key_pressed(Key::ENTER)) {
- return;
+ if (popup_edit_commited) {
+ return; // Already processed by _text_editor_popup_modal_close
+ }
+
+ if (popup_editor->get_hide_reason() == Popup::HIDE_REASON_CANCELED) {
+ return; // ESC pressed, app focus lost, or forced close from code.
}
_line_editor_submit(line_editor->get_text());
@@ -234,15 +244,15 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
Color custom_color = has_custom_color ? folder_colors[assigned_folder_colors[lpath]] : Color();
if (has_custom_color) {
- subdirectory_item->set_icon_modulate(0, editor_is_dark_theme ? custom_color : custom_color * 1.75);
- subdirectory_item->set_custom_bg_color(0, Color(custom_color, editor_is_dark_theme ? 0.1 : 0.15));
+ subdirectory_item->set_icon_modulate(0, editor_is_dark_theme ? custom_color : custom_color * ITEM_COLOR_SCALE);
+ subdirectory_item->set_custom_bg_color(0, Color(custom_color, editor_is_dark_theme ? ITEM_ALPHA_MIN : ITEM_ALPHA_MAX));
} else {
TreeItem *parent = subdirectory_item->get_parent();
if (parent) {
Color parent_bg_color = parent->get_custom_bg_color(0);
if (parent_bg_color != Color()) {
bool parent_has_custom_color = assigned_folder_colors.has(parent->get_metadata(0));
- subdirectory_item->set_custom_bg_color(0, parent_has_custom_color ? parent_bg_color.darkened(0.3) : parent_bg_color);
+ subdirectory_item->set_custom_bg_color(0, parent_has_custom_color ? parent_bg_color.darkened(ITEM_BG_DARK_SCALE) : parent_bg_color);
subdirectory_item->set_icon_modulate(0, parent->get_icon_modulate(0));
} else {
subdirectory_item->set_icon_modulate(0, get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
@@ -265,9 +275,9 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
if (p_unfold_path && current_path.begins_with(lpath) && current_path != lpath) {
subdirectory_item->set_collapsed(false);
} else {
- subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0);
+ subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath));
}
- if (searched_string.length() > 0 && dname.to_lower().find(searched_string) >= 0) {
+ if (!searched_tokens.is_empty() && _matches_all_search_tokens(dname)) {
parent_should_expand = true;
}
@@ -293,8 +303,8 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
}
String file_name = p_dir->get_file(i);
- if (searched_string.length() > 0) {
- if (file_name.to_lower().find(searched_string) < 0) {
+ if (!searched_tokens.is_empty()) {
+ if (!_matches_all_search_tokens(file_name)) {
// The searched string is not in the file name, we skip it.
continue;
} else {
@@ -317,7 +327,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
_sort_file_info_list(file_list);
// Build the tree.
- const int icon_size = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
+ const int icon_size = get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor));
for (const FileInfo &fi : file_list) {
TreeItem *file_item = tree->create_item(subdirectory_item);
@@ -328,7 +338,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
file_item->set_icon_max_width(0, icon_size);
Color parent_bg_color = subdirectory_item->get_custom_bg_color(0);
if (has_custom_color) {
- file_item->set_custom_bg_color(0, parent_bg_color.darkened(0.3));
+ file_item->set_custom_bg_color(0, parent_bg_color.darkened(ITEM_BG_DARK_SCALE));
} else if (parent_bg_color != Color()) {
file_item->set_custom_bg_color(0, parent_bg_color);
}
@@ -352,7 +362,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
}
}
- if (searched_string.length() > 0) {
+ if (!searched_tokens.is_empty()) {
if (parent_should_expand) {
subdirectory_item->set_collapsed(false);
} else if (dname != "res://") {
@@ -411,7 +421,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
favorites_item->set_text(0, TTR("Favorites:"));
favorites_item->set_metadata(0, "Favorites");
- favorites_item->set_collapsed(p_uncollapsed_paths.find("Favorites") < 0);
+ favorites_item->set_collapsed(!p_uncollapsed_paths.has("Favorites"));
Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorites();
@@ -453,14 +463,14 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
int index;
EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->find_file(favorite, &index);
if (dir) {
- icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_path(index), dir->get_file_type(index));
+ icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_type(index), _get_entry_script_icon(dir, index));
} else {
icon = get_editor_theme_icon(SNAME("File"));
}
color = Color(1, 1, 1);
}
- if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
+ if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
TreeItem *ti = tree->create_item(favorites_item);
ti->set_text(0, text);
ti->set_icon(0, icon);
@@ -542,10 +552,10 @@ void FileSystemDock::_notification(int p_what) {
EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &FileSystemDock::_fs_changed));
EditorResourcePreview::get_singleton()->connect("preview_invalidated", callable_mp(this, &FileSystemDock::_preview_invalidated));
- button_file_list_display_mode->connect("pressed", callable_mp(this, &FileSystemDock::_toggle_file_display));
+ button_file_list_display_mode->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_toggle_file_display));
files->connect("item_activated", callable_mp(this, &FileSystemDock::_file_list_activate_file));
- button_hist_next->connect("pressed", callable_mp(this, &FileSystemDock::_fw_history));
- button_hist_prev->connect("pressed", callable_mp(this, &FileSystemDock::_bw_history));
+ button_hist_next->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_fw_history));
+ button_hist_prev->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_bw_history));
file_list_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_list_rmb_option));
tree_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option));
current_path_line_edit->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path).bind(false));
@@ -576,9 +586,9 @@ void FileSystemDock::_notification(int p_what) {
if ((String(dd["favorite"]) == "all")) {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
}
- } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) {
+ } else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs")) {
tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM | Tree::DROP_MODE_INBETWEEN);
- } else if ((String(dd["type"]) == "nodes")) {
+ } else if ((String(dd["type"]) == "nodes") || (String(dd["type"]) == "resource")) {
holding_branch = true;
TreeItem *item = tree->get_next_selected(tree->get_root());
while (item) {
@@ -776,16 +786,11 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
_navigate_to_path(p_path);
// Ensure that the FileSystem dock is visible.
- if (get_window() == get_tree()->get_root()) {
- TabContainer *tab_container = (TabContainer *)get_parent_control();
- tab_container->set_current_tab(tab_container->get_tab_idx_from_control((Control *)this));
- } else {
- get_window()->grab_focus();
- }
+ EditorDockManager::get_singleton()->focus_dock(this);
}
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() || current_path.trim_suffix("/") == p_path.get_base_dir()) && p_preview.is_valid()) {
+ if (p_preview.is_valid()) {
Array uarr = p_udata;
int idx = uarr[0];
String file = uarr[1];
@@ -862,7 +867,7 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
for (int i = 0; i < p_path->get_file_count(); i++) {
String file = p_path->get_file(i);
- if (file.to_lower().contains(searched_string)) {
+ if (_matches_all_search_tokens(file)) {
FileInfo fi;
fi.name = file;
fi.type = p_path->get_file_type(i);
@@ -885,7 +890,7 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> *
struct FileSystemDock::FileInfoTypeComparator {
bool operator()(const FileInfo &p_a, const FileInfo &p_b) const {
- return NaturalNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename());
+ return FileNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename());
}
};
@@ -989,14 +994,14 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
if (favorite == "res://") {
text = "/";
icon = folder_icon;
- if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
+ if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
files->add_item(text, icon, true);
files->set_item_metadata(-1, favorite);
}
} else if (favorite.ends_with("/")) {
text = favorite.substr(0, favorite.length() - 1).get_file();
icon = folder_icon;
- if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
+ if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
files->add_item(text, icon, true);
files->set_item_metadata(-1, favorite);
}
@@ -1009,6 +1014,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
fi.path = favorite;
if (efd) {
fi.type = efd->get_file_type(index);
+ fi.icon_path = _get_entry_script_icon(efd, index);
fi.import_broken = !efd->get_file_import_is_valid(index);
fi.modified_time = efd->get_file_modified_time(index);
} else {
@@ -1017,7 +1023,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
fi.modified_time = 0;
}
- if (searched_string.length() == 0 || fi.name.to_lower().find(searched_string) >= 0) {
+ if (searched_tokens.is_empty() || _matches_all_search_tokens(fi.name)) {
file_list.push_back(fi);
}
}
@@ -1040,7 +1046,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
return;
}
- if (searched_string.length() > 0) {
+ if (!searched_tokens.is_empty()) {
// Display the search results.
// Limit the number of results displayed to avoid an infinite loop.
_search(EditorFileSystem::get_singleton()->get_filesystem(), &file_list, 10000);
@@ -1072,7 +1078,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->set_item_metadata(-1, bd);
files->set_item_selectable(-1, false);
- files->set_item_icon_modulate(-1, editor_is_dark_theme ? inherited_folder_color : inherited_folder_color * 1.75);
+ files->set_item_icon_modulate(-1, editor_is_dark_theme ? inherited_folder_color : inherited_folder_color * ITEM_COLOR_SCALE);
}
bool reversed = file_sort == FILE_SORT_NAME_REVERSE;
@@ -1086,7 +1092,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
files->add_item(dname, folder_icon, true);
files->set_item_metadata(-1, dpath);
Color this_folder_color = has_custom_color ? folder_colors[assigned_folder_colors[dpath]] : inherited_folder_color;
- files->set_item_icon_modulate(-1, editor_is_dark_theme ? this_folder_color : this_folder_color * 1.75);
+ files->set_item_icon_modulate(-1, editor_is_dark_theme ? this_folder_color : this_folder_color * ITEM_COLOR_SCALE);
if (previous_selection.has(dname)) {
files->select(files->get_item_count() - 1, false);
@@ -1101,6 +1107,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
fi.name = efd->get_file(i);
fi.path = directory.path_join(fi.name);
fi.type = efd->get_file_type(i);
+ fi.icon_path = _get_entry_script_icon(efd, i);
fi.import_broken = !efd->get_file_import_is_valid(i);
fi.modified_time = efd->get_file_modified_time(i);
@@ -1118,7 +1125,6 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
FileInfo *finfo = &(E);
String fname = finfo->name;
String fpath = finfo->path;
- String ftype = finfo->type;
Ref<Texture2D> type_icon;
Ref<Texture2D> big_icon;
@@ -1126,11 +1132,10 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
String tooltip = fpath;
// Select the icons.
+ type_icon = _get_tree_item_icon(!finfo->import_broken, finfo->type, finfo->icon_path);
if (!finfo->import_broken) {
- type_icon = (has_theme_icon(ftype, EditorStringName(EditorIcons))) ? get_editor_theme_icon(ftype) : get_editor_theme_icon(SNAME("Object"));
big_icon = file_thumbnail;
} else {
- type_icon = get_editor_theme_icon(SNAME("ImportFail"));
big_icon = file_thumbnail_broken;
tooltip += "\n" + TTR("Status: Import of file failed. Please fix file and reimport manually.");
}
@@ -1227,8 +1232,10 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
if (is_imported) {
SceneImportSettingsDialog::get_singleton()->open_settings(p_path, resource_type == "AnimationLibrary");
- } else {
+ } else if (resource_type == "PackedScene") {
EditorNode::get_singleton()->open_request(fpath);
+ } else {
+ EditorNode::get_singleton()->load_resource(fpath);
}
} else if (ResourceLoader::is_imported(fpath)) {
// If the importer has advanced settings, show them.
@@ -1277,7 +1284,7 @@ void FileSystemDock::_file_list_activate_file(int p_idx) {
}
void FileSystemDock::_preview_invalidated(const String &p_path) {
- if (file_list_display_mode == FILE_LIST_DISPLAY_THUMBNAILS && p_path.get_base_dir() == current_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_tokens.is_empty() && file_list_vb->is_visible_in_tree()) {
for (int i = 0; i < files->get_item_count(); i++) {
if (files->get_item_metadata(i) == p_path) {
// Re-request preview.
@@ -1566,11 +1573,16 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
}
void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const {
- // Update the paths in ResourceUID, so that UIDs remain valid.
- for (const KeyValue<String, ResourceUID::ID> &pair : p_uids) {
- if (p_renames.has(pair.key)) {
- ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]);
+ for (const KeyValue<String, String> &pair : p_renames) {
+ // Update UID path.
+ const String &old_path = pair.key;
+ const String &new_path = pair.value;
+
+ const HashMap<String, ResourceUID::ID>::ConstIterator I = p_uids.find(old_path);
+ if (I) {
+ ResourceUID::get_singleton()->set_id(I->value, new_path);
}
+ EditorFileSystem::get_singleton()->register_global_class_script(old_path, new_path);
}
// Rename all resources loaded, be it subresources or actual resources.
@@ -1588,10 +1600,13 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str
if (p_renames.has(base_path)) {
base_path = p_renames[base_path];
+ r->set_path(base_path + extra_path);
}
-
- r->set_path(base_path + extra_path);
}
+
+ ScriptServer::save_global_classes();
+ EditorNode::get_editor_data().script_class_save_icon_paths();
+ EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated"));
}
void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const HashSet<String> &p_file_owners) const {
@@ -1715,6 +1730,13 @@ void FileSystemDock::_make_scene_confirm() {
}
void FileSystemDock::_resource_removed(const Ref<Resource> &p_resource) {
+ const Ref<Script> &scr = p_resource;
+ if (scr.is_valid()) {
+ ScriptServer::remove_global_class_by_path(scr->get_path());
+ ScriptServer::save_global_classes();
+ EditorNode::get_editor_data().script_class_save_icon_paths();
+ EditorFileSystem::get_singleton()->emit_signal(SNAME("script_classes_updated"));
+ }
emit_signal(SNAME("resource_removed"), p_resource);
}
@@ -1741,8 +1763,19 @@ void FileSystemDock::_folder_removed(const String &p_folder) {
current_path = current_path.get_base_dir();
}
- if (assigned_folder_colors.has(p_folder)) {
- assigned_folder_colors.erase(p_folder);
+ // Remove assigned folder color for all subfolders.
+ bool folder_colors_updated = false;
+ List<Variant> paths;
+ assigned_folder_colors.get_key_list(&paths);
+ for (const Variant &E : paths) {
+ const String &path = E;
+ // These folder paths are guaranteed to end with a "/".
+ if (path.begins_with(p_folder)) {
+ assigned_folder_colors.erase(path);
+ folder_colors_updated = true;
+ }
+ }
+ if (folder_colors_updated) {
_update_folder_colors_setting();
}
@@ -2043,7 +2076,7 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo
Vector<String> FileSystemDock::_remove_self_included_paths(Vector<String> selected_strings) {
// Remove paths or files that are included into another.
if (selected_strings.size() > 1) {
- selected_strings.sort_custom<NaturalNoCaseComparator>();
+ selected_strings.sort_custom<FileNoCaseComparator>();
String last_path = "";
for (int i = 0; i < selected_strings.size(); i++) {
if (!last_path.is_empty() && selected_strings[i].begins_with(last_path)) {
@@ -2213,6 +2246,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
terminal_emulator_args.push_back("--working-directory");
} else if (chosen_terminal_emulator.ends_with("urxvt")) {
terminal_emulator_args.push_back("-cd");
+ } else if (chosen_terminal_emulator.ends_with("xfce4-terminal")) {
+ terminal_emulator_args.push_back("--working-directory");
}
}
#endif
@@ -2247,11 +2282,11 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
}
const bool is_directory = fpath.ends_with("/");
- for (int i = 0; i < terminal_emulator_args.size(); i++) {
+ for (String &terminal_emulator_arg : terminal_emulator_args) {
if (is_directory) {
- terminal_emulator_args[i] = terminal_emulator_args[i].replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath));
+ terminal_emulator_arg = terminal_emulator_arg.replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath));
} else {
- terminal_emulator_args[i] = terminal_emulator_args[i].replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath).get_base_dir());
+ terminal_emulator_arg = terminal_emulator_arg.replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath).get_base_dir());
}
}
@@ -2267,8 +2302,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
const Error err = OS::get_singleton()->create_process(chosen_terminal_emulator, terminal_emulator_args, nullptr, true);
if (err != OK) {
String args_string;
- for (int i = 0; i < terminal_emulator_args.size(); i++) {
- args_string += terminal_emulator_args[i];
+ for (const String &terminal_emulator_arg : terminal_emulator_args) {
+ args_string += terminal_emulator_arg;
}
ERR_PRINT_ED(vformat(TTR("Couldn't run external terminal program (error code %d): %s %s\nCheck `filesystem/external_programs/terminal_emulator` and `filesystem/external_programs/terminal_emulator_flags` in the Editor Settings."), err, chosen_terminal_emulator, args_string));
}
@@ -2279,7 +2314,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
TreeItem *selected = tree->get_root();
selected = tree->get_next_selected(selected);
while (selected) {
- if (p_selected.find(selected->get_metadata(0)) >= 0) {
+ if (p_selected.has(selected->get_metadata(0))) {
selected->set_collapsed(false);
}
selected = tree->get_next_selected(selected);
@@ -2346,6 +2381,12 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
}
} break;
+ case FILE_SHOW_IN_FILESYSTEM: {
+ if (!p_selected.is_empty()) {
+ navigate_to_path(p_selected[0]);
+ }
+ } break;
+
case FILE_DEPENDENCIES: {
// Checkout the file dependencies.
if (!p_selected.is_empty()) {
@@ -2492,6 +2533,14 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
}
} break;
+ case FILE_COPY_ABSOLUTE_PATH: {
+ if (!p_selected.is_empty()) {
+ const String &fpath = p_selected[0];
+ const String absolute_path = ProjectSettings::get_singleton()->globalize_path(fpath);
+ DisplayServer::get_singleton()->clipboard_set(absolute_path);
+ }
+ } break;
+
case FILE_COPY_UID: {
if (!p_selected.is_empty()) {
ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_selected[0]);
@@ -2556,12 +2605,13 @@ void FileSystemDock::_resource_created() {
}
void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) {
- if (searched_string.length() == 0) {
+ if (searched_tokens.is_empty()) {
// Register the uncollapsed paths before they change.
uncollapsed_paths_before_search = get_uncollapsed_paths();
}
- searched_string = p_text.to_lower();
+ const String searched_string = p_text.to_lower();
+ searched_tokens = searched_string.split(" ", false);
if (p_from == tree_search_box) {
file_list_search_box->set_text(searched_string);
@@ -2572,16 +2622,29 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
bool unfold_path = (p_text.is_empty() && !current_path.is_empty());
switch (display_mode) {
case DISPLAY_MODE_TREE_ONLY: {
- _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
+ _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
} break;
case DISPLAY_MODE_HSPLIT:
case DISPLAY_MODE_VSPLIT: {
_update_file_list(false);
- _update_tree(searched_string.length() == 0 ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
+ _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
} break;
}
}
+bool FileSystemDock::_matches_all_search_tokens(const String &p_text) {
+ if (searched_tokens.is_empty()) {
+ return false;
+ }
+ const String s = p_text.to_lower();
+ for (const String &t : searched_tokens) {
+ if (!s.contains(t)) {
+ return false;
+ }
+ }
+ return true;
+}
+
void FileSystemDock::_rescan() {
_set_scanning_mode();
EditorFileSystem::get_singleton()->scan();
@@ -2762,7 +2825,7 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
String to_dir;
bool favorite;
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
- return !to_dir.is_empty();
+ return !favorite;
}
if (drag_data.has("type") && (String(drag_data["type"]) == "files" || String(drag_data["type"]) == "files_and_dirs")) {
@@ -2877,7 +2940,12 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
Ref<Resource> res = drag_data["resource"];
String to_dir;
bool favorite;
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
+ if (to_dir.is_empty()) {
+ to_dir = get_current_directory();
+ }
+
if (res.is_valid() && !to_dir.is_empty()) {
EditorNode::get_singleton()->push_item(res.ptr());
EditorNode::get_singleton()->save_resource_as(res, to_dir);
@@ -2923,7 +2991,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
if (drag_data.has("type") && String(drag_data["type"]) == "nodes") {
String to_dir;
bool favorite;
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
_get_drag_target_folder(to_dir, favorite, p_point, p_from);
+ if (to_dir.is_empty()) {
+ to_dir = get_current_directory();
+ }
SceneTreeDock::get_singleton()->save_branch_to_file(to_dir);
}
}
@@ -2936,6 +3008,7 @@ void FileSystemDock::_get_drag_target_folder(String &target, bool &target_favori
if (p_from == files) {
int pos = files->get_item_at_position(p_point, true);
if (pos == -1) {
+ target = get_current_directory();
return;
}
@@ -3029,6 +3102,8 @@ void FileSystemDock::_folder_color_index_pressed(int p_index, PopupMenu *p_menu)
_update_tree(get_uncollapsed_paths());
_update_file_list(true);
+
+ emit_signal(SNAME("folder_color_changed"));
}
void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vector<String> &p_paths, bool p_display_path_dependent_options) {
@@ -3144,6 +3219,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
if (p_paths.size() == 1) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCopy")), ED_GET_SHORTCUT("filesystem_dock/copy_path"), FILE_COPY_PATH);
+ p_popup->add_shortcut(ED_GET_SHORTCUT("filesystem_dock/copy_absolute_path"), FILE_COPY_ABSOLUTE_PATH);
if (ResourceLoader::get_resource_uid(p_paths[0]) != ResourceUID::INVALID_ID) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Instance")), ED_GET_SHORTCUT("filesystem_dock/copy_uid"), FILE_COPY_UID);
}
@@ -3203,8 +3279,33 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
if (p_paths.size() == 1) {
const String &fpath = p_paths[0];
+ [[maybe_unused]] bool added_separator = false;
+
+ if (favorites_list.has(fpath)) {
+ TreeItem *favorites_item = tree->get_root()->get_first_child();
+ TreeItem *cursor_item = tree->get_selected();
+ bool is_item_in_favorites = false;
+ while (cursor_item != nullptr) {
+ if (cursor_item == favorites_item) {
+ is_item_in_favorites = true;
+ break;
+ }
+
+ cursor_item = cursor_item->get_parent();
+ }
+
+ if (is_item_in_favorites) {
+ p_popup->add_separator();
+ added_separator = true;
+ p_popup->add_icon_item(get_editor_theme_icon(SNAME("ShowInFileSystem")), TTR("Show in FileSystem"), FILE_SHOW_IN_FILESYSTEM);
+ }
+ }
+
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
- p_popup->add_separator();
+ if (!added_separator) {
+ p_popup->add_separator();
+ added_separator = true;
+ }
// Opening the system file manager is not supported on the Android and web editors.
const bool is_directory = fpath.ends_with("/");
@@ -3296,7 +3397,7 @@ void FileSystemDock::_file_list_item_clicked(int p_item, const Vector2 &p_pos, M
// Popup.
if (!paths.is_empty()) {
file_list_popup->clear();
- _file_and_folders_fill_popup(file_list_popup, paths, searched_string.length() == 0);
+ _file_and_folders_fill_popup(file_list_popup, paths, searched_tokens.is_empty());
file_list_popup->set_position(files->get_screen_position() + p_pos);
file_list_popup->reset_size();
file_list_popup->popup();
@@ -3309,7 +3410,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton
}
// Right click on empty space for file list.
- if (searched_string.length() > 0) {
+ if (!searched_tokens.is_empty()) {
return;
}
@@ -3325,6 +3426,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton
file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("TextFile")), TTR("New TextFile..."), FILE_NEW_TEXTFILE);
file_list_popup->add_separator();
file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
+ file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
file_list_popup->set_position(files->get_screen_position() + p_pos);
file_list_popup->reset_size();
@@ -3431,6 +3533,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
_tree_rmb_option(FILE_DUPLICATE);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
_tree_rmb_option(FILE_COPY_PATH);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/copy_absolute_path", p_event)) {
+ _tree_rmb_option(FILE_COPY_ABSOLUTE_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_uid", p_event)) {
_tree_rmb_option(FILE_COPY_UID);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
@@ -3458,37 +3562,41 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && holding_branch) {
- const int item_idx = files->get_item_at_position(mm->get_position());
+ const int item_idx = files->get_item_at_position(mm->get_position(), true);
+ files->deselect_all();
+ String fpath;
if (item_idx != -1) {
- files->deselect_all();
- String fpath = files->get_item_metadata(item_idx);
+ fpath = files->get_item_metadata(item_idx);
if (fpath.ends_with("/") || fpath == "res://") {
files->select(item_idx);
}
+ } else {
+ fpath = get_current_directory();
+ }
- TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
- while (deselect_item) {
- deselect_item->deselect(0);
- deselect_item = tree->get_next_selected(deselect_item);
+ TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
+ while (deselect_item) {
+ deselect_item->deselect(0);
+ deselect_item = tree->get_next_selected(deselect_item);
+ }
+
+ // Try to select the corresponding tree item.
+ TreeItem *tree_item = (item_idx != -1) ? tree->get_item_with_text(files->get_item_text(item_idx)) : nullptr;
+
+ if (tree_item) {
+ tree_item->select(0);
+ } else {
+ // Find parent folder.
+ fpath = fpath.substr(0, fpath.rfind("/") + 1);
+ if (fpath.size() > String("res://").size()) {
+ fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
+ const int slash_idx = fpath.rfind("/");
+ fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
}
- // Try to select the corresponding tree item.
- TreeItem *tree_item = tree->get_item_with_text(files->get_item_text(item_idx));
+ tree_item = tree->get_item_with_text(fpath);
if (tree_item) {
tree_item->select(0);
- } else {
- // Find parent folder.
- fpath = fpath.substr(0, fpath.rfind("/") + 1);
- if (fpath.size() > String("res://").size()) {
- fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
- const int slash_idx = fpath.rfind("/");
- fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
- }
-
- tree_item = tree->get_item_with_text(fpath);
- if (tree_item) {
- tree_item->select(0);
- }
}
}
}
@@ -3499,6 +3607,8 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
_file_list_rmb_option(FILE_DUPLICATE);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
_file_list_rmb_option(FILE_COPY_PATH);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/copy_absolute_path", p_event)) {
+ _file_list_rmb_option(FILE_COPY_ABSOLUTE_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
_file_list_rmb_option(FILE_REMOVE);
} else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
@@ -3626,6 +3736,10 @@ void FileSystemDock::_feature_profile_changed() {
_update_display_mode(true);
}
+void FileSystemDock::_project_settings_changed() {
+ assigned_folder_colors = ProjectSettings::get_singleton()->get_setting("file_customization/folder_colors");
+}
+
void FileSystemDock::set_file_sort(FileSortOption p_file_sort) {
for (int i = 0; i != FILE_SORT_MAX; i++) {
tree_button_sort->get_popup()->set_item_checked(i, (i == (int)p_file_sort));
@@ -3725,6 +3839,7 @@ void FileSystemDock::_bind_methods() {
ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder")));
ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file")));
ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_folder")));
+ ADD_SIGNAL(MethodInfo("folder_color_changed"));
ADD_SIGNAL(MethodInfo("display_mode_changed"));
}
@@ -3802,6 +3917,7 @@ FileSystemDock::FileSystemDock() {
// `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_absolute_path", TTR("Copy Absolute Path"));
ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"));
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KeyModifierMask::CMD_OR_CTRL | Key::D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), Key::KEY_DELETE);
@@ -3857,14 +3973,14 @@ FileSystemDock::FileSystemDock() {
toolbar_hbc->add_child(current_path_line_edit);
button_reload = memnew(Button);
- button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));
+ button_reload->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_rescan));
button_reload->set_focus_mode(FOCUS_NONE);
button_reload->set_tooltip_text(TTR("Re-Scan Filesystem"));
button_reload->hide();
toolbar_hbc->add_child(button_reload);
button_toggle_display_mode = memnew(Button);
- button_toggle_display_mode->connect("pressed", callable_mp(this, &FileSystemDock::_change_split_mode));
+ button_toggle_display_mode->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_change_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
button_toggle_display_mode->set_tooltip_text(TTR("Change Split Mode"));
button_toggle_display_mode->set_theme_type_variation("FlatMenuButton");
@@ -3872,7 +3988,7 @@ FileSystemDock::FileSystemDock() {
button_dock_placement = memnew(Button);
button_dock_placement->set_flat(true);
- button_dock_placement->connect("pressed", callable_mp(this, &FileSystemDock::_change_bottom_dock_placement));
+ button_dock_placement->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_change_bottom_dock_placement));
button_dock_placement->hide();
toolbar_hbc->add_child(button_dock_placement);
@@ -3905,7 +4021,9 @@ FileSystemDock::FileSystemDock() {
add_child(split_box);
tree = memnew(FileSystemTree);
+ tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
tree->set_hide_root(true);
SET_DRAG_FORWARDING_GCD(tree, FileSystemDock);
tree->set_allow_rmb_select(true);
@@ -3919,8 +4037,8 @@ FileSystemDock::FileSystemDock() {
tree->connect("item_mouse_selected", callable_mp(this, &FileSystemDock::_tree_rmb_select));
tree->connect("empty_clicked", callable_mp(this, &FileSystemDock::_tree_empty_click));
tree->connect("nothing_selected", callable_mp(this, &FileSystemDock::_tree_empty_selected));
- tree->connect("gui_input", callable_mp(this, &FileSystemDock::_tree_gui_input));
- tree->connect("mouse_exited", callable_mp(this, &FileSystemDock::_tree_mouse_exited));
+ tree->connect(SceneStringName(gui_input), callable_mp(this, &FileSystemDock::_tree_gui_input));
+ tree->connect(SceneStringName(mouse_exited), callable_mp(this, &FileSystemDock::_tree_mouse_exited));
tree->connect("item_edited", callable_mp(this, &FileSystemDock::_rename_operation_confirm));
file_list_vb = memnew(VBoxContainer);
@@ -3949,7 +4067,7 @@ FileSystemDock::FileSystemDock() {
files->set_select_mode(ItemList::SELECT_MULTI);
SET_DRAG_FORWARDING_GCD(files, FileSystemDock);
files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));
- files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
+ files->connect(SceneStringName(gui_input), callable_mp(this, &FileSystemDock::_file_list_gui_input));
files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
files->connect("empty_clicked", callable_mp(this, &FileSystemDock::_file_list_empty_clicked));
files->connect("item_edited", callable_mp(this, &FileSystemDock::_rename_operation_confirm));
@@ -3989,7 +4107,7 @@ FileSystemDock::FileSystemDock() {
overwrite_dialog = memnew(ConfirmationDialog);
add_child(overwrite_dialog);
overwrite_dialog->set_ok_button_text(TTR("Overwrite"));
- overwrite_dialog->add_button(TTR("Keep Both"), true)->connect("pressed", callable_mp(this, &FileSystemDock::_overwrite_dialog_action).bind(false));
+ overwrite_dialog->add_button(TTR("Keep Both"), true)->connect(SceneStringName(pressed), callable_mp(this, &FileSystemDock::_overwrite_dialog_action).bind(false));
overwrite_dialog->connect("confirmed", callable_mp(this, &FileSystemDock::_overwrite_dialog_action).bind(true));
VBoxContainer *overwrite_dialog_vb = memnew(VBoxContainer);
@@ -4039,7 +4157,6 @@ FileSystemDock::FileSystemDock() {
new_resource_dialog->set_base_type("Resource");
new_resource_dialog->connect("create", callable_mp(this, &FileSystemDock::_resource_created));
- searched_string = String();
uncollapsed_paths_before_search = Vector<String>();
tree_update_id = 0;
@@ -4052,7 +4169,9 @@ FileSystemDock::FileSystemDock() {
old_display_mode = DISPLAY_MODE_TREE_ONLY;
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
+ ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &FileSystemDock::_project_settings_changed));
add_resource_tooltip_plugin(memnew(EditorTextureTooltipPlugin));
+ add_resource_tooltip_plugin(memnew(EditorAudioStreamTooltipPlugin));
}
FileSystemDock::~FileSystemDock() {