feat(dependency_editor): add sort button and text filter to the dependency editor dialog

This commit is contained in:
Joel Gomes da Silva 2025-12-12 14:46:28 -03:00
parent 77579f93e6
commit b3f9f8264c
2 changed files with 169 additions and 15 deletions

View file

@ -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<String, String> 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<TreeItem>(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<String> DependencyEditor::_filter_deps(const List<String> &p_deps) {
const String filter_text = filter->get_text();
if (filter_text.is_empty()) {
return p_deps;
}
List<String> 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<String> deps;
ResourceLoader::get_dependencies(editing, &deps, true);
deps = _filter_deps(deps);
switch (sort_by) {
case DependencyEditorSortBy::TYPE:
deps.sort_custom<DependencyEditorSortByType>();
break;
case DependencyEditorSortBy::TYPE_REVERSE:
deps.sort_custom<DependencyEditorSortByType>();
deps.reverse();
break;
case DependencyEditorSortBy::PATH:
deps.sort_custom<DependencyEditorSortByPath>();
break;
case DependencyEditorSortBy::PATH_REVERSE:
deps.sort_custom<DependencyEditorSortByPath>();
deps.reverse();
break;
case DependencyEditorSortBy::NAME:
deps.sort_custom<DependencyEditorSortByFile>();
break;
case DependencyEditorSortBy::NAME_REVERSE:
deps.sort_custom<DependencyEditorSortByFile>();
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<Texture2D> 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);

View file

@ -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<String> 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<String> _filter_deps(const List<String> &p_deps);
void _fix_all();
void _update_list();
void _update_menu_sort();
void _sort_option_selected(int p_id);
void _update_file();
protected: