diff --git a/editor/file_system/dependency_editor.cpp b/editor/file_system/dependency_editor.cpp index aa3e4d63d0..e0bcddd665 100644 --- a/editor/file_system/dependency_editor.cpp +++ b/editor/file_system/dependency_editor.cpp @@ -42,7 +42,9 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/box_container.h" #include "scene/gui/item_list.h" +#include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" +#include "scene/gui/menu_button.h" #include "scene/gui/popup_menu.h" #include "scene/gui/tree.h" @@ -60,6 +62,34 @@ static void _setup_search_file_dialog(EditorFileDialog *p_dialog, const String & } } +struct DependencyEditorSortByType { + bool operator()(const String &p_a, const String &p_b) const { + const String a_type = p_a.contains("::") ? p_a.get_slice("::", 1) : "Resource"; + const String b_type = p_b.contains("::") ? p_b.get_slice("::", 1) : "Resource"; + const String a_path = p_a.contains("::") ? p_a.get_slice("::", 2) : p_a; + const String b_path = p_b.contains("::") ? p_b.get_slice("::", 2) : p_b; + return a_type == b_type ? a_path < b_path : a_type < b_type; + } +}; + +struct DependencyEditorSortByPath { + bool operator()(const String &p_a, const String &p_b) const { + const String a_path = p_a.contains("::") ? p_a.get_slice("::", 2) : p_a; + const String b_path = p_b.contains("::") ? p_b.get_slice("::", 2) : p_b; + return a_path < b_path; + } +}; + +struct DependencyEditorSortByFile { + bool operator()(const String &p_a, const String &p_b) const { + const String a_path = p_a.contains("::") ? p_a.get_slice("::", 2) : p_a; + const String b_path = p_b.contains("::") ? p_b.get_slice("::", 2) : p_b; + const String a_file = a_path.get_file(); + const String b_file = b_path.get_file(); + return a_file == b_file ? a_path < b_path : a_file < b_file; + } +}; + void DependencyEditor::_searched(const String &p_path) { HashMap dep_rename; dep_rename[replacing] = p_path; @@ -75,7 +105,7 @@ void DependencyEditor::_load_pressed(Object *p_item, int p_cell, int p_button, M return; } TreeItem *ti = Object::cast_to(p_item); - replacing = ti->get_text(1); + replacing = ti->get_text((int)Column::PATH); _setup_search_file_dialog(search, replacing, ti->get_metadata(0)); search->popup_file_dialog(); @@ -176,6 +206,8 @@ void DependencyEditor::_update_file() { void DependencyEditor::_notification(int p_what) { if (p_what == NOTIFICATION_THEME_CHANGED) { warning_label->add_theme_color_override(SceneStringName(font_color), get_theme_color("warning_color", EditorStringName(Editor))); + filter->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + menu_sort->set_button_icon(get_editor_theme_icon(SNAME("Sort"))); } } @@ -203,9 +235,56 @@ static String _get_stored_dep_path(const String &p_dep) { return p_dep.get_slice("::", 0); } +List DependencyEditor::_filter_deps(const List &p_deps) { + const String filter_text = filter->get_text(); + + if (filter_text.is_empty()) { + return p_deps; + } + + List filtered; + + for (const String &item : p_deps) { + const String path = item.contains("::") ? item.get_slice("::", 2) : item; + + if (path.containsn(filter_text)) { + filtered.push_back(item); + } + } + + return filtered; +} + void DependencyEditor::_update_list() { List deps; ResourceLoader::get_dependencies(editing, &deps, true); + deps = _filter_deps(deps); + + switch (sort_by) { + case DependencyEditorSortBy::TYPE: + deps.sort_custom(); + break; + case DependencyEditorSortBy::TYPE_REVERSE: + deps.sort_custom(); + deps.reverse(); + break; + case DependencyEditorSortBy::PATH: + deps.sort_custom(); + break; + case DependencyEditorSortBy::PATH_REVERSE: + deps.sort_custom(); + deps.reverse(); + break; + case DependencyEditorSortBy::NAME: + deps.sort_custom(); + break; + case DependencyEditorSortBy::NAME_REVERSE: + deps.sort_custom(); + deps.reverse(); + break; + default: + break; + } tree->clear(); missing.clear(); @@ -221,23 +300,26 @@ void DependencyEditor::_update_list() { const String path = _get_resolved_dep_path(dep); if (FileAccess::exists(path)) { - item->set_text(0, path.get_file()); - item->set_text(1, path); + item->set_text((int)Column::NAME, path.get_file()); + item->set_text((int)Column::PATH, path); } else { const String &stored_path = _get_stored_dep_path(dep); - item->set_text(0, stored_path.get_file()); - item->set_text(1, stored_path); - item->set_custom_color(1, Color(1, 0.4, 0.3)); + item->set_text((int)Column::NAME, stored_path.get_file()); + item->set_text((int)Column::PATH, stored_path); + item->set_custom_color((int)Column::PATH, Color(1, 0.4, 0.3)); missing.push_back(stored_path); broken = true; } const String type = dep.contains("::") ? dep.get_slice("::", 1) : "Resource"; + String name = path.get_file(); Ref icon = EditorNode::get_singleton()->get_class_icon(type); - item->set_icon(0, icon); + item->set_icon((int)Column::TYPE, icon); item->set_metadata(0, type); - - item->add_button(1, folder, 0); + item->set_text((int)Column::TYPE, type); + item->set_text((int)Column::NAME, name); + item->set_text((int)Column::PATH, path); + item->add_button((int)Column::PATH, folder, 0); } fixdeps->set_disabled(!broken); @@ -247,6 +329,9 @@ void DependencyEditor::edit(const String &p_path) { editing = p_path; set_title(TTR("Dependencies For:") + " " + p_path.get_file()); + filter->set_text(""); + + _update_menu_sort(); _update_list(); if (EditorNode::get_singleton()->is_scene_open(p_path)) { @@ -261,21 +346,37 @@ void DependencyEditor::edit(const String &p_path) { popup_centered_ratio(0.4); } +void DependencyEditor::_sort_option_selected(int p_id) { + sort_by = (DependencyEditorSortBy)p_id; + _update_menu_sort(); + _update_list(); +} + +void DependencyEditor::_update_menu_sort() { + for (int i = 0; i != (int)DependencyEditorSortBy::MAX; i++) { + menu_sort->get_popup()->set_item_checked(i, (i == (int)sort_by)); + } +} + DependencyEditor::DependencyEditor() { VBoxContainer *vb = memnew(VBoxContainer); - vb->set_name(TTR("Dependencies")); add_child(vb); tree = memnew(Tree); tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_theme_type_variation("TreeTable"); tree->set_hide_folding(true); - tree->set_columns(2); + tree->set_columns((int)Column::MAX); tree->set_column_titles_visible(true); - tree->set_column_title(0, TTR("Resource")); - tree->set_column_clip_content(0, true); - tree->set_column_title(1, TTR("Path")); - tree->set_column_clip_content(1, true); + tree->set_column_title((int)Column::TYPE, TTRC("Type")); + tree->set_column_clip_content((int)Column::TYPE, true); + tree->set_column_expand_ratio((int)Column::TYPE, 2); + tree->set_column_title((int)Column::NAME, TTRC("Name")); + tree->set_column_clip_content((int)Column::NAME, true); + tree->set_column_expand_ratio((int)Column::NAME, 3); + tree->set_column_title((int)Column::PATH, TTRC("Path")); + tree->set_column_clip_content((int)Column::PATH, true); + tree->set_column_expand_ratio((int)Column::PATH, 5); tree->set_hide_root(true); tree->connect("button_clicked", callable_mp(this, &DependencyEditor::_load_pressed)); @@ -291,6 +392,34 @@ DependencyEditor::DependencyEditor() { vb->add_child(hbc); + HBoxContainer *hbc_filter = memnew(HBoxContainer); + vb->add_child(hbc_filter); + filter = memnew(LineEdit); + filter->set_accessibility_name(TTRC("Filter Dependencies")); + filter->set_placeholder(TTRC("Filter Dependencies")); + filter->set_clear_button_enabled(true); + filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); + filter->connect(SceneStringName(text_changed), callable_mp(this, &DependencyEditor::_update_list).unbind(1)); + hbc_filter->add_child(filter); + + menu_sort = memnew(MenuButton); + menu_sort->set_flat(false); + menu_sort->set_theme_type_variation("FlatMenuButton"); + menu_sort->set_tooltip_text(TTRC("Sort Dependencies")); + menu_sort->set_accessibility_name(TTRC("Sort Dependencies")); + + PopupMenu *popup_sort = menu_sort->get_popup(); + popup_sort->connect(SceneStringName(id_pressed), callable_mp(this, &DependencyEditor::_sort_option_selected)); + popup_sort->add_radio_check_item(TTRC("Sort by Type (Ascending)"), (int)DependencyEditorSortBy::TYPE); + popup_sort->add_radio_check_item(TTRC("Sort by Type (Descending)"), (int)DependencyEditorSortBy::TYPE_REVERSE); + popup_sort->add_radio_check_item(TTRC("Sort by Name (Ascending)"), (int)DependencyEditorSortBy::NAME); + popup_sort->add_radio_check_item(TTRC("Sort by Name (Descending)"), (int)DependencyEditorSortBy::NAME_REVERSE); + popup_sort->add_radio_check_item(TTRC("Sort by Path (Ascending)"), (int)DependencyEditorSortBy::PATH); + popup_sort->add_radio_check_item(TTRC("Sort by Path (Descending)"), (int)DependencyEditorSortBy::PATH_REVERSE); + popup_sort->set_item_checked((int)sort_by, true); + + hbc_filter->add_child(menu_sort); + MarginContainer *mc = memnew(MarginContainer); mc->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/file_system/dependency_editor.h b/editor/file_system/dependency_editor.h index 5fd637514f..63950a1fc0 100644 --- a/editor/file_system/dependency_editor.h +++ b/editor/file_system/dependency_editor.h @@ -39,6 +39,25 @@ class PopupMenu; class Tree; class TreeItem; class VBoxContainer; +class LineEdit; +class MenuButton; + +enum class DependencyEditorSortBy { + TYPE, + TYPE_REVERSE, + NAME, + NAME_REVERSE, + PATH, + PATH_REVERSE, + MAX, +}; + +enum class Column { + TYPE, + NAME, + PATH, + MAX, +}; class DependencyEditor : public AcceptDialog { GDCLASS(DependencyEditor, AcceptDialog); @@ -46,9 +65,12 @@ class DependencyEditor : public AcceptDialog { Tree *tree = nullptr; Button *fixdeps = nullptr; Label *warning_label = nullptr; + LineEdit *filter = nullptr; + MenuButton *menu_sort = nullptr; EditorFileDialog *search = nullptr; + DependencyEditorSortBy sort_by = DependencyEditorSortBy::PATH; String replacing; String editing; List missing; @@ -57,9 +79,12 @@ class DependencyEditor : public AcceptDialog { void _searched(const String &p_path); void _load_pressed(Object *p_item, int p_cell, int p_button, MouseButton p_mouse_button); + List _filter_deps(const List &p_deps); void _fix_all(); void _update_list(); + void _update_menu_sort(); + void _sort_option_selected(int p_id); void _update_file(); protected: