Compare commits

..

2 Commits

Author SHA1 Message Date
monxa 5607244db6
Merge 14cfb14ab9 into 760af804c0 2024-10-06 04:28:12 +00:00
Alexander Montag 14cfb14ab9
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:28:03 +02:00
1 changed files with 7 additions and 26 deletions

View File

@ -56,13 +56,9 @@ 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);
} }
@ -80,10 +76,6 @@ 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];
@ -228,9 +220,8 @@ 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();
} }
@ -250,11 +241,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_root); _update_number_matches(tree_reference->get_root());
} }
void TreeSearch::_update_number_matches(TreeItem *item) { void TreeSearch::_update_number_matches(TreeItem *item) {
@ -277,7 +268,7 @@ void TreeSearch::_update_number_matches(TreeItem *item) {
} }
String TreeSearch::_get_search_mask() const { String TreeSearch::_get_search_mask() const {
ERR_FAIL_COND_V(!search_panel, ""); ERR_FAIL_COND(!search_panel);
return search_panel->get_text(); return search_panel->get_text();
} }
@ -285,12 +276,10 @@ 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);
@ -347,10 +336,8 @@ 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
@ -485,18 +472,12 @@ 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();
} }