mirror of
https://github.com/godotengine/godot.git
synced 2024-11-25 21:52:51 +00:00
Improve Scene Tree Dock's Node filter (Allow multiple terms & more)
- Allows more than one parameter to be passed in the "Filter Node" search box, each term separated by spaces. - Grays out any parent Node not matching the search, but still having to be there because a child is. - Adds a `group:` filter. It matches any Node belonging to the passed group. If no argument is passed, it matches all Nodes belonging to any group. It also ignores groups used internally, and its alias is `g`.
This commit is contained in:
parent
e7a0a97c0b
commit
1c4095a66a
@ -602,7 +602,7 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
|
||||
updating_tree = false;
|
||||
tree_dirty = false;
|
||||
|
||||
if (!filter.is_empty()) {
|
||||
if (!filter.strip_edges().is_empty()) {
|
||||
_update_filter(nullptr, p_scroll_to_selected);
|
||||
}
|
||||
}
|
||||
@ -617,18 +617,28 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
|
||||
return false;
|
||||
}
|
||||
|
||||
bool keep = false;
|
||||
bool keep_for_children = false;
|
||||
for (TreeItem *child = p_parent->get_first_child(); child; child = child->get_next()) {
|
||||
keep = _update_filter(child, p_scroll_to_selected) || keep;
|
||||
// Always keep if at least one of the children are kept.
|
||||
keep_for_children = _update_filter(child, p_scroll_to_selected) || keep_for_children;
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
StringName node_type = get_node(p_parent->get_metadata(0))->get_class();
|
||||
bool is_kept_by_type = (filter.begins_with("type:") && filter.trim_prefix("type:").is_subsequence_ofn(node_type)) || (filter.begins_with("t:") && filter.trim_prefix("t:").is_subsequence_ofn(node_type));
|
||||
keep = (filter.is_subsequence_ofn(p_parent->get_text(0)) || is_kept_by_type);
|
||||
// Now find other reasons to keep this Node, too.
|
||||
PackedStringArray terms = filter.to_lower().split_spaces();
|
||||
bool keep = _item_matches_all_terms(p_parent, terms);
|
||||
|
||||
p_parent->set_visible(keep_for_children || keep);
|
||||
if (keep_for_children) {
|
||||
if (keep) {
|
||||
p_parent->clear_custom_color(0);
|
||||
p_parent->set_selectable(0, true);
|
||||
} else {
|
||||
p_parent->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
|
||||
p_parent->set_selectable(0, false);
|
||||
p_parent->deselect(0);
|
||||
}
|
||||
}
|
||||
|
||||
p_parent->set_visible(keep);
|
||||
if (editor_selection) {
|
||||
Node *n = get_node(p_parent->get_metadata(0));
|
||||
if (keep) {
|
||||
@ -643,7 +653,68 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
|
||||
}
|
||||
}
|
||||
|
||||
return keep;
|
||||
return keep || keep_for_children;
|
||||
}
|
||||
|
||||
bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms) {
|
||||
if (p_terms.is_empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_terms.size(); i++) {
|
||||
String term = p_terms[i];
|
||||
|
||||
// Recognise special filter.
|
||||
if (term.contains(":") && !term.get_slicec(':', 0).is_empty()) {
|
||||
String parameter = term.get_slicec(':', 0);
|
||||
String argument = term.get_slicec(':', 1);
|
||||
|
||||
if (parameter == "type" || parameter == "t") {
|
||||
// Filter by Type.
|
||||
String node_type = get_node(p_item->get_metadata(0))->get_class().to_lower();
|
||||
|
||||
if (!node_type.contains(argument)) {
|
||||
return false;
|
||||
}
|
||||
} else if (parameter == "group" || parameter == "g") {
|
||||
// Filter by Group.
|
||||
Node *node = get_node(p_item->get_metadata(0));
|
||||
|
||||
List<Node::GroupInfo> group_info_list;
|
||||
node->get_groups(&group_info_list);
|
||||
if (group_info_list.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
// When argument is empty, match all Nodes belonging to any group.
|
||||
if (!argument.is_empty()) {
|
||||
bool term_in_groups = false;
|
||||
for (int j = 0; j < group_info_list.size(); j++) {
|
||||
// Ignore private groups.
|
||||
if (String(group_info_list[j].name).begins_with("__")) {
|
||||
continue;
|
||||
}
|
||||
if (String(group_info_list[j].name).to_lower().contains(argument)) {
|
||||
term_in_groups = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!term_in_groups) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WARN_PRINT(vformat(TTR("Special Node filter \"%s\" is not recognised. Available filters include \"type\" and \"group\"."), parameter));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Default.
|
||||
if (!p_item->get_text(0).to_lower().contains(term)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneTreeEditor::_compute_hash(Node *p_node, uint64_t &hash) {
|
||||
|
@ -78,6 +78,7 @@ class SceneTreeEditor : public Control {
|
||||
void _test_update_tree();
|
||||
void _update_tree(bool p_scroll_to_selected = false);
|
||||
bool _update_filter(TreeItem *p_parent = nullptr, bool p_scroll_to_selected = false);
|
||||
bool _item_matches_all_terms(TreeItem *p_item, PackedStringArray p_terms);
|
||||
void _tree_changed();
|
||||
void _tree_process_mode_changed();
|
||||
void _node_removed(Node *p_node);
|
||||
|
Loading…
Reference in New Issue
Block a user