Compare commits

..

2 Commits

Author SHA1 Message Date
monxa a1949026b3
Merge 6776319472 into 760af804c0 2024-10-06 06:57:29 +02:00
Alexander Montag 6776319472
Implement Tree Search Functionality with Highlighting and Filtering
This commit introduces a comprehensive Tree Search feature, including:
- Tree highlighting: Highlights items that match the search query.
- Tree filtering: Filters items so only matches and descendants are
  shown.
- Counting descendants: Shows the number of matching items within collapsed branches.
- Jump to next match: on enter.
- (Limbo-)Shortcut: Default CTRL-F.
- Menu entry: Misc->Search Tree.
- Remember separate SearchInfo for each tab.

Key implementation details:
- Optimized performance for large trees
- Implemented recursive filtering for efficiency
- Added UI elements including next/previous match buttons

Development History:
- Initial implementation of highlighting and filtering
- Multiple rounds of performance optimization
- Bug fixes and refactoring for correctness
- UI enhancements and polish
- Code cleanup and style improvements
2024-10-06 06:57:11 +02:00
1 changed files with 26 additions and 7 deletions

View File

@ -56,9 +56,13 @@ void TreeSearch::_clean_callable_cache() {
void TreeSearch::_filter_tree() { void TreeSearch::_filter_tree() {
ERR_FAIL_COND(!tree_reference); ERR_FAIL_COND(!tree_reference);
if (!tree_reference->get_root()) {
return;
}
if (matching_entries.is_empty()) { if (matching_entries.is_empty()) {
return; return;
} }
_filter_tree(tree_reference->get_root(), false); _filter_tree(tree_reference->get_root(), false);
} }
@ -76,6 +80,10 @@ void TreeSearch::_filter_tree(TreeItem *p_item, bool p_parent_matching) {
// Makes all tree items visible. // Makes all tree items visible.
void TreeSearch::_clear_filter() { void TreeSearch::_clear_filter() {
ERR_FAIL_COND(!tree_reference); ERR_FAIL_COND(!tree_reference);
if (!tree_reference->get_root()) {
return;
}
Vector<TreeItem *> items = { tree_reference->get_root() }; Vector<TreeItem *> items = { tree_reference->get_root() };
for (int idx = 0; idx < items.size(); idx++) { for (int idx = 0; idx < items.size(); idx++) {
TreeItem *cur_item = items[idx]; TreeItem *cur_item = items[idx];
@ -220,8 +228,9 @@ void TreeSearch::_update_matching_entries(const String &p_search_mask) {
- i4 ---> [i1,i2,i3,i4] - i4 ---> [i1,i2,i3,i4]
*/ */
void TreeSearch::_update_ordered_tree_items(TreeItem *p_tree_item) { void TreeSearch::_update_ordered_tree_items(TreeItem *p_tree_item) {
if (!p_tree_item) if (!p_tree_item) {
return; return;
}
if (p_tree_item == p_tree_item->get_tree()->get_root()) { if (p_tree_item == p_tree_item->get_tree()->get_root()) {
ordered_tree_items.clear(); ordered_tree_items.clear();
} }
@ -241,11 +250,11 @@ void TreeSearch::_update_number_matches() {
number_matches.clear(); number_matches.clear();
number_matches.reserve(ordered_tree_items.size()); number_matches.reserve(ordered_tree_items.size());
TreeItem * tree_root = tree_reference->get_root(); TreeItem *tree_root = tree_reference->get_root();
if (!tree_root){ if (!tree_root) {
return; return;
} }
_update_number_matches(tree_reference->get_root()); _update_number_matches(tree_root);
} }
void TreeSearch::_update_number_matches(TreeItem *item) { void TreeSearch::_update_number_matches(TreeItem *item) {
@ -268,7 +277,7 @@ void TreeSearch::_update_number_matches(TreeItem *item) {
} }
String TreeSearch::_get_search_mask() const { String TreeSearch::_get_search_mask() const {
ERR_FAIL_COND(!search_panel); ERR_FAIL_COND_V(!search_panel, "");
return search_panel->get_text(); return search_panel->get_text();
} }
@ -276,10 +285,12 @@ void TreeSearch::_find_matching_entries(TreeItem *p_tree_item, const String &p_s
if (!p_tree_item) { if (!p_tree_item) {
return; return;
} }
StringSearchIndices item_search_indices = _substring_bounds(p_tree_item->get_text(0), p_search_mask); StringSearchIndices item_search_indices = _substring_bounds(p_tree_item->get_text(0), p_search_mask);
if (item_search_indices.hit()) { if (item_search_indices.hit()) {
p_accum.push_back(p_tree_item); p_accum.push_back(p_tree_item);
} }
for (int i = 0; i < p_tree_item->get_child_count(); i++) { for (int i = 0; i < p_tree_item->get_child_count(); i++) {
TreeItem *child = p_tree_item->get_child(i); TreeItem *child = p_tree_item->get_child(i);
_find_matching_entries(child, p_search_mask, p_accum); _find_matching_entries(child, p_search_mask, p_accum);
@ -336,8 +347,10 @@ TreeSearch::StringSearchIndices TreeSearch::_substring_bounds(const String &p_se
} }
void TreeSearch::_select_item(TreeItem *p_item) { void TreeSearch::_select_item(TreeItem *p_item) {
if (!p_item) if (!p_item) {
return; return;
}
ERR_FAIL_COND(!tree_reference || p_item->get_tree() != tree_reference); ERR_FAIL_COND(!tree_reference || p_item->get_tree() != tree_reference);
// First unfold ancestors // First unfold ancestors
@ -472,12 +485,18 @@ void TreeSearch::update_search(Tree *p_tree) {
tree_reference = p_tree; tree_reference = p_tree;
if (!tree_reference->get_root()) {
return;
}
if (!search_panel->is_visible() || search_panel->get_text().length() == 0) { if (!search_panel->is_visible() || search_panel->get_text().length() == 0) {
// Clear and redraw if search was active recently. // Clear and redraw if search was active recently.
if (was_searched_recently) { if (was_searched_recently) {
_clear_filter();
number_matches.clear(); number_matches.clear();
matching_entries.clear(); matching_entries.clear();
_clear_filter();
was_searched_recently = false; was_searched_recently = false;
p_tree->queue_redraw(); p_tree->queue_redraw();
} }