diff --git a/doc/classes/EditorResourcePreview.xml b/doc/classes/EditorResourcePreview.xml
index 68ead12c0302..ed0d5e063d2b 100644
--- a/doc/classes/EditorResourcePreview.xml
+++ b/doc/classes/EditorResourcePreview.xml
@@ -31,7 +31,7 @@
- Queue the [param resource] being edited for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called.
+ Queue the [param resource] being edited for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Texture2D] custom_type_icon, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called. custom_type_icon is the custom icon of the resource if it has one.
[b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null.
@@ -42,7 +42,7 @@
- Queue a resource file located at [param path] for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called.
+ Queue a resource file located at [param path] for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Texture2D] custom_type_icon, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called. custom_type_icon is the custom icon of the resource if it has one.
[b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null.
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 80d1e9dcd7e4..5da61f04e9ae 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -332,7 +332,7 @@ void EditorFileDialog::_post_popup() {
set_process_shortcut_input(true);
}
-void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) {
+void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata) {
if (display_mode == DISPLAY_LIST || p_preview.is_null()) {
return;
}
@@ -347,7 +347,7 @@ void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) {
+void EditorFileDialog::_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata) {
set_process(false);
preview_waiting = false;
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 021f2e6d4cee..043bb4f9ab55 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -221,8 +221,8 @@ class EditorFileDialog : public ConfirmationDialog {
void _save_to_recent();
// Callback function is callback(String p_path,Ref preview,Variant udata) preview null if could not load.
- void _thumbnail_result(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata);
- void _thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata);
+ void _thumbnail_result(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata);
+ void _thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata);
void _request_single_thumbnail(const String &p_path);
virtual void shortcut_input(const Ref &p_event) override;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index b854da8e4f4d..cf576a3527e0 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5521,7 +5521,7 @@ void EditorNode::_reposition_active_tab(int idx_to) {
_update_scene_tabs();
}
-void EditorNode::_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) {
+void EditorNode::_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata) {
int p_tab = p_udata.operator signed int();
if (p_preview.is_valid()) {
Rect2 rect = scene_tabs->get_tab_rect(p_tab);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index eefe45ca1fa1..6a3fc2cb9346 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -656,7 +656,7 @@ class EditorNode : public Node {
void _scene_tab_exit();
void _scene_tab_input(const Ref &p_input);
void _reposition_active_tab(int idx_to);
- void _thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata);
+ void _thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata);
void _scene_tab_script_edited(int p_tab);
Dictionary _get_main_scene_state();
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index db4d12c7610a..d11e3f6b61d6 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -99,7 +99,7 @@ void EditorResourcePreview::_thread_func(void *ud) {
erp->_thread();
}
-void EditorResourcePreview::_preview_ready(const String &p_str, const Ref &p_texture, const Ref &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
+void EditorResourcePreview::_preview_ready(const String &p_str, const Ref &p_texture, const Ref &p_small_texture, const Ref &p_custom_type_icon, ObjectID id, const StringName &p_func, const Variant &p_ud) {
String path = p_str;
{
MutexLock lock(preview_mutex);
@@ -118,16 +118,17 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Refpush_call(id, p_func, path, p_texture, p_small_texture, p_ud);
+ MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_custom_type_icon, p_ud);
}
-void EditorResourcePreview::_generate_preview(Ref &r_texture, Ref &r_small_texture, const QueueItem &p_item, const String &cache_base) {
+void EditorResourcePreview::_generate_preview(Ref &r_texture, Ref &r_small_texture, Ref &r_custom_type_icon, const QueueItem &p_item, const String &cache_base) {
String type;
if (p_item.resource.is_valid()) {
@@ -184,11 +185,42 @@ void EditorResourcePreview::_generate_preview(Ref &r_texture, Ref<
break;
}
+ // Fetch custom type icon.
+ r_custom_type_icon = Ref();
+ Ref res;
+ if (p_item.resource.is_valid()) {
+ res = p_item.resource;
+ } else {
+ res = ResourceLoader::load(p_item.path, "");
+ }
+ if (res.is_valid()) {
+ r_custom_type_icon = EditorNode::get_singleton()->get_object_icon(res.ptr(), "");
+ }
+
if (!p_item.resource.is_valid()) {
+ // Cache the preview in case it's a resource on disk
+ bool has_custom_type_icon = r_custom_type_icon.is_valid();
+ bool has_texture = r_texture.is_valid();
+ bool has_small_texture = r_small_texture.is_valid();
+ if (has_texture || has_custom_type_icon) {
+ // Preview is valid, saving the cache now...
+ if (has_texture) {
+ ResourceSaver::save(r_texture, cache_base + ".png");
+
+ // Small texture could only exist if the main texture exists.
+ if (has_small_texture) {
+ ResourceSaver::save(r_small_texture, cache_base + "_small.png");
+ }
+ }
+ if (has_custom_type_icon) {
+ ResourceSaver::save(r_custom_type_icon, cache_base + "_custom_type_icon.png");
+ }
+ }
+
// cache the preview in case it's a resource on disk
if (r_texture.is_valid()) {
//wow it generated a preview... save cache
- bool has_small_texture = r_small_texture.is_valid();
+ has_small_texture = r_small_texture.is_valid();
ResourceSaver::save(r_texture, cache_base + ".png");
if (has_small_texture) {
ResourceSaver::save(r_small_texture, cache_base + "_small.png");
@@ -196,7 +228,9 @@ void EditorResourcePreview::_generate_preview(Ref &r_texture, Ref<
Ref f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + cache_base + ".txt'. Check user write permissions.");
f->store_line(itos(thumbnail_size));
+ f->store_line(itos(has_texture));
f->store_line(itos(has_small_texture));
+ f->store_line(itos(has_custom_type_icon));
f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
f->store_line(FileAccess::get_md5(p_item.path));
}
@@ -217,7 +251,7 @@ void EditorResourcePreview::_iterate() {
path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
}
- _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
+ _preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, cache[item.path].custom_type_icon, item.id, item.function, item.userdata);
preview_mutex.unlock();
} else {
@@ -225,15 +259,16 @@ void EditorResourcePreview::_iterate() {
Ref texture;
Ref small_texture;
+ Ref custom_type_icon_texture;
int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
if (item.resource.is_valid()) {
- _generate_preview(texture, small_texture, item, String());
+ _generate_preview(texture, small_texture, custom_type_icon_texture, item, String());
//adding hash to the end of path (should be ID::) because of 5 argument limit to call_deferred
- _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
+ _preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, custom_type_icon_texture, item.id, item.function, item.userdata);
} else {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
@@ -246,11 +281,13 @@ void EditorResourcePreview::_iterate() {
Ref f = FileAccess::open(file, FileAccess::READ);
if (f.is_null()) {
// No cache found, generate
- _generate_preview(texture, small_texture, item, cache_base);
+ _generate_preview(texture, small_texture, custom_type_icon_texture, item, cache_base);
} else {
uint64_t modtime = FileAccess::get_modified_time(item.path);
int tsize = f->get_line().to_int();
+ bool has_texture = f->get_line().to_int();
bool has_small_texture = f->get_line().to_int();
+ bool has_custom_type_icon = f->get_line().to_int();
uint64_t last_modtime = f->get_line().to_int();
bool cache_valid = true;
@@ -275,7 +312,9 @@ void EditorResourcePreview::_iterate() {
ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
} else {
f2->store_line(itos(thumbnail_size));
+ f2->store_line(itos(has_texture));
f2->store_line(itos(has_small_texture));
+ f2->store_line(itos(has_custom_type_icon));
f2->store_line(itos(modtime));
f2->store_line(md5);
}
@@ -289,32 +328,44 @@ void EditorResourcePreview::_iterate() {
img.instantiate();
Ref small_img;
small_img.instantiate();
+ Ref custom_type_icon_img;
+ custom_type_icon_img.instantiate();
- if (img->load(cache_base + ".png") != OK) {
- cache_valid = false;
- } else {
- texture.instantiate();
- texture->set_image(img);
-
- if (has_small_texture) {
- if (small_img->load(cache_base + "_small.png") != OK) {
- cache_valid = false;
- } else {
- small_texture.instantiate();
- small_texture->set_image(small_img);
+ if (has_texture) {
+ if (img->load(cache_base + ".png") != OK) {
+ cache_valid = false;
+ } else {
+ texture.instantiate();
+ texture->create_from_image(img);
+
+ if (has_small_texture) {
+ if (small_img->load(cache_base + "_small.png") != OK) {
+ cache_valid = false;
+ } else {
+ small_texture.instantiate();
+ small_texture->create_from_image(small_img);
+ }
}
}
}
+
+ if (has_custom_type_icon) {
+ if (custom_type_icon_img->load(cache_base + "_custom_type_icon.png") != OK) {
+ cache_valid = false;
+ } else {
+ custom_type_icon_texture.instantiate();
+ custom_type_icon_texture->create_from_image(custom_type_icon_img);
+ }
+ }
}
if (!cache_valid) {
- _generate_preview(texture, small_texture, item, cache_base);
+ _generate_preview(texture, small_texture, custom_type_icon_texture, item, cache_base);
}
}
- _preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
+ _preview_ready(item.path, texture, small_texture, custom_type_icon_texture, item.id, item.function, item.userdata);
}
}
-
} else {
preview_mutex.unlock();
}
@@ -340,7 +391,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref &p
if (cache.has(path_id) && cache[path_id].last_hash == p_res->hash_edited_version()) {
cache[path_id].order = order++;
- p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
+ p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, cache[path_id].custom_type_icon, p_userdata);
return;
}
@@ -365,7 +416,7 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
if (cache.has(p_path)) {
cache[p_path].order = order++;
- p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
+ p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, cache[p_path].custom_type_icon, p_userdata);
return;
}
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index aae7c5b164cb..b2c153490a75 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -84,6 +84,7 @@ class EditorResourcePreview : public Node {
struct Item {
Ref preview;
Ref small_preview;
+ Ref custom_type_icon;
int order = 0;
uint32_t last_hash = 0;
uint64_t modified_time = 0;
@@ -93,8 +94,8 @@ class EditorResourcePreview : public Node {
HashMap cache;
- void _preview_ready(const String &p_str, const Ref &p_texture, const Ref &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
- void _generate_preview(Ref &r_texture, Ref &r_small_texture, const QueueItem &p_item, const String &cache_base);
+ void _preview_ready(const String &p_str, const Ref &p_texture, const Ref &p_small_texture, const Ref &p_custom_type_icon, ObjectID id, const StringName &p_func, const Variant &p_ud);
+ void _generate_preview(Ref &r_texture, Ref &r_small_texture, Ref &p_custom_type_icon, const QueueItem &p_item, const String &cache_base);
static void _thread_func(void *ud);
void _thread();
@@ -108,7 +109,7 @@ class EditorResourcePreview : public Node {
public:
static EditorResourcePreview *get_singleton();
- // p_receiver_func callback has signature (String p_path, Ref p_preview, Ref p_preview_small, Variant p_userdata)
+ // p_receiver_func callback has signature (String p_path, Ref p_preview, Ref p_preview_small, Ref p_custom_type_icon, Variant p_userdata)
// p_preview will be null if there was an error
void queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
void queue_edited_resource_preview(const Ref &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index e1924c7994c8..05d9b390c94a 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -132,6 +132,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
FileInfo fi;
fi.name = p_dir->get_file(i);
fi.type = p_dir->get_file_type(i);
+ fi.path = p_dir->get_file_path(i);
fi.import_broken = !p_dir->get_file_import_is_valid(i);
fi.modified_time = p_dir->get_file_modified_time(i);
@@ -157,8 +158,10 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
file_item->set_custom_color(0, get_theme_color(SNAME("accent_color"), SNAME("Editor")));
}
Array udata;
- udata.push_back(tree_update_id);
- udata.push_back(file_item);
+ udata.resize(3);
+ udata[0] = tree_update_id;
+ udata[1] = file_item;
+ udata[2] = fi.type;
EditorResourcePreview::get_singleton()->queue_resource_preview(file_metadata, this, "_tree_thumbnail_done", udata);
}
} else if (display_mode == DISPLAY_MODE_SPLIT) {
@@ -286,8 +289,10 @@ void FileSystemDock::_update_tree(const Vector &p_uncollapsed_paths, boo
}
if (!favorite.ends_with("/")) {
Array udata;
- udata.push_back(tree_update_id);
- udata.push_back(ti);
+ udata.resize(3);
+ udata[0] = tree_update_id;
+ udata[1] = ti;
+ udata[2] = ResourceLoader::get_resource_type(favorite);
EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
}
}
@@ -581,30 +586,45 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
_navigate_to_path(p_path);
}
-void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) {
- if ((file_list_vb->is_visible_in_tree() || path == p_path.get_base_dir()) && p_preview.is_valid()) {
+void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata) {
+ if ((file_list_vb->is_visible_in_tree() || path == p_path.get_base_dir()) && (p_preview.is_valid() || p_custom_type_icon.is_valid())) {
Array uarr = p_udata;
int idx = uarr[0];
String file = uarr[1];
+ String resource_type = uarr[2];
if (idx < files->get_item_count() && files->get_item_text(idx) == file && files->get_item_metadata(idx) == p_path) {
if (file_list_display_mode == FILE_LIST_DISPLAY_LIST) {
+ // Prioritize showing previews before custom icons.
if (p_small_preview.is_valid()) {
files->set_item_icon(idx, p_small_preview);
+ } else if (resource_type == "Resource" && p_custom_type_icon.is_valid()) {
+ files->set_item_icon(idx, p_custom_type_icon);
}
} else {
- files->set_item_icon(idx, p_preview);
+ if (resource_type == "Resource" && p_custom_type_icon.is_valid()) {
+ files->set_item_tag_icon(idx, p_custom_type_icon);
+ }
+ if (p_preview.is_valid()) {
+ files->set_item_icon(idx, p_preview);
+ }
}
}
}
}
-void FileSystemDock::_tree_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata) {
- if (p_small_preview.is_valid()) {
+void FileSystemDock::_tree_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata) {
+ if (p_small_preview.is_valid() || p_custom_type_icon.is_valid()) {
Array uarr = p_udata;
if (tree_update_id == (int)uarr[0]) {
TreeItem *file_item = Object::cast_to(uarr[1]);
+ String resource_type = (String)uarr[2];
if (file_item) {
- file_item->set_icon(0, p_small_preview);
+ // Prioritize showing previews before custom icons.
+ if (p_small_preview.is_valid()) {
+ file_item->set_icon(0, p_small_preview);
+ } else if (resource_type == "Resource" && p_custom_type_icon.is_valid()) {
+ file_item->set_icon(0, p_custom_type_icon);
+ }
}
}
}
@@ -941,9 +961,10 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
// Generate the preview.
if (!finfo->import_broken) {
Array udata;
- udata.resize(2);
+ udata.resize(3);
udata[0] = item_index;
udata[1] = fname;
+ udata[2] = ftype;
EditorResourcePreview::get_singleton()->queue_resource_preview(fpath, this, "_file_list_thumbnail_done", udata);
}
@@ -1083,9 +1104,10 @@ void FileSystemDock::_preview_invalidated(const String &p_path) {
if (files->get_item_metadata(i) == p_path) {
// Re-request preview.
Array udata;
- udata.resize(2);
+ udata.resize(3);
udata[0] = i;
udata[1] = files->get_item_text(i);
+ udata[2] = ResourceLoader::get_resource_type(p_path);
EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, this, "_file_list_thumbnail_done", udata);
break;
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 9060f5c0a4d9..c3d312373afe 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -295,8 +295,8 @@ class FileSystemDock : public VBoxContainer {
void _get_drag_target_folder(String &target, bool &target_favorites, const Point2 &p_point, Control *p_from) const;
void _preview_invalidated(const String &p_path);
- void _file_list_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata);
- void _tree_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Variant &p_udata);
+ void _file_list_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata);
+ void _tree_thumbnail_done(const String &p_path, const Ref &p_preview, const Ref &p_small_preview, const Ref &p_custom_type_icon, const Variant &p_udata);
void _update_display_mode(bool p_force = false);