Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance filesystem dock tooltips #63263

Merged
merged 1 commit into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/classes/EditorResourcePreviewGenerator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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">
Expand Down
46 changes: 46 additions & 0 deletions doc/classes/EditorResourceTooltipPlugin.xml
Original file line number Diff line number Diff line change
@@ -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>
14 changes: 14 additions & 0 deletions doc/classes/FileSystemDock.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,27 @@
<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" />
<description>
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">
Expand Down
6 changes: 3 additions & 3 deletions editor/editor_resource_preview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion editor/editor_resource_preview.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class EditorResourcePreview : public Node {
// 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);
Expand Down
62 changes: 60 additions & 2 deletions editor/filesystem_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,35 @@
#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"
#include "scene/gui/item_list.h"
#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) {
Expand Down Expand Up @@ -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;
KoBeWi marked this conversation as resolved.
Show resolved Hide resolved
}

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;
Expand Down Expand Up @@ -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")));

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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() {
Expand Down
19 changes: 17 additions & 2 deletions editor/filesystem_dock.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -189,14 +198,16 @@ class FileSystemDock : public VBoxContainer {

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

Expand Down Expand Up @@ -351,6 +362,10 @@ class FileSystemDock : public VBoxContainer {

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();
};
Expand Down
122 changes: 122 additions & 0 deletions editor/plugins/editor_resource_tooltip_plugins.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
Loading