Skip to content

Commit

Permalink
Optimize enumeration of global classes in create dialog and autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
RandomShaper committed Jan 13, 2025
1 parent 9b43474 commit 1ee1eb2
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 95 deletions.
2 changes: 1 addition & 1 deletion editor/connections_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,7 @@ void ConnectionsDock::update_tree() {
doc_class_name = String();
}

class_icon = editor_data.get_script_icon(script_base);
class_icon = editor_data.get_script_icon(script_base->get_path());
if (class_icon.is_null() && has_theme_icon(native_base, EditorStringName(EditorIcons))) {
class_icon = get_editor_theme_icon(native_base);
}
Expand Down
15 changes: 7 additions & 8 deletions editor/create_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,9 @@ void CreateDialog::_add_type(const StringName &p_type, TypeCategory p_type_categ
inherits = ClassDB::get_parent_class(p_type);
inherited_type = TypeCategory::CPP_TYPE;
} else {
if (p_type_category == TypeCategory::PATH_TYPE || ScriptServer::is_global_class(p_type)) {
Ref<Script> scr;
if (p_type_category == TypeCategory::PATH_TYPE) {
ERR_FAIL_COND(!ResourceLoader::exists(p_type, "Script"));
scr = ResourceLoader::load(p_type, "Script");
} else {
scr = EditorNode::get_editor_data().script_class_load_script(p_type);
}
if (p_type_category == TypeCategory::PATH_TYPE) {
ERR_FAIL_COND(!ResourceLoader::exists(p_type, "Script"));
Ref<Script> scr = ResourceLoader::load(p_type, "Script");
ERR_FAIL_COND(scr.is_null());

Ref<Script> base = scr->get_base_script();
Expand All @@ -260,6 +255,10 @@ void CreateDialog::_add_type(const StringName &p_type, TypeCategory p_type_categ
inherited_type = TypeCategory::PATH_TYPE;
}
}
} else if (ScriptServer::is_global_class(p_type)) {
inherits = ScriptServer::get_global_class_base(p_type);
bool is_native_class = ClassDB::class_exists(inherits);
inherited_type = is_native_class ? TypeCategory::CPP_TYPE : TypeCategory::OTHER_TYPE;
} else {
inherits = custom_type_parents[p_type];
if (ClassDB::class_exists(inherits)) {
Expand Down
81 changes: 12 additions & 69 deletions editor/editor_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -984,20 +984,6 @@ bool EditorData::script_class_is_parent(const String &p_class, const String &p_i
return true;
}

StringName EditorData::script_class_get_base(const String &p_class) const {
Ref<Script> script = script_class_load_script(p_class);
if (script.is_null()) {
return StringName();
}

Ref<Script> base_script = script->get_base_script();
if (base_script.is_null()) {
return ScriptServer::get_global_class_base(p_class);
}

return script->get_language()->get_global_class_name(base_script->get_path());
}

Variant EditorData::script_class_instance(const String &p_class) {
if (ScriptServer::is_global_class(p_class)) {
Ref<Script> script = script_class_load_script(p_class);
Expand Down Expand Up @@ -1034,7 +1020,7 @@ String EditorData::script_class_get_icon_path(const String &p_class) const {
String current = p_class;
String ret = _script_class_icon_paths[current];
while (ret.is_empty()) {
current = script_class_get_base(current);
current = ScriptServer::get_global_class_base(p_class);
if (!ScriptServer::is_global_class(current)) {
return String();
}
Expand Down Expand Up @@ -1105,15 +1091,11 @@ void EditorData::script_class_load_icon_paths() {
}
}

Ref<Texture2D> EditorData::extension_class_get_icon(const String &p_class) const {
String EditorData::extension_class_get_icon_path(const String &p_class) const {
if (GDExtensionManager::get_singleton()->class_has_icon_path(p_class)) {
String icon_path = GDExtensionManager::get_singleton()->class_get_icon_path(p_class);
Ref<Texture2D> icon = _load_script_icon(icon_path);
if (icon.is_valid()) {
return icon;
}
return GDExtensionManager::get_singleton()->class_get_icon_path(p_class);
}
return nullptr;
return String();
}

Ref<Texture2D> EditorData::_load_script_icon(const String &p_path) const {
Expand All @@ -1126,58 +1108,19 @@ Ref<Texture2D> EditorData::_load_script_icon(const String &p_path) const {
return nullptr;
}

Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
Ref<Texture2D> EditorData::get_script_icon(const String &p_script_path) {
// Take from the local cache, if available.
if (_script_icon_cache.has(p_script)) {
if (_script_icon_cache.has(p_script_path)) {
// Can be an empty value if we can't resolve any icon for this script.
// An empty value is still cached to avoid unnecessary attempts at resolving it again.
return _script_icon_cache[p_script];
return _script_icon_cache[p_script_path];
}

Ref<Script> base_scr = p_script;
while (base_scr.is_valid()) {
// Check for scripted classes.
String icon_path;
StringName class_name = script_class_get_name(base_scr->get_path());
if (base_scr->is_built_in() || class_name == StringName()) {
icon_path = base_scr->get_class_icon_path();
} else {
icon_path = script_class_get_icon_path(class_name);
}

Ref<Texture2D> icon = _load_script_icon(icon_path);
if (icon.is_valid()) {
_script_icon_cache[p_script] = icon;
return icon;
}

// Check for legacy custom classes defined by plugins.
// TODO: Should probably be deprecated in 4.x
const EditorData::CustomType *ctype = get_custom_type_by_path(base_scr->get_path());
if (ctype && ctype->icon.is_valid()) {
_script_icon_cache[p_script] = ctype->icon;
return ctype->icon;
}

// Move to the base class.
base_scr = base_scr->get_base_script();
}

// No custom icon was found in the inheritance chain, so check the base
// class of the script instead.
String base_type;
p_script->get_language()->get_global_class_name(p_script->get_path(), &base_type);

// Check if the base type is an extension-defined type.
Ref<Texture2D> ext_icon = extension_class_get_icon(base_type);
if (ext_icon.is_valid()) {
_script_icon_cache[p_script] = ext_icon;
return ext_icon;
}

// If no icon found, cache it as null.
_script_icon_cache[p_script] = Ref<Texture>();
return nullptr;
StringName class_name = script_class_get_name(p_script_path);
String icon_path = script_class_get_icon_path(class_name);
Ref<Texture2D> icon = _load_script_icon(icon_path);
_script_icon_cache[p_script_path] = icon;
return icon;
}

void EditorData::clear_script_icon_cache() {
Expand Down
7 changes: 3 additions & 4 deletions editor/editor_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class EditorData {

HashMap<StringName, String> _script_class_icon_paths;
HashMap<String, StringName> _script_class_file_to_path;
HashMap<Ref<Script>, Ref<Texture>> _script_icon_cache;
HashMap<String, Ref<Texture>> _script_icon_cache;

Ref<Texture2D> _load_script_icon(const String &p_path) const;

Expand Down Expand Up @@ -240,7 +240,6 @@ class EditorData {
void notify_scene_saved(const String &p_path);

bool script_class_is_parent(const String &p_class, const String &p_inherits);
StringName script_class_get_base(const String &p_class) const;
Variant script_class_instance(const String &p_class);

Ref<Script> script_class_load_script(const String &p_class) const;
Expand All @@ -254,9 +253,9 @@ class EditorData {
void script_class_save_icon_paths();
void script_class_load_icon_paths();

Ref<Texture2D> extension_class_get_icon(const String &p_class) const;
String extension_class_get_icon_path(const String &p_class) const;

Ref<Texture2D> get_script_icon(const Ref<Script> &p_script);
Ref<Texture2D> get_script_icon(const String &p_script_path);
void clear_script_icon_cache();

EditorData();
Expand Down
28 changes: 16 additions & 12 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4823,22 +4823,21 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na
}
}

Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback, bool p_fallback_script_to_theme) {
Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, const String &p_script_path, const String &p_fallback, bool p_fallback_script_to_theme) {
ERR_FAIL_COND_V_MSG(p_class.is_empty(), nullptr, "Class name cannot be empty.");
EditorData &ed = EditorNode::get_editor_data();

// Check for a script icon first.
if (p_script.is_valid()) {
Ref<Texture2D> script_icon = ed.get_script_icon(p_script);
if (!p_script_path.is_empty()) {
Ref<Texture2D> script_icon = ed.get_script_icon(p_script_path);
if (script_icon.is_valid()) {
return script_icon;
}

if (p_fallback_script_to_theme) {
// Look for the native base type in the editor theme. This is relevant for
// scripts extending other scripts and for built-in classes.
String script_class_name = p_script->get_language()->get_global_class_name(p_script->get_path());
String base_type = ScriptServer::get_global_class_native_base(script_class_name);
String base_type = ScriptServer::get_global_class_native_base(p_class);
if (theme.is_valid() && theme->has_icon(base_type, EditorStringName(EditorIcons))) {
return theme->get_icon(base_type, EditorStringName(EditorIcons));
}
Expand All @@ -4849,9 +4848,14 @@ Ref<Texture2D> EditorNode::_get_class_or_script_icon(const String &p_class, cons
// directly.

// Check if the class name is an extension-defined type.
Ref<Texture2D> ext_icon = ed.extension_class_get_icon(p_class);
if (ext_icon.is_valid()) {
return ext_icon;
{
const String &icon_path = ed.extension_class_get_icon_path(p_class);
if (!icon_path.is_empty()) {
const Ref<Texture2D> &icon = ResourceLoader::load(icon_path);
if (icon.is_valid()) {
return icon;
}
}
}

// Check if the class name is a custom type.
Expand Down Expand Up @@ -4894,18 +4898,18 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String
scr = p_object;
}

return _get_class_or_script_icon(p_object->get_class(), scr, p_fallback);
return _get_class_or_script_icon(p_object->get_class(), scr.is_valid() ? scr->get_path() : String(), p_fallback);
}

Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p_fallback) {
ERR_FAIL_COND_V_MSG(p_class.is_empty(), nullptr, "Class name cannot be empty.");

Ref<Script> scr;
String script_path;
if (ScriptServer::is_global_class(p_class)) {
scr = EditorNode::get_editor_data().script_class_load_script(p_class);
script_path = ScriptServer::get_global_class_path(p_class);
}

return _get_class_or_script_icon(p_class, scr, p_fallback, true);
return _get_class_or_script_icon(p_class, script_path, p_fallback, true);
}

bool EditorNode::is_object_of_custom_type(const Object *p_object, const StringName &p_class) {
Expand Down
2 changes: 1 addition & 1 deletion editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ class EditorNode : public Node {
void _feature_profile_changed();
bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class);

Ref<Texture2D> _get_class_or_script_icon(const String &p_class, const Ref<Script> &p_script, const String &p_fallback = "Object", bool p_fallback_script_to_theme = false);
Ref<Texture2D> _get_class_or_script_icon(const String &p_class, const String &p_script_path, const String &p_fallback = "Object", bool p_fallback_script_to_theme = false);

void _pick_main_scene_custom_action(const String &p_custom_action_name);

Expand Down

0 comments on commit 1ee1eb2

Please sign in to comment.