Refactor tree filtering logic for correctness and efficiency
This commit is contained in:
parent
4f7996b1ea
commit
540bb585a8
|
@ -25,6 +25,7 @@
|
||||||
#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"
|
||||||
|
#include "core/templates/hash_set.h"
|
||||||
#endif // LIMBOAI_MODULE
|
#endif // LIMBOAI_MODULE
|
||||||
|
|
||||||
#ifdef LIMBOAI_GDEXTENSION
|
#ifdef LIMBOAI_GDEXTENSION
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
#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>
|
||||||
|
#include <godot_cpp/templates/hash_set.hpp>
|
||||||
|
|
||||||
#endif // LIMBOAI_GDEXTENSION
|
#endif // LIMBOAI_GDEXTENSION
|
||||||
|
|
||||||
|
@ -55,51 +57,60 @@ void TreeSearch::_clean_callable_cache() {
|
||||||
callable_cache = new_callable_cache;
|
callable_cache = new_callable_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes all tree items invisible that don't match the following criteria:
|
||||||
|
// 1. is parent of matching tree_item
|
||||||
|
// 2. is matching tree_item
|
||||||
|
// 3. is any descendent of matching tree item
|
||||||
void TreeSearch::_filter_tree(const String &p_search_mask) {
|
void TreeSearch::_filter_tree(const String &p_search_mask) {
|
||||||
|
ERR_FAIL_COND(!tree_reference);
|
||||||
|
|
||||||
|
// We don't filter if no search_mask is given.
|
||||||
if (matching_entries.is_empty()) {
|
if (matching_entries.is_empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<bool> item_visibilities;
|
HashSet<TreeItem *> visible_items;
|
||||||
item_visibilities.resize(ordered_tree_items.size());
|
visible_items.reserve(ordered_tree_items.size());
|
||||||
item_visibilities.fill(false);
|
|
||||||
|
|
||||||
// Make all entries visible that have any matching descendents. O(n)
|
Vector<TreeItem *> items = { tree_reference->get_root() };
|
||||||
for (int i = 0; i < ordered_tree_items.size(); i++) {
|
|
||||||
TreeItem *entry = ordered_tree_items[i];
|
for (int idx = 0; idx < items.size(); idx++) {
|
||||||
if (number_matches.has(entry) && number_matches[entry] > 0) {
|
TreeItem *cur_item = items[idx];
|
||||||
item_visibilities.set(i, true);
|
if (_vector_has_bsearch(matching_entries, cur_item)) {
|
||||||
|
visible_items.insert(cur_item);
|
||||||
|
TreeItem *parent_of_match = cur_item->get_parent();
|
||||||
|
|
||||||
|
// 1. mark all parents visible
|
||||||
|
while (parent_of_match) {
|
||||||
|
visible_items.insert(parent_of_match);
|
||||||
|
parent_of_match = parent_of_match->get_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for 2. and 3. we collect all children of match.
|
||||||
|
Vector<TreeItem *> matching_entries_descendents = { cur_item };
|
||||||
|
|
||||||
|
// 2. and 3. mark all descendents visible
|
||||||
|
for (int i = 0; i < matching_entries_descendents.size(); i++) {
|
||||||
|
TreeItem *cur_descendent_item = matching_entries_descendents[i];
|
||||||
|
visible_items.insert(cur_descendent_item);
|
||||||
|
|
||||||
|
// 3. collect all children of descendent
|
||||||
|
for (int i = 0; i < cur_descendent_item->get_child_count(); i++) {
|
||||||
|
matching_entries_descendents.push_back(cur_descendent_item->get_child(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // not a matching entry: process children
|
||||||
|
for (int i = 0; i < cur_item->get_child_count(); i++) {
|
||||||
|
items.push_back(cur_item->get_child(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make all descendents of matching entries visible. O(n) * log(|matching_entries|)
|
|
||||||
for (int i = 0; i < ordered_tree_items.size(); i++) {
|
for (int i = 0; i < ordered_tree_items.size(); i++) {
|
||||||
TreeItem *entry = ordered_tree_items[i];
|
TreeItem *cur_item = ordered_tree_items[i];
|
||||||
if (_vector_has_bsearch(matching_entries, entry)) {
|
if (!visible_items.has(cur_item)) {
|
||||||
// the [next_entry] at the same depth or depth above.
|
cur_item->set_visible(false);
|
||||||
TreeItem *next_entry = entry->get_next();
|
|
||||||
|
|
||||||
// search above current depth if no [next_entry].
|
|
||||||
while (!next_entry && entry) {
|
|
||||||
entry = entry->get_parent();
|
|
||||||
}
|
|
||||||
if (entry) {
|
|
||||||
next_entry = entry->get_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark visible all successors upto next entry at the same depth or above
|
|
||||||
int j = i;
|
|
||||||
for (; j < ordered_tree_items.size() && ordered_tree_items[j] != next_entry; j++) {
|
|
||||||
item_visibilities.set(j, true);
|
|
||||||
}
|
|
||||||
i = j - 1; // every entry is only processed once.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply visibility. O(n)
|
|
||||||
for (int i = 0; i < ordered_tree_items.size(); i++) {
|
|
||||||
if (!item_visibilities[i]) {
|
|
||||||
ordered_tree_items[i]->set_visible(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +181,7 @@ void TreeSearch::_draw_highlight_item(TreeItem *p_tree_item, const Rect2 p_rect,
|
||||||
if (!p_tree_item) {
|
if (!p_tree_item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call any parent draw methods such as for probability FIRST.
|
// call any parent draw methods such as for probability FIRST.
|
||||||
p_parent_draw_method.call(p_tree_item, p_rect);
|
p_parent_draw_method.call(p_tree_item, p_rect);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue