Skip to content

Commit 2920a87

Browse files
Cache TreeItems between runs in EditorHelpSearch
1 parent 107f296 commit 2920a87

File tree

2 files changed

+122
-42
lines changed

2 files changed

+122
-42
lines changed

editor/editor_help_search.cpp

+107-41
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void EditorHelpSearch::_update_results() {
4848
search_flags |= SEARCH_SHOW_HIERARCHY;
4949
}
5050

51-
search = Ref<Runner>(memnew(Runner(results_tree, results_tree, term, search_flags)));
51+
search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags)));
5252
set_process(true);
5353
}
5454

@@ -96,6 +96,7 @@ void EditorHelpSearch::_notification(int p_what) {
9696
switch (p_what) {
9797
case NOTIFICATION_VISIBILITY_CHANGED: {
9898
if (!is_visible()) {
99+
tree_cache.clear();
99100
callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation.
100101
get_ok_button()->set_disabled(true);
101102
EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size()));
@@ -258,6 +259,13 @@ EditorHelpSearch::EditorHelpSearch() {
258259
vbox->add_child(results_tree, true);
259260
}
260261

262+
void EditorHelpSearch::TreeCache::clear() {
263+
for (const KeyValue<String, TreeItem *> &E : item_cache) {
264+
memdelete(E.value);
265+
}
266+
item_cache.clear();
267+
}
268+
261269
bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile(const StringName &p_class) {
262270
Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
263271
if (profile.is_null()) {
@@ -436,11 +444,42 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
436444
return iterator_stack.is_empty();
437445
}
438446

447+
void EditorHelpSearch::Runner::_populate_cache() {
448+
root_item = results_tree->get_root();
449+
450+
if (root_item) {
451+
LocalVector<TreeItem *> stack;
452+
453+
// Add children of root item to stack.
454+
for (TreeItem *child = root_item->get_first_child(); child; child = child->get_next()) {
455+
stack.push_back(child);
456+
}
457+
458+
// Traverse stack and cache items.
459+
while (!stack.is_empty()) {
460+
TreeItem *cur_item = stack[stack.size() - 1];
461+
stack.resize(stack.size() - 1);
462+
463+
// Add to the cache.
464+
tree_cache->item_cache.insert(cur_item->get_metadata(0).operator String(), cur_item);
465+
466+
// Add any children to the stack.
467+
for (TreeItem *child = cur_item->get_first_child(); child; child = child->get_next()) {
468+
stack.push_back(child);
469+
}
470+
471+
// Remove from parent.
472+
cur_item->get_parent()->remove_child(cur_item);
473+
}
474+
} else {
475+
root_item = results_tree->create_item();
476+
}
477+
}
478+
439479
bool EditorHelpSearch::Runner::_phase_class_items_init() {
440480
iterator_match = matches.begin();
441481

442-
results_tree->clear();
443-
root_item = results_tree->create_item();
482+
_populate_cache();
444483
class_items.clear();
445484

446485
return true;
@@ -618,27 +657,54 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_
618657
return class_item;
619658
}
620659

660+
bool EditorHelpSearch::Runner::_find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item) {
661+
// Attempt to find in cache.
662+
if (tree_cache->item_cache.has(p_item_meta)) {
663+
r_item = tree_cache->item_cache[p_item_meta];
664+
665+
// Remove from cache.
666+
tree_cache->item_cache.erase(p_item_meta);
667+
668+
// Add to tree.
669+
p_parent->add_child(r_item);
670+
671+
return false;
672+
} else {
673+
// Otherwise create item.
674+
r_item = results_tree->create_item(p_parent);
675+
676+
return true;
677+
}
678+
}
679+
621680
TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) {
622681
String tooltip = DTR(p_doc->brief_description.strip_edges());
623682

624-
TreeItem *item = results_tree->create_item(p_parent);
625-
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name));
626-
item->set_text(0, p_doc->name);
627-
item->set_text(1, TTR("Class"));
628-
item->set_tooltip_text(0, tooltip);
629-
item->set_tooltip_text(1, tooltip);
630-
item->set_metadata(0, "class_name:" + p_doc->name);
683+
const String item_meta = "class_name:" + p_doc->name;
684+
685+
TreeItem *item = nullptr;
686+
if (_find_or_create_item(p_parent, item_meta, item)) {
687+
item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name));
688+
item->set_text(0, p_doc->name);
689+
item->set_text(1, TTR("Class"));
690+
item->set_tooltip_text(0, tooltip);
691+
item->set_tooltip_text(1, tooltip);
692+
item->set_metadata(0, item_meta);
693+
if (p_doc->is_deprecated) {
694+
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError"));
695+
item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated."));
696+
} else if (p_doc->is_experimental) {
697+
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning"));
698+
item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental."));
699+
}
700+
}
701+
631702
if (p_gray) {
632703
item->set_custom_color(0, disabled_color);
633704
item->set_custom_color(1, disabled_color);
634-
}
635-
636-
if (p_doc->is_deprecated) {
637-
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError");
638-
item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated."));
639-
} else if (p_doc->is_experimental) {
640-
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning");
641-
item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental."));
705+
} else {
706+
item->clear_custom_color(0);
707+
item->clear_custom_color(1);
642708
}
643709

644710
_match_item(item, p_doc->name);
@@ -679,30 +745,29 @@ TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_pare
679745
}
680746

681747
TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, bool is_deprecated, bool is_experimental) {
682-
Ref<Texture2D> icon;
683-
String text;
684-
if (search_flags & SEARCH_SHOW_HIERARCHY) {
685-
icon = ui_service->get_editor_theme_icon(p_icon);
686-
text = p_text;
687-
} else {
688-
icon = ui_service->get_editor_theme_icon(p_icon);
689-
text = p_class_name + "." + p_text;
748+
const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name;
749+
750+
TreeItem *item = nullptr;
751+
if (_find_or_create_item(p_parent, item_meta, item)) {
752+
item->set_icon(0, ui_service->get_editor_theme_icon(p_icon));
753+
item->set_text(1, TTRGET(p_type));
754+
item->set_tooltip_text(0, p_tooltip);
755+
item->set_tooltip_text(1, p_tooltip);
756+
item->set_metadata(0, item_meta);
757+
758+
if (is_deprecated) {
759+
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError"));
760+
item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated."));
761+
} else if (is_experimental) {
762+
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning"));
763+
item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental."));
764+
}
690765
}
691766

692-
TreeItem *item = results_tree->create_item(p_parent);
693-
item->set_icon(0, icon);
694-
item->set_text(0, text);
695-
item->set_text(1, TTRGET(p_type));
696-
item->set_tooltip_text(0, p_tooltip);
697-
item->set_tooltip_text(1, p_tooltip);
698-
item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name);
699-
700-
if (is_deprecated) {
701-
Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError");
702-
item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated."));
703-
} else if (is_experimental) {
704-
Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning");
705-
item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental."));
767+
if (search_flags & SEARCH_SHOW_HIERARCHY) {
768+
item->set_text(0, p_text);
769+
} else {
770+
item->set_text(0, p_class_name + "." + p_text);
706771
}
707772

708773
_match_item(item, p_name);
@@ -721,9 +786,10 @@ bool EditorHelpSearch::Runner::work(uint64_t slot) {
721786
return true;
722787
}
723788

724-
EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags) :
789+
EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags) :
725790
ui_service(p_icon_service),
726791
results_tree(p_results_tree),
792+
tree_cache(p_tree_cache),
727793
term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()),
728794
search_flags(p_search_flags),
729795
disabled_color(ui_service->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))) {

editor/editor_help_search.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ class EditorHelpSearch : public ConfirmationDialog {
6767
class Runner;
6868
Ref<Runner> search;
6969

70+
struct TreeCache {
71+
HashMap<String, TreeItem *> item_cache;
72+
73+
void clear();
74+
75+
~TreeCache() {
76+
clear();
77+
}
78+
} tree_cache;
79+
7080
void _update_results();
7181

7282
void _search_box_gui_input(const Ref<InputEvent> &p_event);
@@ -117,6 +127,7 @@ class EditorHelpSearch::Runner : public RefCounted {
117127

118128
Control *ui_service = nullptr;
119129
Tree *results_tree = nullptr;
130+
TreeCache *tree_cache = nullptr;
120131
String term;
121132
Vector<String> terms;
122133
int search_flags;
@@ -134,6 +145,9 @@ class EditorHelpSearch::Runner : public RefCounted {
134145

135146
bool _is_class_disabled_by_feature_profile(const StringName &p_class);
136147

148+
void _populate_cache();
149+
bool _find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item);
150+
137151
bool _slice();
138152
bool _phase_match_classes_init();
139153
bool _phase_match_classes();
@@ -162,7 +176,7 @@ class EditorHelpSearch::Runner : public RefCounted {
162176
public:
163177
bool work(uint64_t slot = 100000);
164178

165-
Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags);
179+
Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags);
166180
};
167181

168182
#endif // EDITOR_HELP_SEARCH_H

0 commit comments

Comments
 (0)