@@ -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+
261269bool 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+
439479bool 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+
621680TreeItem *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
681747TreeItem *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))) {
0 commit comments