diff options
Diffstat (limited to 'editor/editor_help_search.cpp')
-rw-r--r-- | editor/editor_help_search.cpp | 243 |
1 files changed, 170 insertions, 73 deletions
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 64bd209d4d..104b0a73c4 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -33,9 +33,9 @@ #include "core/os/keyboard.h" #include "editor/editor_feature_profile.h" #include "editor/editor_node.h" -#include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_string_names.h" +#include "editor/themes/editor_scale.h" void EditorHelpSearch::_update_results() { String term = search_box->get_text(); @@ -48,7 +48,7 @@ void EditorHelpSearch::_update_results() { search_flags |= SEARCH_SHOW_HIERARCHY; } - search = Ref<Runner>(memnew(Runner(results_tree, results_tree, term, search_flags))); + search = Ref<Runner>(memnew(Runner(results_tree, results_tree, &tree_cache, term, search_flags))); set_process(true); } @@ -96,6 +96,7 @@ void EditorHelpSearch::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible()) { + tree_cache.clear(); callable_mp(results_tree, &Tree::clear).call_deferred(); // Wait for the Tree's mouse event propagation. get_ok_button()->set_disabled(true); EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "search_help", Rect2(get_position(), get_size())); @@ -258,6 +259,13 @@ EditorHelpSearch::EditorHelpSearch() { vbox->add_child(results_tree, true); } +void EditorHelpSearch::TreeCache::clear() { + for (const KeyValue<String, TreeItem *> &E : item_cache) { + memdelete(E.value); + } + item_cache.clear(); +} + bool EditorHelpSearch::Runner::_is_class_disabled_by_feature_profile(const StringName &p_class) { Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); if (profile.is_null()) { @@ -317,7 +325,13 @@ bool EditorHelpSearch::Runner::_slice() { } bool EditorHelpSearch::Runner::_phase_match_classes_init() { - iterator_doc = EditorHelp::get_doc_data()->class_list.begin(); + iterator_doc = nullptr; + iterator_stack.clear(); + if (search_flags & SEARCH_SHOW_HIERARCHY) { + iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[""].front()); + } else { + iterator_doc = EditorHelp::get_doc_data()->class_list.begin(); + } matches.clear(); matched_item = nullptr; match_highest_score = 0; @@ -331,88 +345,144 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() { } bool EditorHelpSearch::Runner::_phase_match_classes() { - if (!iterator_doc) { + if (!iterator_doc && iterator_stack.is_empty()) { return true; } - DocData::ClassDoc &class_doc = iterator_doc->value; - if (class_doc.name.is_empty()) { - ++iterator_doc; - return false; + DocData::ClassDoc *class_doc = nullptr; + if (iterator_doc) { + class_doc = &iterator_doc->value; + } else if (!iterator_stack.is_empty() && iterator_stack[iterator_stack.size() - 1]) { + class_doc = EditorHelp::get_doc_data()->class_list.getptr(iterator_stack[iterator_stack.size() - 1]->get()); + } + + if (class_doc && class_doc->name.is_empty()) { + class_doc = nullptr; } - if (!_is_class_disabled_by_feature_profile(class_doc.name)) { + if (class_doc && !_is_class_disabled_by_feature_profile(class_doc->name)) { ClassMatch match; - match.doc = &class_doc; + match.doc = class_doc; // Match class name. if (search_flags & SEARCH_CLASSES) { // If the search term is empty, add any classes which are not script docs or which don't start with // a double-quotation. This will ensure that only C++ classes and explicitly named classes will // be added. - match.name = (term.is_empty() && (!class_doc.is_script_doc || class_doc.name[0] != '\"')) || _match_string(term, class_doc.name); + match.name = (term.is_empty() && (!class_doc->is_script_doc || class_doc->name[0] != '\"')) || _match_string(term, class_doc->name); } // Match members only if the term is long enough, to avoid slow performance from building a large tree. // Make an exception for annotations, since there are not that many of them. if (term.length() > 1 || term == "@") { if (search_flags & SEARCH_CONSTRUCTORS) { - _match_method_name_and_push_back(class_doc.constructors, &match.constructors); + _match_method_name_and_push_back(class_doc->constructors, &match.constructors); } if (search_flags & SEARCH_METHODS) { - _match_method_name_and_push_back(class_doc.methods, &match.methods); + _match_method_name_and_push_back(class_doc->methods, &match.methods); } if (search_flags & SEARCH_OPERATORS) { - _match_method_name_and_push_back(class_doc.operators, &match.operators); + _match_method_name_and_push_back(class_doc->operators, &match.operators); } if (search_flags & SEARCH_SIGNALS) { - for (int i = 0; i < class_doc.signals.size(); i++) { - if (_all_terms_in_name(class_doc.signals[i].name)) { - match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i])); + for (int i = 0; i < class_doc->signals.size(); i++) { + if (_all_terms_in_name(class_doc->signals[i].name)) { + match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc->signals[i])); } } } if (search_flags & SEARCH_CONSTANTS) { - for (int i = 0; i < class_doc.constants.size(); i++) { - if (_all_terms_in_name(class_doc.constants[i].name)) { - match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i])); + for (int i = 0; i < class_doc->constants.size(); i++) { + if (_all_terms_in_name(class_doc->constants[i].name)) { + match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc->constants[i])); } } } if (search_flags & SEARCH_PROPERTIES) { - for (int i = 0; i < class_doc.properties.size(); i++) { - if (_all_terms_in_name(class_doc.properties[i].name)) { - match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i])); + for (int i = 0; i < class_doc->properties.size(); i++) { + if (_all_terms_in_name(class_doc->properties[i].name)) { + match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc->properties[i])); } } } if (search_flags & SEARCH_THEME_ITEMS) { - for (int i = 0; i < class_doc.theme_properties.size(); i++) { - if (_all_terms_in_name(class_doc.theme_properties[i].name)) { - match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i])); + for (int i = 0; i < class_doc->theme_properties.size(); i++) { + if (_all_terms_in_name(class_doc->theme_properties[i].name)) { + match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc->theme_properties[i])); } } } if (search_flags & SEARCH_ANNOTATIONS) { - for (int i = 0; i < class_doc.annotations.size(); i++) { - if (_match_string(term, class_doc.annotations[i].name)) { - match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc.annotations[i])); + for (int i = 0; i < class_doc->annotations.size(); i++) { + if (_match_string(term, class_doc->annotations[i].name)) { + match.annotations.push_back(const_cast<DocData::MethodDoc *>(&class_doc->annotations[i])); } } } } - matches[class_doc.name] = match; + matches[class_doc->name] = match; + } + + if (iterator_doc) { + ++iterator_doc; + return !iterator_doc; + } + + if (!iterator_stack.is_empty()) { + if (iterator_stack[iterator_stack.size() - 1]) { + iterator_stack[iterator_stack.size() - 1] = iterator_stack[iterator_stack.size() - 1]->next(); + } + if (!iterator_stack[iterator_stack.size() - 1]) { + iterator_stack.resize(iterator_stack.size() - 1); + } } - ++iterator_doc; - return !iterator_doc; + if (class_doc && EditorHelp::get_doc_data()->inheriting.has(class_doc->name)) { + iterator_stack.push_back(EditorHelp::get_doc_data()->inheriting[class_doc->name].front()); + } + + return iterator_stack.is_empty(); +} + +void EditorHelpSearch::Runner::_populate_cache() { + // Deselect to prevent re-selection issues. + results_tree->deselect_all(); + + root_item = results_tree->get_root(); + + if (root_item) { + LocalVector<TreeItem *> stack; + + // Add children of root item to stack. + for (TreeItem *child = root_item->get_first_child(); child; child = child->get_next()) { + stack.push_back(child); + } + + // Traverse stack and cache items. + while (!stack.is_empty()) { + TreeItem *cur_item = stack[stack.size() - 1]; + stack.resize(stack.size() - 1); + + // Add to the cache. + tree_cache->item_cache.insert(cur_item->get_metadata(0).operator String(), cur_item); + + // Add any children to the stack. + for (TreeItem *child = cur_item->get_first_child(); child; child = child->get_next()) { + stack.push_back(child); + } + + // Remove from parent. + cur_item->get_parent()->remove_child(cur_item); + } + } else { + root_item = results_tree->create_item(); + } } bool EditorHelpSearch::Runner::_phase_class_items_init() { iterator_match = matches.begin(); - results_tree->clear(); - root_item = results_tree->create_item(); + _populate_cache(); class_items.clear(); return true; @@ -590,27 +660,54 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_ return class_item; } +bool EditorHelpSearch::Runner::_find_or_create_item(TreeItem *p_parent, const String &p_item_meta, TreeItem *&r_item) { + // Attempt to find in cache. + if (tree_cache->item_cache.has(p_item_meta)) { + r_item = tree_cache->item_cache[p_item_meta]; + + // Remove from cache. + tree_cache->item_cache.erase(p_item_meta); + + // Add to tree. + p_parent->add_child(r_item); + + return false; + } else { + // Otherwise create item. + r_item = results_tree->create_item(p_parent); + + return true; + } +} + TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) { String tooltip = DTR(p_doc->brief_description.strip_edges()); - TreeItem *item = results_tree->create_item(p_parent); - item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name)); - item->set_text(0, p_doc->name); - item->set_text(1, TTR("Class")); - item->set_tooltip_text(0, tooltip); - item->set_tooltip_text(1, tooltip); - item->set_metadata(0, "class_name:" + p_doc->name); + const String item_meta = "class_name:" + p_doc->name; + + TreeItem *item = nullptr; + if (_find_or_create_item(p_parent, item_meta, item)) { + item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_doc->name)); + item->set_text(0, p_doc->name); + item->set_text(1, TTR("Class")); + item->set_tooltip_text(0, tooltip); + item->set_tooltip_text(1, tooltip); + item->set_metadata(0, item_meta); + if (p_doc->is_deprecated) { + Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError")); + item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated.")); + } else if (p_doc->is_experimental) { + Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning")); + item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental.")); + } + } + if (p_gray) { item->set_custom_color(0, disabled_color); item->set_custom_color(1, disabled_color); - } - - if (p_doc->is_deprecated) { - Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError"); - item->add_button(0, error_icon, 0, false, TTR("This class is marked as deprecated.")); - } else if (p_doc->is_experimental) { - Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning"); - item->add_button(0, warning_icon, 0, false, TTR("This class is marked as experimental.")); + } else { + item->clear_custom_color(0); + item->clear_custom_color(1); } _match_item(item, p_doc->name); @@ -651,30 +748,29 @@ TreeItem *EditorHelpSearch::Runner::_create_theme_property_item(TreeItem *p_pare } 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) { - Ref<Texture2D> icon; - String text; - if (search_flags & SEARCH_SHOW_HIERARCHY) { - icon = ui_service->get_editor_theme_icon(p_icon); - text = p_text; - } else { - icon = ui_service->get_editor_theme_icon(p_icon); - text = p_class_name + "." + p_text; + const String item_meta = "class_" + p_metatype + ":" + p_class_name + ":" + p_name; + + TreeItem *item = nullptr; + if (_find_or_create_item(p_parent, item_meta, item)) { + item->set_icon(0, ui_service->get_editor_theme_icon(p_icon)); + item->set_text(1, TTRGET(p_type)); + item->set_tooltip_text(0, p_tooltip); + item->set_tooltip_text(1, p_tooltip); + item->set_metadata(0, item_meta); + + if (is_deprecated) { + Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon(SNAME("StatusError")); + item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated.")); + } else if (is_experimental) { + Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon(SNAME("NodeWarning")); + item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental.")); + } } - TreeItem *item = results_tree->create_item(p_parent); - item->set_icon(0, icon); - item->set_text(0, text); - item->set_text(1, TTRGET(p_type)); - item->set_tooltip_text(0, p_tooltip); - item->set_tooltip_text(1, p_tooltip); - item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name); - - if (is_deprecated) { - Ref<Texture2D> error_icon = ui_service->get_editor_theme_icon("StatusError"); - item->add_button(0, error_icon, 0, false, TTR("This member is marked as deprecated.")); - } else if (is_experimental) { - Ref<Texture2D> warning_icon = ui_service->get_editor_theme_icon("NodeWarning"); - item->add_button(0, warning_icon, 0, false, TTR("This member is marked as experimental.")); + if (search_flags & SEARCH_SHOW_HIERARCHY) { + item->set_text(0, p_text); + } else { + item->set_text(0, p_class_name + "." + p_text); } _match_item(item, p_name); @@ -693,10 +789,11 @@ bool EditorHelpSearch::Runner::work(uint64_t slot) { return true; } -EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, const String &p_term, int p_search_flags) : +EditorHelpSearch::Runner::Runner(Control *p_icon_service, Tree *p_results_tree, TreeCache *p_tree_cache, const String &p_term, int p_search_flags) : ui_service(p_icon_service), results_tree(p_results_tree), + tree_cache(p_tree_cache), term((p_search_flags & SEARCH_CASE_SENSITIVE) == 0 ? p_term.strip_edges().to_lower() : p_term.strip_edges()), search_flags(p_search_flags), - disabled_color(ui_service->get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor))) { + disabled_color(ui_service->get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor))) { } |