Skip to content

Commit

Permalink
Merge pull request #75472 from YuriSizov/editor-iconography
Browse files Browse the repository at this point in the history
Improve editor support for icons of custom, scripted, and GDExtension classes
  • Loading branch information
akien-mga authored Apr 1, 2023
2 parents c580802 + ee2cc34 commit 21d080e
Show file tree
Hide file tree
Showing 35 changed files with 518 additions and 219 deletions.
9 changes: 9 additions & 0 deletions core/extension/gdextension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,15 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
return Ref<Resource>();
}

// Handle icons if any are specified.
if (config->has_section("icons")) {
List<String> keys;
config->get_section_keys("icons", &keys);
for (const String &key : keys) {
lib->class_icon_paths[key] = config->get_value("icons", key);
}
}

return lib;
}

Expand Down
2 changes: 2 additions & 0 deletions core/extension/gdextension.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class GDExtension : public Resource {
static void _bind_methods();

public:
HashMap<String, String> class_icon_paths;

static String get_extension_list_config_file();
static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr);

Expand Down
23 changes: 23 additions & 0 deletions core/extension/gdextension_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &
extension->initialize_library(GDExtension::InitializationLevel(i));
}
}

for (const KeyValue<String, String> &kv : extension->class_icon_paths) {
gdextension_class_icon_paths[kv.key] = kv.value;
}

gdextension_map[p_path] = extension;
return LOAD_STATUS_OK;
}
Expand All @@ -74,6 +79,11 @@ GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String
extension->deinitialize_library(GDExtension::InitializationLevel(i));
}
}

for (const KeyValue<String, String> &kv : extension->class_icon_paths) {
gdextension_class_icon_paths.erase(kv.key);
}

gdextension_map.erase(p_path);
return LOAD_STATUS_OK;
}
Expand All @@ -95,6 +105,19 @@ Ref<GDExtension> GDExtensionManager::get_extension(const String &p_path) {
return E->value;
}

bool GDExtensionManager::class_has_icon_path(const String &p_class) const {
// TODO: Check that the icon belongs to a registered class somehow.
return gdextension_class_icon_paths.has(p_class);
}

String GDExtensionManager::class_get_icon_path(const String &p_class) const {
// TODO: Check that the icon belongs to a registered class somehow.
if (gdextension_class_icon_paths.has(p_class)) {
return gdextension_class_icon_paths[p_class];
}
return "";
}

void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) {
ERR_FAIL_COND(int32_t(p_level) - 1 != level);
for (KeyValue<String, Ref<GDExtension>> &E : gdextension_map) {
Expand Down
4 changes: 4 additions & 0 deletions core/extension/gdextension_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class GDExtensionManager : public Object {

int32_t level = -1;
HashMap<String, Ref<GDExtension>> gdextension_map;
HashMap<String, String> gdextension_class_icon_paths;

static void _bind_methods();

Expand All @@ -59,6 +60,9 @@ class GDExtensionManager : public Object {
Vector<String> get_loaded_extensions() const;
Ref<GDExtension> get_extension(const String &p_path);

bool class_has_icon_path(const String &p_class) const;
String class_get_icon_path(const String &p_class) const;

void initialize_extensions(GDExtension::InitializationLevel p_level);
void deinitialize_extensions(GDExtension::InitializationLevel p_level);

Expand Down
5 changes: 4 additions & 1 deletion doc/classes/Button.xml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
When this property is enabled, text that is too large to fit the button is clipped, when disabled the Button will always be wide enough to hold the text.
</member>
<member name="expand_icon" type="bool" setter="set_expand_icon" getter="is_expand_icon" default="false">
When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect.
When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect. See also [theme_item icon_max_width].
</member>
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
Flat buttons don't display decoration.
Expand Down Expand Up @@ -116,6 +116,9 @@
<theme_item name="h_separation" data_type="constant" type="int" default="2">
The horizontal space between [Button]'s icon and text. Negative values will be treated as [code]0[/code] when used.
</theme_item>
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the [Button]'s icon. This limit is applied on top of the default size of the icon, or its expanded size if [member expand_icon] is [code]true[/code]. The height is adjusted according to the icon's ratio.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
Expand Down
18 changes: 18 additions & 0 deletions doc/classes/PopupMenu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@
Returns the icon of the item at the given [param index].
</description>
</method>
<method name="get_item_icon_max_width" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the maximum allowed width of the icon for the item at the given [param index].
</description>
</method>
<method name="get_item_id" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
Expand Down Expand Up @@ -397,6 +404,14 @@
Replaces the [Texture2D] icon of the item at the given [param index].
</description>
</method>
<method name="set_item_icon_max_width">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="width" type="int" />
<description>
Sets the maximum allowed width of the icon for the item at the given [param index]. This limit is applied on top of the default size of the icon and on top of [theme_item icon_max_width]. The height is adjusted according to the icon's ratio.
</description>
</method>
<method name="set_item_id">
<return type="void" />
<param index="0" name="index" type="int" />
Expand Down Expand Up @@ -573,6 +588,9 @@
<theme_item name="h_separation" data_type="constant" type="int" default="4">
The horizontal space between the item's elements.
</theme_item>
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the item's icon. This limit is applied on top of the default size of the icon, but before the value set with [method set_item_icon_max_width]. The height is adjusted according to the icon's ratio.
</theme_item>
<theme_item name="indent" data_type="constant" type="int" default="10">
Width of the single indentation level.
</theme_item>
Expand Down
22 changes: 20 additions & 2 deletions doc/classes/TabBar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,21 @@
<return type="Texture2D" />
<param index="0" name="tab_idx" type="int" />
<description>
Returns the [Texture2D] for the right button of the tab at index [param tab_idx] or [code]null[/code] if the button has no [Texture2D].
Returns the icon for the right button of the tab at index [param tab_idx] or [code]null[/code] if the right button has no icon.
</description>
</method>
<method name="get_tab_icon" qualifiers="const">
<return type="Texture2D" />
<param index="0" name="tab_idx" type="int" />
<description>
Returns the [Texture2D] for the tab at index [param tab_idx] or [code]null[/code] if the tab has no [Texture2D].
Returns the icon for the tab at index [param tab_idx] or [code]null[/code] if the tab has no icon.
</description>
</method>
<method name="get_tab_icon_max_width" qualifiers="const">
<return type="int" />
<param index="0" name="tab_idx" type="int" />
<description>
Returns the maximum allowed width of the icon for the tab at index [param tab_idx].
</description>
</method>
<method name="get_tab_idx_at_point" qualifiers="const">
Expand Down Expand Up @@ -158,6 +165,14 @@
Sets an [param icon] for the tab at index [param tab_idx].
</description>
</method>
<method name="set_tab_icon_max_width">
<return type="void" />
<param index="0" name="tab_idx" type="int" />
<param index="1" name="width" type="int" />
<description>
Sets the maximum allowed width of the icon for the tab at index [param tab_idx]. This limit is applied on top of the default size of the icon and on top of [theme_item icon_max_width]. The height is adjusted according to the icon's ratio.
</description>
</method>
<method name="set_tab_language">
<return type="void" />
<param index="0" name="tab_idx" type="int" />
Expand Down Expand Up @@ -323,6 +338,9 @@
<theme_item name="h_separation" data_type="constant" type="int" default="4">
The horizontal separation between the elements inside tabs.
</theme_item>
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the tab's icon. This limit is applied on top of the default size of the icon, but before the value set with [method set_tab_icon_max_width]. The height is adjusted according to the icon's ratio.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the tab text outline.
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/TabContainer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@
<theme_item name="font_unselected_color" data_type="color" type="Color" default="Color(0.7, 0.7, 0.7, 1)">
Font color of the other, unselected tabs.
</theme_item>
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the tab's icon. This limit is applied on top of the default size of the icon, but before the value set with [method TabBar.set_tab_icon_max_width]. The height is adjusted according to the icon's ratio.
</theme_item>
<theme_item name="icon_separation" data_type="constant" type="int" default="4">
Space between tab's name and its icon.
</theme_item>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/Tree.xml
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,9 @@
<theme_item name="h_separation" data_type="constant" type="int" default="4">
The horizontal space between item cells. This is also used as the margin at the start of an item when folding is disabled.
</theme_item>
<theme_item name="icon_max_width" data_type="constant" type="int" default="0">
The maximum allowed width of the icon in item's cells. This limit is applied on top of the default size of the icon, but before the value set with [method TreeItem.set_icon_max_width]. The height is adjusted according to the icon's ratio.
</theme_item>
<theme_item name="item_margin" data_type="constant" type="int" default="16">
The horizontal margin at the start of an item. This is used when folding is enabled for the item.
</theme_item>
Expand Down
4 changes: 2 additions & 2 deletions doc/classes/TreeItem.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@
<return type="int" />
<param index="0" name="column" type="int" />
<description>
Returns the column's icon's maximum width.
Returns the maximum allowed width of the icon in the given [param column].
</description>
</method>
<method name="get_icon_modulate" qualifiers="const">
Expand Down Expand Up @@ -545,7 +545,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="width" type="int" />
<description>
Sets the given column's icon's maximum width.
Sets the maximum allowed width of the icon in the given [param column]. This limit is applied on top of the default size of the icon and on top of [theme_item Tree.icon_max_width]. The height is adjusted according to the icon's ratio.
</description>
</method>
<method name="set_icon_modulate">
Expand Down
5 changes: 5 additions & 0 deletions editor/create_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ void CreateDialog::_notification(int p_what) {
} break;

case NOTIFICATION_THEME_CHANGED: {
const int icon_width = get_theme_constant(SNAME("class_icon_size"), SNAME("Editor"));
search_options->add_theme_constant_override("icon_max_width", icon_width);
favorites->add_theme_constant_override("icon_max_width", icon_width);
recent->set_fixed_icon_size(Size2(icon_width, icon_width));

_update_theme();
} break;
}
Expand Down
65 changes: 63 additions & 2 deletions editor/editor_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@
#include "editor_data.h"

#include "core/config/project_settings.h"
#include "core/extension/gdextension_manager.h"
#include "core/io/file_access.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/resources/packed_scene.h"
Expand Down Expand Up @@ -457,10 +460,10 @@ void EditorData::add_custom_type(const String &p_type, const String &p_inherits,
ct.name = p_type;
ct.icon = p_icon;
ct.script = p_script;

if (!custom_types.has(p_inherits)) {
custom_types[p_inherits] = Vector<CustomType>();
}

custom_types[p_inherits].push_back(ct);
}

Expand Down Expand Up @@ -1028,8 +1031,66 @@ void EditorData::script_class_load_icon_paths() {
}
}

Ref<Texture2D> EditorData::extension_class_get_icon(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 nullptr;
}

Ref<Texture2D> EditorData::_load_script_icon(const String &p_path) const {
if (!p_path.is_empty() && ResourceLoader::exists(p_path)) {
Ref<Texture2D> icon = ResourceLoader::load(p_path);
if (icon.is_valid()) {
return icon;
}
}
return nullptr;
}

Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
// Take from the local cache, if available.
if (_script_icon_cache.has(p_script) && _script_icon_cache[p_script].is_valid()) {
return _script_icon_cache[p_script];
}

Ref<Script> base_scr = p_script;
while (base_scr.is_valid()) {
// Check for scripted classes.
StringName class_name = script_class_get_name(base_scr->get_path());
String 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();
}

// If no icon found, cache it as null.
_script_icon_cache[p_script] = Ref<Texture>();
return nullptr;
}

void EditorData::clear_script_icon_cache() {
_script_icon_cache.clear();
}

EditorData::EditorData() {
current_edited_scene = -1;
undo_redo_manager = memnew(EditorUndoRedoManager);
script_class_load_icon_paths();
}
Expand Down
8 changes: 8 additions & 0 deletions editor/editor_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ 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;

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

public:
EditorPlugin *get_editor(Object *p_object);
Expand Down Expand Up @@ -240,6 +243,11 @@ 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;

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

EditorData();
~EditorData();
};
Expand Down
Loading

0 comments on commit 21d080e

Please sign in to comment.