Compare commits

..

2 Commits

Author SHA1 Message Date
monxa 72b588af8f
Merge 5ebb36077a into 760af804c0 2024-10-04 14:56:06 +00:00
Alexander Montag 5ebb36077a
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.
- 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-04 16:55:53 +02:00
2 changed files with 27 additions and 13 deletions

View File

@ -21,7 +21,6 @@
#include "core/math/math_funcs.h" #include "core/math/math_funcs.h"
#include "editor/editor_interface.h" #include "editor/editor_interface.h"
#include "editor/themes/editor_scale.h" #include "editor/themes/editor_scale.h"
#include "scene/gui/separator.h"
#include "scene/main/viewport.h" #include "scene/main/viewport.h"
#include "scene/resources/font.h" #include "scene/resources/font.h"
#include "scene/resources/style_box_flat.h" #include "scene/resources/style_box_flat.h"
@ -30,7 +29,6 @@
#ifdef LIMBOAI_GDEXTENSION #ifdef LIMBOAI_GDEXTENSION
#include <godot_cpp/classes/editor_interface.hpp> // for edge scale #include <godot_cpp/classes/editor_interface.hpp> // for edge scale
#include <godot_cpp/classes/font.hpp> #include <godot_cpp/classes/font.hpp>
#include <godot_cpp/classes/h_separator.hpp>
#include <godot_cpp/classes/style_box_flat.hpp> #include <godot_cpp/classes/style_box_flat.hpp>
#include <godot_cpp/classes/viewport.hpp> #include <godot_cpp/classes/viewport.hpp>
#include <godot_cpp/core/math.hpp> #include <godot_cpp/core/math.hpp>
@ -65,7 +63,7 @@ void TreeSearch::_filter_tree() {
} }
void TreeSearch::_filter_tree(TreeItem *p_item, bool p_parent_matching) { void TreeSearch::_filter_tree(TreeItem *p_item, bool p_parent_matching) {
bool visible = number_matches.has(p_item) | p_parent_matching; bool visible = (number_matches.has(p_item) && (number_matches.get(p_item) > 0)) || p_parent_matching;
p_item->set_visible(visible); p_item->set_visible(visible);
@ -118,13 +116,13 @@ void TreeSearch::_highlight_tree_item(TreeItem *p_tree_item) {
} }
Callable draw_callback = callable_mp(this, &TreeSearch::_draw_highlight_item).bind(parent_draw_method); Callable draw_callback = callable_mp(this, &TreeSearch::_draw_highlight_item).bind(parent_draw_method);
callable_cache[p_tree_item] = draw_callback;
// This is necessary because of the modularity of this implementation. // This is necessary because of the modularity of this implementation.
// Cache render properties of entry. // Cache render properties of entry.
String cached_text = p_tree_item->get_text(0); String cached_text = p_tree_item->get_text(0);
Ref<Texture2D> cached_icon = p_tree_item->get_icon(0); Ref<Texture2D> cached_icon = p_tree_item->get_icon(0);
int cached_max_width = p_tree_item->get_icon_max_width(0); int cached_max_width = p_tree_item->get_icon_max_width(0);
callable_cache[p_tree_item] = draw_callback;
// This removes render properties in entry. // This removes render properties in entry.
p_tree_item->set_custom_draw_callback(0, draw_callback); p_tree_item->set_custom_draw_callback(0, draw_callback);
@ -136,7 +134,7 @@ void TreeSearch::_highlight_tree_item(TreeItem *p_tree_item) {
p_tree_item->set_icon_max_width(0, cached_max_width); p_tree_item->set_icon_max_width(0, cached_max_width);
} }
// Custom draw callback for highlighting (bind the parent_drw_method to this) // Custom draw callback for highlighting (bind the parent_draw_method to this)
void TreeSearch::_draw_highlight_item(TreeItem *p_tree_item, const Rect2 p_rect, const Callable p_parent_draw_method) { void TreeSearch::_draw_highlight_item(TreeItem *p_tree_item, const Rect2 p_rect, const Callable p_parent_draw_method) {
if (!p_tree_item) { if (!p_tree_item) {
return; return;
@ -239,15 +237,30 @@ void TreeSearch::_update_ordered_tree_items(TreeItem *p_tree_item) {
} }
void TreeSearch::_update_number_matches() { void TreeSearch::_update_number_matches() {
ERR_FAIL_COND(!tree_reference);
number_matches.clear(); number_matches.clear();
for (int i = 0; i < matching_entries.size(); i++) { number_matches.reserve(ordered_tree_items.size());
TreeItem *item = matching_entries[i];
while (item) { _update_number_matches(tree_reference->get_root());
int previous_match_cnt = number_matches.has(item) ? number_matches.get(item) : 0; }
number_matches[item] = previous_match_cnt + 1;
item = item->get_parent(); void TreeSearch::_update_number_matches(TreeItem *item) {
} for (int i = 0; i < item->get_child_count(); i++) {
TreeItem *child = item->get_child(i);
_update_number_matches(child);
} }
int count = _vector_has_bsearch(matching_entries, item) ? 1 : 0;
for (int i = 0; i < item->get_child_count(); i++) {
TreeItem *child = item->get_child(i);
count += number_matches.has(child) ? number_matches.get(child) : 0;
}
if (count == 0) {
return;
}
number_matches[item] = count;
} }
String TreeSearch::_get_search_mask() const { String TreeSearch::_get_search_mask() const {

View File

@ -76,12 +76,13 @@ private:
void _highlight_tree(); void _highlight_tree();
void _highlight_tree_item(TreeItem *p_tree_item); void _highlight_tree_item(TreeItem *p_tree_item);
// custom draw-Callback (bind inherited Callable). // Custom draw-Callback (bind inherited Callable).
void _draw_highlight_item(TreeItem *p_tree_item, const Rect2 p_rect, const Callable p_parent_draw_method); void _draw_highlight_item(TreeItem *p_tree_item, const Rect2 p_rect, const Callable p_parent_draw_method);
void _update_matching_entries(const String &p_search_mask); void _update_matching_entries(const String &p_search_mask);
void _update_ordered_tree_items(TreeItem *p_tree_item); void _update_ordered_tree_items(TreeItem *p_tree_item);
void _update_number_matches(); void _update_number_matches();
void _update_number_matches(TreeItem *item);
void _find_matching_entries(TreeItem *p_tree_item, const String &p_search_mask, Vector<TreeItem *> &p_accum) const; void _find_matching_entries(TreeItem *p_tree_item, const String &p_search_mask, Vector<TreeItem *> &p_accum) const;
String _get_search_mask() const; String _get_search_mask() const;