Enhance filesystem dock tooltips

This commit is contained in:
kobewi 2022-07-20 23:44:06 +02:00
parent 20ed51a912
commit 27dccf1b5e
10 changed files with 337 additions and 10 deletions

View File

@ -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">

View File

@ -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>

View File

@ -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">

View File

@ -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() {

View File

@ -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);

View File

@ -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() {

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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

View File

@ -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);