summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/io/resource_loader.cpp3
-rw-r--r--core/io/resource_loader.h16
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml4
-rw-r--r--doc/classes/EditorResourceTooltipPlugin.xml46
-rw-r--r--doc/classes/FileSystemDock.xml14
-rw-r--r--editor/editor_node.cpp18
-rw-r--r--editor/editor_node.h11
-rw-r--r--editor/editor_resource_preview.cpp6
-rw-r--r--editor/editor_resource_preview.h2
-rw-r--r--editor/filesystem_dock.cpp62
-rw-r--r--editor/filesystem_dock.h19
-rw-r--r--editor/import/editor_import_collada.cpp7
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/plugins/editor_resource_tooltip_plugins.cpp122
-rw-r--r--editor/plugins/editor_resource_tooltip_plugins.h70
-rw-r--r--editor/register_editor_types.cpp2
16 files changed, 357 insertions, 47 deletions
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index a27341dd2c..f852e8d382 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -1136,10 +1136,7 @@ void ResourceLoader::initialize() {}
void ResourceLoader::finalize() {}
ResourceLoadErrorNotify ResourceLoader::err_notify = nullptr;
-void *ResourceLoader::err_notify_ud = nullptr;
-
DependencyErrorNotify ResourceLoader::dep_err_notify = nullptr;
-void *ResourceLoader::dep_err_notify_ud = nullptr;
bool ResourceLoader::create_missing_resources_if_class_unavailable = false;
bool ResourceLoader::abort_on_missing_resource = true;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index ffe9d5de9a..592befb603 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -89,8 +89,8 @@ public:
VARIANT_ENUM_CAST(ResourceFormatLoader::CacheMode)
-typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text);
-typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type);
+typedef void (*ResourceLoadErrorNotify)(const String &p_text);
+typedef void (*DependencyErrorNotify)(const String &p_loading, const String &p_which, const String &p_type);
typedef Error (*ResourceLoaderImport)(const String &p_path);
typedef void (*ResourceLoadedCallback)(Ref<Resource> p_resource, const String &p_path);
@@ -218,24 +218,24 @@ public:
static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load = p_timestamp; }
static bool get_timestamp_on_load() { return timestamp_on_load; }
+ // Loaders can safely use this regardless which thread they are running on.
static void notify_load_error(const String &p_err) {
if (err_notify) {
- err_notify(err_notify_ud, p_err);
+ callable_mp_static(err_notify).bind(p_err).call_deferred();
}
}
- static void set_error_notify_func(void *p_ud, ResourceLoadErrorNotify p_err_notify) {
+ static void set_error_notify_func(ResourceLoadErrorNotify p_err_notify) {
err_notify = p_err_notify;
- err_notify_ud = p_ud;
}
+ // Loaders can safely use this regardless which thread they are running on.
static void notify_dependency_error(const String &p_path, const String &p_dependency, const String &p_type) {
if (dep_err_notify) {
- dep_err_notify(dep_err_notify_ud, p_path, p_dependency, p_type);
+ callable_mp_static(dep_err_notify).bind(p_path, p_dependency, p_type).call_deferred();
}
}
- static void set_dependency_error_notify_func(void *p_ud, DependencyErrorNotify p_err_notify) {
+ static void set_dependency_error_notify_func(DependencyErrorNotify p_err_notify) {
dep_err_notify = p_err_notify;
- dep_err_notify_ud = p_ud;
}
static void set_abort_on_missing_resources(bool p_abort) { abort_on_missing_resource = p_abort; }
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index 3dc60b3a98..e69c6489df 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -25,7 +25,7 @@
Generate a preview from a given resource with the specified size. This must always be implemented.
Returning an empty texture is an OK way to fail and let another generator take care.
Care must be taken because this function is always called from a thread (not the main thread).
- [param metadata] dictionary can modified to store file-specific metadata that can be used by the editor (like image size, sample length etc.).
+ [param metadata] dictionary can modified to store file-specific metadata that can be used in [method EditorResourceTooltipPlugin._make_tooltip_for_path] (like image size, sample length etc.).
</description>
</method>
<method name="_generate_from_path" qualifiers="virtual const">
@@ -37,7 +37,7 @@
Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method _generate].
Returning an empty texture is an OK way to fail and let another generator take care.
Care must be taken because this function is always called from a thread (not the main thread).
- [param metadata] dictionary can modified to store file-specific metadata that can be used by the editor (like image size, sample length etc.).
+ [param metadata] dictionary can modified to store file-specific metadata that can be used in [method EditorResourceTooltipPlugin._make_tooltip_for_path] (like image size, sample length etc.).
</description>
</method>
<method name="_generate_small_preview_automatically" qualifiers="virtual const">
diff --git a/doc/classes/EditorResourceTooltipPlugin.xml b/doc/classes/EditorResourceTooltipPlugin.xml
new file mode 100644
index 0000000000..ada91c4e7c
--- /dev/null
+++ b/doc/classes/EditorResourceTooltipPlugin.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorResourceTooltipPlugin" inherits="RefCounted" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A plugin that advanced tooltip for its handled resource type.
+ </brief_description>
+ <description>
+ Resource tooltip plugins are used by [FileSystemDock] to generate customized tooltips for specific resources. E.g. tooltip for a [Texture2D] displays a bigger preview and the texture's dimensions.
+ A plugin must be first registered with [method FileSystemDock.add_resource_tooltip_plugin]. When the user hovers a resource in filesystem dock which is handled by the plugin, [method _make_tooltip_for_path] is called to create the tooltip. It works similarly to [method Control._make_custom_tooltip].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_handles" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="type" type="String" />
+ <description>
+ Return [code]true[/code] if the plugin is going to handle the given [Resource] [param type].
+ </description>
+ </method>
+ <method name="_make_tooltip_for_path" qualifiers="virtual const">
+ <return type="Object" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="metadata" type="Dictionary" />
+ <description>
+ Create and return a tooltip that will be displayed when the user hovers resource under given [param path] in filesystem dock. For best results, use [method make_default_tooltip] as a base.
+ The [param metadata] dictionary is provided by preview generator (see method EditorResourcePreviewGenerator._generate]).
+ [b]Note:[/b] It's unadvised to use [method ResourceLoader.load], especially with heavy resources like models or textures, because it will make the editor unresponsive when creating the tooltip. You can use [method request_thumbnail] if you want to display a preview in your tooltip.
+ </description>
+ </method>
+ <method name="make_default_tooltip" qualifiers="static">
+ <return type="VBoxContainer" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Creates a default file tooltip. The tooltip includes file name, file size and [Resource] type if available.
+ </description>
+ </method>
+ <method name="request_thumbnail" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="control" type="TextureRect" />
+ <description>
+ Requests a thumbnail for the given [TextureRect]. The thumbnail is created asynchronously by [EditorResourcePreview] and automatically set when available.
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
index f8f6f26bfc..82a216d713 100644
--- a/doc/classes/FileSystemDock.xml
+++ b/doc/classes/FileSystemDock.xml
@@ -10,6 +10,13 @@
<tutorials>
</tutorials>
<methods>
+ <method name="add_resource_tooltip_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceTooltipPlugin" />
+ <description>
+ Registers a new [EditorResourceTooltipPlugin].
+ </description>
+ </method>
<method name="navigate_to_path">
<return type="void" />
<param index="0" name="path" type="String" />
@@ -17,6 +24,13 @@
Sets the given [param path] as currently selected, ensuring that the selected file/directory is visible.
</description>
</method>
+ <method name="remove_resource_tooltip_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceTooltipPlugin" />
+ <description>
+ Removes an [EditorResourceTooltipPlugin]. Fails if the plugin wasn't previously added.
+ </description>
+ </method>
</methods>
<signals>
<signal name="display_mode_changed">
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 16128603b5..2d9f9645b8 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -4115,16 +4115,10 @@ void EditorNode::notify_all_debug_sessions_exited() {
}
void EditorNode::add_io_error(const String &p_error) {
- _load_error_notify(singleton, p_error);
-}
-
-void EditorNode::_load_error_notify(void *p_ud, const String &p_text) {
- EditorNode *en = static_cast<EditorNode *>(p_ud);
- if (en && en->load_error_dialog) {
- en->load_errors->add_image(en->gui_base->get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
- en->load_errors->add_text(p_text + "\n");
- en->load_error_dialog->attach_and_popup_centered_ratio(0.5);
- }
+ DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());
+ singleton->load_errors->add_image(singleton->gui_base->get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
+ singleton->load_errors->add_text(p_error + "\n");
+ singleton->load_error_dialog->attach_and_popup_centered_ratio(0.5);
}
bool EditorNode::_find_scene_in_use(Node *p_node, const String &p_path) const {
@@ -6731,8 +6725,8 @@ EditorNode::EditorNode() {
}
ResourceLoader::set_abort_on_missing_resources(false);
- ResourceLoader::set_error_notify_func(this, _load_error_notify);
- ResourceLoader::set_dependency_error_notify_func(this, _dependency_error_report);
+ ResourceLoader::set_error_notify_func(&EditorNode::add_io_error);
+ ResourceLoader::set_dependency_error_notify_func(&EditorNode::_dependency_error_report);
{
// Register importers at the beginning, so dialogs are created with the right extensions.
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 9917fa16bc..221637be1c 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -504,12 +504,12 @@ private:
static int plugin_init_callback_count;
static Vector<EditorNodeInitCallback> _init_callbacks;
- static void _dependency_error_report(void *ud, const String &p_path, const String &p_dep, const String &p_type) {
- EditorNode *en = static_cast<EditorNode *>(ud);
- if (!en->dependency_errors.has(p_path)) {
- en->dependency_errors[p_path] = HashSet<String>();
+ static void _dependency_error_report(const String &p_path, const String &p_dep, const String &p_type) {
+ DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id());
+ if (!singleton->dependency_errors.has(p_path)) {
+ singleton->dependency_errors[p_path] = HashSet<String>();
}
- en->dependency_errors[p_path].insert(p_dep + "::" + p_type);
+ singleton->dependency_errors[p_path].insert(p_dep + "::" + p_type);
}
static Ref<Texture2D> _file_dialog_get_icon(const String &p_path);
@@ -518,7 +518,6 @@ private:
static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
- static void _load_error_notify(void *p_ud, const String &p_text);
static void _file_access_close_error_notify(const String &p_str);
static void _print_handler(void *p_this, const String &p_string, bool p_error, bool p_rich);
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 7dea1a7e01..45a100a4e5 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -198,9 +198,9 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
}
-Variant EditorResourcePreview::get_preview_metadata(const String &p_path, const String &p_meta) const {
- ERR_FAIL_COND_V(!cache.has(p_path), Variant());
- return cache[p_path].preview_metadata.get(p_meta, Variant());
+const Dictionary EditorResourcePreview::get_preview_metadata(const String &p_path) const {
+ ERR_FAIL_COND_V(!cache.has(p_path), Dictionary());
+ return cache[p_path].preview_metadata;
}
void EditorResourcePreview::_iterate() {
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index c97e153c0a..96ce672d0e 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -116,7 +116,7 @@ public:
// 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<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata);
- Variant get_preview_metadata(const String &p_path, const String &p_meta) const;
+ const Dictionary get_preview_metadata(const String &p_path) const;
void add_preview_generator(const Ref<EditorResourcePreviewGenerator> &p_generator);
void remove_preview_generator(const Ref<EditorResourcePreviewGenerator> &p_generator);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index dd80ff49ac..87ba7f53b0 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -47,6 +47,7 @@
#include "editor/gui/editor_dir_dialog.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import_dock.h"
+#include "editor/plugins/editor_resource_tooltip_plugins.h"
#include "editor/scene_create_dialog.h"
#include "editor/scene_tree_dock.h"
#include "editor/shader_create_dialog.h"
@@ -54,10 +55,27 @@
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/progress_bar.h"
+#include "scene/gui/texture_rect.h"
#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
#include "servers/display_server.h"
+Control *FileSystemTree::make_custom_tooltip(const String &p_text) const {
+ TreeItem *item = get_item_at_position(get_local_mouse_position());
+ if (!item) {
+ return nullptr;
+ }
+ return FileSystemDock::get_singleton()->create_tooltip_for_path(item->get_metadata(0));
+}
+
+Control *FileSystemList::make_custom_tooltip(const String &p_text) const {
+ int idx = get_item_at_position(get_local_mouse_position());
+ if (idx == -1) {
+ return nullptr;
+ }
+ return FileSystemDock::get_singleton()->create_tooltip_for_path(get_item_metadata(idx));
+}
+
FileSystemDock *FileSystemDock::singleton = nullptr;
Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, String p_file_type) {
@@ -2249,6 +2267,41 @@ void FileSystemDock::set_file_list_display_mode(FileListDisplayMode p_mode) {
_toggle_file_display();
}
+void FileSystemDock::add_resource_tooltip_plugin(const Ref<EditorResourceTooltipPlugin> &p_plugin) {
+ tooltip_plugins.push_back(p_plugin);
+}
+
+void FileSystemDock::remove_resource_tooltip_plugin(const Ref<EditorResourceTooltipPlugin> &p_plugin) {
+ int index = tooltip_plugins.find(p_plugin);
+ ERR_FAIL_COND_MSG(index == -1, "Can't remove plugin that wasn't registered.");
+ tooltip_plugins.remove_at(index);
+}
+
+Control *FileSystemDock::create_tooltip_for_path(const String &p_path) const {
+ if (DirAccess::exists(p_path)) {
+ // No tooltip for directory.
+ return nullptr;
+ }
+
+ const String type = ResourceLoader::get_resource_type(p_path);
+ Control *tooltip = nullptr;
+
+ for (const Ref<EditorResourceTooltipPlugin> &plugin : tooltip_plugins) {
+ if (plugin->handles(type)) {
+ tooltip = plugin->make_tooltip_for_path(p_path, EditorResourcePreview::get_singleton()->get_preview_metadata(p_path));
+ }
+
+ if (tooltip) {
+ break;
+ }
+ }
+
+ if (!tooltip) {
+ tooltip = EditorResourceTooltipPlugin::make_default_tooltip(p_path);
+ }
+ return tooltip;
+}
+
Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
bool all_favorites = true;
bool all_not_favorites = true;
@@ -3130,6 +3183,9 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
+ ClassDB::bind_method(D_METHOD("add_resource_tooltip_plugin", "plugin"), &FileSystemDock::add_resource_tooltip_plugin);
+ ClassDB::bind_method(D_METHOD("remove_resource_tooltip_plugin", "plugin"), &FileSystemDock::remove_resource_tooltip_plugin);
+
ADD_SIGNAL(MethodInfo("inherit", PropertyInfo(Variant::STRING, "file")));
ADD_SIGNAL(MethodInfo("instantiate", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files")));
@@ -3227,7 +3283,7 @@ FileSystemDock::FileSystemDock() {
split_box->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(split_box);
- tree = memnew(Tree);
+ tree = memnew(FileSystemTree);
tree->set_hide_root(true);
SET_DRAG_FORWARDING_GCD(tree, FileSystemDock);
@@ -3266,7 +3322,7 @@ FileSystemDock::FileSystemDock() {
button_file_list_display_mode->set_flat(true);
path_hb->add_child(button_file_list_display_mode);
- files = memnew(ItemList);
+ files = memnew(FileSystemList);
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_select_mode(ItemList::SELECT_MULTI);
SET_DRAG_FORWARDING_GCD(files, FileSystemDock);
@@ -3355,6 +3411,8 @@ FileSystemDock::FileSystemDock() {
display_mode = DISPLAY_MODE_TREE_ONLY;
old_display_mode = DISPLAY_MODE_TREE_ONLY;
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
+
+ add_resource_tooltip_plugin(memnew(EditorTextureTooltipPlugin));
}
FileSystemDock::~FileSystemDock() {
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 05a6372830..d8d7434579 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -50,6 +50,15 @@ class ProgressBar;
class SceneCreateDialog;
class ShaderCreateDialog;
class DirectoryCreateDialog;
+class EditorResourceTooltipPlugin;
+
+class FileSystemTree : public Tree {
+ virtual Control *make_custom_tooltip(const String &p_text) const;
+};
+
+class FileSystemList : public ItemList {
+ virtual Control *make_custom_tooltip(const String &p_text) const;
+};
class FileSystemDock : public VBoxContainer {
GDCLASS(FileSystemDock, VBoxContainer);
@@ -189,14 +198,16 @@ private:
bool updating_tree = false;
int tree_update_id;
- Tree *tree = nullptr;
- ItemList *files = nullptr;
+ FileSystemTree *tree = nullptr;
+ FileSystemList *files = nullptr;
bool import_dock_needs_update = false;
bool holding_branch = false;
Vector<TreeItem *> tree_items_selected_on_drag_begin;
PackedInt32Array list_items_selected_on_drag_begin;
+ LocalVector<Ref<EditorResourceTooltipPlugin>> tooltip_plugins;
+
void _tree_mouse_exited();
void _reselect_items_selected_on_drag_begin(bool reset = false);
@@ -351,6 +362,10 @@ public:
Tree *get_tree_control() { return tree; }
+ void add_resource_tooltip_plugin(const Ref<EditorResourceTooltipPlugin> &p_plugin);
+ void remove_resource_tooltip_plugin(const Ref<EditorResourceTooltipPlugin> &p_plugin);
+ Control *create_tooltip_for_path(const String &p_path) const;
+
FileSystemDock();
~FileSystemDock();
};
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 1ffede6502..5f714e4488 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1782,15 +1782,8 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3
ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Cannot load scene from file '" + p_path + "'.");
if (state.missing_textures.size()) {
- /*
- for(int i=0;i<state.missing_textures.size();i++) {
- EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
- }
- */
-
if (r_missing_deps) {
for (int i = 0; i < state.missing_textures.size(); i++) {
- //EditorNode::add_io_error("Texture Not Found: "+state.missing_textures[i]);
r_missing_deps->push_back(state.missing_textures[i]);
}
}
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index ba48fc9029..1275e5b85a 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -106,7 +106,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri
if (err != OK) {
if (!ShaderFileEditor::singleton->is_visible_in_tree()) {
- EditorNode::get_singleton()->add_io_error(vformat(TTR("Error importing GLSL shader file: '%s'. Open the file in the filesystem dock in order to see the reason."), p_source_file));
+ callable_mp_static(&EditorNode::add_io_error).bind(vformat(TTR("Error importing GLSL shader file: '%s'. Open the file in the filesystem dock in order to see the reason."), p_source_file)).call_deferred();
}
}
diff --git a/editor/plugins/editor_resource_tooltip_plugins.cpp b/editor/plugins/editor_resource_tooltip_plugins.cpp
new file mode 100644
index 0000000000..26371360e9
--- /dev/null
+++ b/editor/plugins/editor_resource_tooltip_plugins.cpp
@@ -0,0 +1,122 @@
+/**************************************************************************/
+/* editor_resource_tooltip_plugins.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "editor_resource_tooltip_plugins.h"
+
+#include "editor/editor_resource_preview.h"
+#include "editor/editor_scale.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/control.h"
+#include "scene/gui/label.h"
+#include "scene/gui/texture_rect.h"
+
+void EditorResourceTooltipPlugin::_thumbnail_ready(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) {
+ ObjectID trid = p_udata;
+ TextureRect *tr = Object::cast_to<TextureRect>(ObjectDB::get_instance(trid));
+
+ if (!tr) {
+ return;
+ }
+
+ tr->set_texture(p_preview);
+}
+
+void EditorResourceTooltipPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_thumbnail_ready"), &EditorResourceTooltipPlugin::_thumbnail_ready);
+
+ ClassDB::bind_static_method("EditorResourceTooltipPlugin", D_METHOD("make_default_tooltip", "path"), &EditorResourceTooltipPlugin::make_default_tooltip);
+ ClassDB::bind_method(D_METHOD("request_thumbnail", "path", "control"), &EditorResourceTooltipPlugin::request_thumbnail);
+
+ GDVIRTUAL_BIND(_handles, "type");
+ GDVIRTUAL_BIND(_make_tooltip_for_path, "path", "metadata");
+}
+
+VBoxContainer *EditorResourceTooltipPlugin::make_default_tooltip(const String &p_resource_path) {
+ VBoxContainer *vb = memnew(VBoxContainer);
+ vb->add_theme_constant_override("separation", -4 * EDSCALE);
+ {
+ Label *label = memnew(Label(p_resource_path.get_file()));
+ vb->add_child(label);
+ }
+
+ {
+ Ref<FileAccess> f = FileAccess::open(p_resource_path, FileAccess::READ);
+ Label *label = memnew(Label(vformat(TTR("Size: %s"), String::humanize_size(f->get_length()))));
+ vb->add_child(label);
+ }
+
+ if (ResourceLoader::exists(p_resource_path)) {
+ String type = ResourceLoader::get_resource_type(p_resource_path);
+ Label *label = memnew(Label(vformat(TTR("Type: %s"), type)));
+ vb->add_child(label);
+ }
+ return vb;
+}
+
+void EditorResourceTooltipPlugin::request_thumbnail(const String &p_path, TextureRect *p_for_control) const {
+ ERR_FAIL_NULL(p_for_control);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, const_cast<EditorResourceTooltipPlugin *>(this), "_thumbnail_ready", p_for_control->get_instance_id());
+}
+
+bool EditorResourceTooltipPlugin::handles(const String &p_resource_type) const {
+ bool ret = false;
+ GDVIRTUAL_CALL(_handles, p_resource_type, ret);
+ return ret;
+}
+
+Control *EditorResourceTooltipPlugin::make_tooltip_for_path(const String &p_resource_path, const Dictionary &p_metadata) const {
+ Object *ret = nullptr;
+ GDVIRTUAL_CALL(_make_tooltip_for_path, p_resource_path, p_metadata, ret);
+ return Object::cast_to<Control>(ret);
+}
+
+// EditorTextureTooltipPlugin
+
+bool EditorTextureTooltipPlugin::handles(const String &p_resource_type) const {
+ return ClassDB::is_parent_class(p_resource_type, "Texture2D") || ClassDB::is_parent_class(p_resource_type, "Image");
+}
+
+Control *EditorTextureTooltipPlugin::make_tooltip_for_path(const String &p_resource_path, const Dictionary &p_metadata) const {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ VBoxContainer *vb = EditorResourceTooltipPlugin::make_default_tooltip(p_resource_path);
+ vb->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+
+ Vector2 dimensions = p_metadata.get("dimensions", Vector2());
+ Label *label = memnew(Label(vformat(TTR(U"Dimensions: %d × %d"), dimensions.x, dimensions.y)));
+ vb->add_child(label);
+
+ TextureRect *tr = memnew(TextureRect);
+ tr->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
+ hb->add_child(tr);
+ request_thumbnail(p_resource_path, tr);
+
+ hb->add_child(vb);
+ return hb;
+}
diff --git a/editor/plugins/editor_resource_tooltip_plugins.h b/editor/plugins/editor_resource_tooltip_plugins.h
new file mode 100644
index 0000000000..dfccbb80ed
--- /dev/null
+++ b/editor/plugins/editor_resource_tooltip_plugins.h
@@ -0,0 +1,70 @@
+/**************************************************************************/
+/* editor_resource_tooltip_plugins.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef EDITOR_RESOURCE_TOOLTIP_PLUGINS_H
+#define EDITOR_RESOURCE_TOOLTIP_PLUGINS_H
+
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/ref_counted.h"
+#include "core/object/script_language.h"
+
+class Control;
+class Texture2D;
+class TextureRect;
+class VBoxContainer;
+
+class EditorResourceTooltipPlugin : public RefCounted {
+ GDCLASS(EditorResourceTooltipPlugin, RefCounted);
+
+ void _thumbnail_ready(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL1RC(bool, _handles, String)
+ GDVIRTUAL2RC(Object *, _make_tooltip_for_path, String, Dictionary)
+
+public:
+ static VBoxContainer *make_default_tooltip(const String &p_resource_path);
+ void request_thumbnail(const String &p_path, TextureRect *p_for_control) const;
+
+ virtual bool handles(const String &p_resource_type) const;
+ virtual Control *make_tooltip_for_path(const String &p_resource_path, const Dictionary &p_metadata) const;
+};
+
+class EditorTextureTooltipPlugin : public EditorResourceTooltipPlugin {
+ GDCLASS(EditorTextureTooltipPlugin, EditorResourceTooltipPlugin);
+
+public:
+ virtual bool handles(const String &p_resource_type) const override;
+ virtual Control *make_tooltip_for_path(const String &p_resource_path, const Dictionary &p_metadata) const override;
+};
+
+#endif // EDITOR_RESOURCE_TOOLTIP_PLUGINS_H
diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp
index 1096003c40..758565b266 100644
--- a/editor/register_editor_types.cpp
+++ b/editor/register_editor_types.cpp
@@ -65,6 +65,7 @@
#include "editor/plugins/cpu_particles_3d_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/editor_debugger_plugin.h"
+#include "editor/plugins/editor_resource_tooltip_plugins.h"
#include "editor/plugins/font_config_plugin.h"
#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
#include "editor/plugins/gpu_particles_3d_editor_plugin.h"
@@ -129,6 +130,7 @@ void register_editor_types() {
GDREGISTER_CLASS(EditorNode3DGizmo);
GDREGISTER_CLASS(EditorNode3DGizmoPlugin);
GDREGISTER_ABSTRACT_CLASS(EditorResourcePreview);
+ GDREGISTER_ABSTRACT_CLASS(EditorResourceTooltipPlugin);
GDREGISTER_CLASS(EditorResourcePreviewGenerator);
GDREGISTER_ABSTRACT_CLASS(EditorFileSystem);
GDREGISTER_CLASS(EditorFileSystemDirectory);