Skip to content

Commit 7e89fc1

Browse files
committed
Add custom resource icon support in filesystem.
Edited EditorResourcePreview to cache icons when generating previews for resources.
1 parent 0c27edf commit 7e89fc1

9 files changed

Lines changed: 124 additions & 50 deletions

doc/classes/EditorResourcePreview.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<param index="2" name="receiver_func" type="StringName" />
3232
<param index="3" name="userdata" type="Variant" />
3333
<description>
34-
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.
34+
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.
3535
[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.
3636
</description>
3737
</method>
@@ -42,7 +42,7 @@
4242
<param index="2" name="receiver_func" type="StringName" />
4343
<param index="3" name="userdata" type="Variant" />
4444
<description>
45-
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.
45+
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.
4646
[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.
4747
</description>
4848
</method>

editor/editor_file_dialog.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ void EditorFileDialog::_post_popup() {
332332
set_process_shortcut_input(true);
333333
}
334334

335-
void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) {
335+
void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata) {
336336
if (display_mode == DISPLAY_LIST || p_preview.is_null()) {
337337
return;
338338
}
@@ -347,7 +347,7 @@ void EditorFileDialog::_thumbnail_result(const String &p_path, const Ref<Texture
347347
}
348348
}
349349

350-
void EditorFileDialog::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) {
350+
void EditorFileDialog::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata) {
351351
set_process(false);
352352
preview_waiting = false;
353353

editor/editor_file_dialog.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ class EditorFileDialog : public ConfirmationDialog {
221221
void _save_to_recent();
222222
// Callback function is callback(String p_path,Ref<Texture2D> preview,Variant udata) preview null if could not load.
223223

224-
void _thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
225-
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
224+
void _thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata);
225+
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata);
226226
void _request_single_thumbnail(const String &p_path);
227227

228228
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;

editor/editor_node.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5521,7 +5521,7 @@ void EditorNode::_reposition_active_tab(int idx_to) {
55215521
_update_scene_tabs();
55225522
}
55235523

5524-
void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) {
5524+
void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata) {
55255525
int p_tab = p_udata.operator signed int();
55265526
if (p_preview.is_valid()) {
55275527
Rect2 rect = scene_tabs->get_tab_rect(p_tab);

editor/editor_node.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ class EditorNode : public Node {
656656
void _scene_tab_exit();
657657
void _scene_tab_input(const Ref<InputEvent> &p_input);
658658
void _reposition_active_tab(int idx_to);
659-
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
659+
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Ref<Texture2D> &p_custom_type_icon, const Variant &p_udata);
660660
void _scene_tab_script_edited(int p_tab);
661661

662662
Dictionary _get_main_scene_state();

editor/editor_resource_preview.cpp

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void EditorResourcePreview::_thread_func(void *ud) {
9999
erp->_thread();
100100
}
101101

102-
void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
102+
void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, const Ref<Texture2D> &p_custom_type_icon, ObjectID id, const StringName &p_func, const Variant &p_ud) {
103103
String path = p_str;
104104
{
105105
MutexLock lock(preview_mutex);
@@ -118,16 +118,17 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
118118
item.order = order++;
119119
item.preview = p_texture;
120120
item.small_preview = p_small_texture;
121+
item.custom_type_icon = p_custom_type_icon;
121122
item.last_hash = hash;
122123
item.modified_time = modified_time;
123124

124125
cache[path] = item;
125126
}
126127

127-
MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_ud);
128+
MessageQueue::get_singleton()->push_call(id, p_func, path, p_texture, p_small_texture, p_custom_type_icon, p_ud);
128129
}
129130

130-
void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base) {
131+
void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, Ref<ImageTexture> &r_custom_type_icon, const QueueItem &p_item, const String &cache_base) {
131132
String type;
132133

133134
if (p_item.resource.is_valid()) {
@@ -184,19 +185,52 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
184185
break;
185186
}
186187

188+
// Fetch custom type icon.
189+
r_custom_type_icon = Ref<ImageTexture>();
190+
Ref<Resource> res;
191+
if (p_item.resource.is_valid()) {
192+
res = p_item.resource;
193+
} else {
194+
res = ResourceLoader::load(p_item.path, "");
195+
}
196+
if (res.is_valid()) {
197+
r_custom_type_icon = EditorNode::get_singleton()->get_object_icon(res.ptr(), "");
198+
}
199+
187200
if (!p_item.resource.is_valid()) {
201+
// Cache the preview in case it's a resource on disk
202+
bool has_custom_type_icon = r_custom_type_icon.is_valid();
203+
bool has_texture = r_texture.is_valid();
204+
bool has_small_texture = r_small_texture.is_valid();
205+
if (has_texture || has_custom_type_icon) {
206+
// Preview is valid, saving the cache now...
207+
if (has_texture) {
208+
ResourceSaver::save(r_texture, cache_base + ".png");
209+
210+
// Small texture could only exist if the main texture exists.
211+
if (has_small_texture) {
212+
ResourceSaver::save(r_small_texture, cache_base + "_small.png");
213+
}
214+
}
215+
if (has_custom_type_icon) {
216+
ResourceSaver::save(r_custom_type_icon, cache_base + "_custom_type_icon.png");
217+
}
218+
}
219+
188220
// cache the preview in case it's a resource on disk
189221
if (r_texture.is_valid()) {
190222
//wow it generated a preview... save cache
191-
bool has_small_texture = r_small_texture.is_valid();
223+
has_small_texture = r_small_texture.is_valid();
192224
ResourceSaver::save(r_texture, cache_base + ".png");
193225
if (has_small_texture) {
194226
ResourceSaver::save(r_small_texture, cache_base + "_small.png");
195227
}
196228
Ref<FileAccess> f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE);
197229
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + cache_base + ".txt'. Check user write permissions.");
198230
f->store_line(itos(thumbnail_size));
231+
f->store_line(itos(has_texture));
199232
f->store_line(itos(has_small_texture));
233+
f->store_line(itos(has_custom_type_icon));
200234
f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
201235
f->store_line(FileAccess::get_md5(p_item.path));
202236
}
@@ -217,23 +251,24 @@ void EditorResourcePreview::_iterate() {
217251
path += ":" + itos(cache[item.path].last_hash); //keep last hash (see description of what this is in condition below)
218252
}
219253

220-
_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, item.id, item.function, item.userdata);
254+
_preview_ready(path, cache[item.path].preview, cache[item.path].small_preview, cache[item.path].custom_type_icon, item.id, item.function, item.userdata);
221255

222256
preview_mutex.unlock();
223257
} else {
224258
preview_mutex.unlock();
225259

226260
Ref<ImageTexture> texture;
227261
Ref<ImageTexture> small_texture;
262+
Ref<ImageTexture> custom_type_icon_texture;
228263

229264
int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
230265
thumbnail_size *= EDSCALE;
231266

232267
if (item.resource.is_valid()) {
233-
_generate_preview(texture, small_texture, item, String());
268+
_generate_preview(texture, small_texture, custom_type_icon_texture, item, String());
234269

235270
//adding hash to the end of path (should be ID:<objid>:<hash>) because of 5 argument limit to call_deferred
236-
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, item.id, item.function, item.userdata);
271+
_preview_ready(item.path + ":" + itos(item.resource->hash_edited_version()), texture, small_texture, custom_type_icon_texture, item.id, item.function, item.userdata);
237272

238273
} else {
239274
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
@@ -246,11 +281,13 @@ void EditorResourcePreview::_iterate() {
246281
Ref<FileAccess> f = FileAccess::open(file, FileAccess::READ);
247282
if (f.is_null()) {
248283
// No cache found, generate
249-
_generate_preview(texture, small_texture, item, cache_base);
284+
_generate_preview(texture, small_texture, custom_type_icon_texture, item, cache_base);
250285
} else {
251286
uint64_t modtime = FileAccess::get_modified_time(item.path);
252287
int tsize = f->get_line().to_int();
288+
bool has_texture = f->get_line().to_int();
253289
bool has_small_texture = f->get_line().to_int();
290+
bool has_custom_type_icon = f->get_line().to_int();
254291
uint64_t last_modtime = f->get_line().to_int();
255292

256293
bool cache_valid = true;
@@ -275,7 +312,9 @@ void EditorResourcePreview::_iterate() {
275312
ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions.");
276313
} else {
277314
f2->store_line(itos(thumbnail_size));
315+
f2->store_line(itos(has_texture));
278316
f2->store_line(itos(has_small_texture));
317+
f2->store_line(itos(has_custom_type_icon));
279318
f2->store_line(itos(modtime));
280319
f2->store_line(md5);
281320
}
@@ -289,32 +328,44 @@ void EditorResourcePreview::_iterate() {
289328
img.instantiate();
290329
Ref<Image> small_img;
291330
small_img.instantiate();
331+
Ref<Image> custom_type_icon_img;
332+
custom_type_icon_img.instantiate();
292333

293-
if (img->load(cache_base + ".png") != OK) {
294-
cache_valid = false;
295-
} else {
296-
texture.instantiate();
297-
texture->set_image(img);
298-
299-
if (has_small_texture) {
300-
if (small_img->load(cache_base + "_small.png") != OK) {
301-
cache_valid = false;
302-
} else {
303-
small_texture.instantiate();
304-
small_texture->set_image(small_img);
334+
if (has_texture) {
335+
if (img->load(cache_base + ".png") != OK) {
336+
cache_valid = false;
337+
} else {
338+
texture.instantiate();
339+
texture->create_from_image(img);
340+
341+
if (has_small_texture) {
342+
if (small_img->load(cache_base + "_small.png") != OK) {
343+
cache_valid = false;
344+
} else {
345+
small_texture.instantiate();
346+
small_texture->create_from_image(small_img);
347+
}
305348
}
306349
}
307350
}
351+
352+
if (has_custom_type_icon) {
353+
if (custom_type_icon_img->load(cache_base + "_custom_type_icon.png") != OK) {
354+
cache_valid = false;
355+
} else {
356+
custom_type_icon_texture.instantiate();
357+
custom_type_icon_texture->create_from_image(custom_type_icon_img);
358+
}
359+
}
308360
}
309361

310362
if (!cache_valid) {
311-
_generate_preview(texture, small_texture, item, cache_base);
363+
_generate_preview(texture, small_texture, custom_type_icon_texture, item, cache_base);
312364
}
313365
}
314-
_preview_ready(item.path, texture, small_texture, item.id, item.function, item.userdata);
366+
_preview_ready(item.path, texture, small_texture, custom_type_icon_texture, item.id, item.function, item.userdata);
315367
}
316368
}
317-
318369
} else {
319370
preview_mutex.unlock();
320371
}
@@ -340,7 +391,7 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
340391

341392
if (cache.has(path_id) && cache[path_id].last_hash == p_res->hash_edited_version()) {
342393
cache[path_id].order = order++;
343-
p_receiver->call(p_receiver_func, path_id, cache[path_id].preview, cache[path_id].small_preview, p_userdata);
394+
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);
344395
return;
345396
}
346397

@@ -365,7 +416,7 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
365416

366417
if (cache.has(p_path)) {
367418
cache[p_path].order = order++;
368-
p_receiver->call(p_receiver_func, p_path, cache[p_path].preview, cache[p_path].small_preview, p_userdata);
419+
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);
369420
return;
370421
}
371422

editor/editor_resource_preview.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class EditorResourcePreview : public Node {
8484
struct Item {
8585
Ref<Texture2D> preview;
8686
Ref<Texture2D> small_preview;
87+
Ref<Texture2D> custom_type_icon;
8788
int order = 0;
8889
uint32_t last_hash = 0;
8990
uint64_t modified_time = 0;
@@ -93,8 +94,8 @@ class EditorResourcePreview : public Node {
9394

9495
HashMap<String, Item> cache;
9596

96-
void _preview_ready(const String &p_str, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
97-
void _generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base);
97+
void _preview_ready(const String &p_str, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, const Ref<Texture2D> &p_custom_type_icon, ObjectID id, const StringName &p_func, const Variant &p_ud);
98+
void _generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, Ref<ImageTexture> &p_custom_type_icon, const QueueItem &p_item, const String &cache_base);
9899

99100
static void _thread_func(void *ud);
100101
void _thread();
@@ -108,7 +109,7 @@ class EditorResourcePreview : public Node {
108109
public:
109110
static EditorResourcePreview *get_singleton();
110111

111-
// p_receiver_func callback has signature (String p_path, Ref<Texture2D> p_preview, Ref<Texture2D> p_preview_small, Variant p_userdata)
112+
// p_receiver_func callback has signature (String p_path, Ref<Texture2D> p_preview, Ref<Texture2D> p_preview_small, Ref<Texture2D> p_custom_type_icon, Variant p_userdata)
112113
// p_preview will be null if there was an error
113114
void queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
114115
void queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);

0 commit comments

Comments
 (0)