@@ -48,7 +48,7 @@ void EditorHelpSearch::_update_results() {
48
48
search_flags |= SEARCH_SHOW_HIERARCHY;
49
49
}
50
50
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)));
52
52
set_process (true );
53
53
}
54
54
@@ -96,6 +96,7 @@ void EditorHelpSearch::_notification(int p_what) {
96
96
switch (p_what) {
97
97
case NOTIFICATION_VISIBILITY_CHANGED: {
98
98
if (!is_visible ()) {
99
+ tree_cache.clear ();
99
100
callable_mp (results_tree, &Tree::clear).call_deferred (); // Wait for the Tree's mouse event propagation.
100
101
get_ok_button ()->set_disabled (true );
101
102
EditorSettings::get_singleton ()->set_project_metadata (" dialog_bounds" , " search_help" , Rect2 (get_position (), get_size ()));
@@ -258,6 +259,13 @@ EditorHelpSearch::EditorHelpSearch() {
258
259
vbox->add_child (results_tree, true );
259
260
}
260
261
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
+
261
269
bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile (const StringName &p_class) {
262
270
Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton ()->get_current_profile ();
263
271
if (profile.is_null ()) {
@@ -436,11 +444,42 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
436
444
return iterator_stack.is_empty ();
437
445
}
438
446
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
+
439
479
bool EditorHelpSearch::Runner::_phase_class_items_init () {
440
480
iterator_match = matches.begin ();
441
481
442
- results_tree->clear ();
443
- root_item = results_tree->create_item ();
482
+ _populate_cache ();
444
483
class_items.clear ();
445
484
446
485
return true ;
@@ -618,27 +657,54 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_
618
657
return class_item;
619
658
}
620
659
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
+
621
680
TreeItem *EditorHelpSearch::Runner::_create_class_item (TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) {
622
681
String tooltip = DTR (p_doc->brief_description .strip_edges ());
623
682
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
+
631
702
if (p_gray) {
632
703
item->set_custom_color (0 , disabled_color);
633
704
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 );
642
708
}
643
709
644
710
_match_item (item, p_doc->name );
@@ -679,30 +745,29 @@ TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_pare
679
745
}
680
746
681
747
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
+ }
690
765
}
691
766
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);
706
771
}
707
772
708
773
_match_item (item, p_name);
@@ -721,9 +786,10 @@ bool EditorHelpSearch::Runner::work(uint64_t slot) {
721
786
return true ;
722
787
}
723
788
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) :
725
790
ui_service(p_icon_service),
726
791
results_tree(p_results_tree),
792
+ tree_cache(p_tree_cache),
727
793
term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()),
728
794
search_flags(p_search_flags),
729
795
disabled_color(ui_service->get_theme_color (SNAME(" font_disabled_color" ), EditorStringName(Editor))) {
0 commit comments