mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Merge pull request #108147 from KoBeWi/set_get_is_back
Expose FileDialog callbacks for getting custom icons
This commit is contained in:
commit
45dfd4dd23
6 changed files with 138 additions and 13 deletions
|
@ -131,6 +131,34 @@
|
||||||
[b]Note:[/b] [FileDialog] will update its internal [ItemList] of favorites when its visibility changes. Be sure to call this method earlier if you want your changes to have effect.
|
[b]Note:[/b] [FileDialog] will update its internal [ItemList] of favorites when its visibility changes. Be sure to call this method earlier if you want your changes to have effect.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="set_get_icon_callback" qualifiers="static">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="callback" type="Callable" />
|
||||||
|
<description>
|
||||||
|
Sets the callback used by the [FileDialog] nodes to get a file icon, when [constant DISPLAY_LIST] mode is used. The callback should take a single [String] argument (file path), and return a [Texture2D]. If an invalid texture is returned, the [theme_item file] icon will be used instead.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="set_get_thumbnail_callback" qualifiers="static">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="callback" type="Callable" />
|
||||||
|
<description>
|
||||||
|
Sets the callback used by the [FileDialog] nodes to get a file icon, when [constant DISPLAY_THUMBNAILS] mode is used. The callback should take a single [String] argument (file path), and return a [Texture2D]. If an invalid texture is returned, the [theme_item file_thumbnail] icon will be used instead.
|
||||||
|
Thumbnails are usually more complex and may take a while to load. To avoid stalling the application, you can use [ImageTexture] to asynchronously create the thumbnail.
|
||||||
|
[codeblock]
|
||||||
|
func _ready():
|
||||||
|
FileDialog.set_get_thumbnail_callback(thumbnail_method)
|
||||||
|
|
||||||
|
func thumbnail_method(path):
|
||||||
|
var image_texture = ImageTexture.new()
|
||||||
|
make_thumbnail_async(path, image_texture)
|
||||||
|
return image_texture
|
||||||
|
|
||||||
|
func make_thumbnail_async(path, image_texture):
|
||||||
|
var thumbnail_texture = await generate_thumbnail(path) # Some method that generates a thumbnail.
|
||||||
|
image_texture.set_image(thumbnail_texture.get_image())
|
||||||
|
[/codeblock]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="set_option_default">
|
<method name="set_option_default">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="option" type="int" />
|
<param index="0" name="option" type="int" />
|
||||||
|
|
|
@ -687,6 +687,10 @@ void EditorNode::_update_theme(bool p_skip_creation) {
|
||||||
_update_renderer_color();
|
_update_renderer_color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<Texture2D> thumbnail_icon = gui_base->get_theme_icon(SNAME("file_thumbnail"), SNAME("FileDialog"));
|
||||||
|
default_thumbnail.instantiate();
|
||||||
|
default_thumbnail->set_image(thumbnail_icon->get_image());
|
||||||
|
|
||||||
editor_dock_manager->update_tab_styles();
|
editor_dock_manager->update_tab_styles();
|
||||||
editor_dock_manager->update_docks_menu();
|
editor_dock_manager->update_docks_menu();
|
||||||
editor_dock_manager->set_tab_icon_max_width(theme->get_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
|
editor_dock_manager->set_tab_icon_max_width(theme->get_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
|
||||||
|
@ -5625,6 +5629,19 @@ Ref<Texture2D> EditorNode::_file_dialog_get_icon(const String &p_path) {
|
||||||
return singleton->icon_type_cache["Object"];
|
return singleton->icon_type_cache["Object"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<Texture2D> EditorNode::_file_dialog_get_thumbnail(const String &p_path) {
|
||||||
|
Ref<ImageTexture> texture = singleton->default_thumbnail->duplicate();
|
||||||
|
EditorResourcePreview::get_singleton()->queue_resource_preview(p_path, callable_mp_static(EditorNode::_file_dialog_thumbnail_callback).bind(texture));
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorNode::_file_dialog_thumbnail_callback(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Ref<ImageTexture> p_texture) {
|
||||||
|
ERR_FAIL_COND(p_texture.is_null());
|
||||||
|
if (p_preview.is_valid()) {
|
||||||
|
p_texture->set_image(p_preview->get_image());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode::_build_icon_type_cache() {
|
void EditorNode::_build_icon_type_cache() {
|
||||||
List<StringName> tl;
|
List<StringName> tl;
|
||||||
theme->get_icon_list(EditorStringName(EditorIcons), &tl);
|
theme->get_icon_list(EditorStringName(EditorIcons), &tl);
|
||||||
|
@ -7817,7 +7834,8 @@ EditorNode::EditorNode() {
|
||||||
EditorContextMenuPluginManager::create();
|
EditorContextMenuPluginManager::create();
|
||||||
|
|
||||||
// Used for previews.
|
// Used for previews.
|
||||||
FileDialog::get_icon_func = _file_dialog_get_icon;
|
FileDialog::set_get_icon_callback(callable_mp_static(_file_dialog_get_icon));
|
||||||
|
FileDialog::set_get_thumbnail_callback(callable_mp_static(_file_dialog_get_thumbnail));
|
||||||
FileDialog::register_func = _file_dialog_register;
|
FileDialog::register_func = _file_dialog_register;
|
||||||
FileDialog::unregister_func = _file_dialog_unregister;
|
FileDialog::unregister_func = _file_dialog_unregister;
|
||||||
|
|
||||||
|
@ -8919,7 +8937,6 @@ EditorNode::~EditorNode() {
|
||||||
GDExtensionEditorPlugins::editor_node_add_plugin = nullptr;
|
GDExtensionEditorPlugins::editor_node_add_plugin = nullptr;
|
||||||
GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr;
|
GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr;
|
||||||
|
|
||||||
FileDialog::get_icon_func = nullptr;
|
|
||||||
FileDialog::register_func = nullptr;
|
FileDialog::register_func = nullptr;
|
||||||
FileDialog::unregister_func = nullptr;
|
FileDialog::unregister_func = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ class ConfirmationDialog;
|
||||||
class Control;
|
class Control;
|
||||||
class FileDialog;
|
class FileDialog;
|
||||||
class HBoxContainer;
|
class HBoxContainer;
|
||||||
|
class ImageTexture;
|
||||||
class MenuBar;
|
class MenuBar;
|
||||||
class MenuButton;
|
class MenuButton;
|
||||||
class OptionButton;
|
class OptionButton;
|
||||||
|
@ -512,6 +513,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ref<Texture2D> _file_dialog_get_icon(const String &p_path);
|
static Ref<Texture2D> _file_dialog_get_icon(const String &p_path);
|
||||||
|
static Ref<Texture2D> _file_dialog_get_thumbnail(const String &p_path);
|
||||||
|
static void _file_dialog_thumbnail_callback(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Ref<ImageTexture> p_texture);
|
||||||
|
Ref<ImageTexture> default_thumbnail;
|
||||||
|
|
||||||
static void _file_dialog_register(FileDialog *p_dialog);
|
static void _file_dialog_register(FileDialog *p_dialog);
|
||||||
static void _file_dialog_unregister(FileDialog *p_dialog);
|
static void _file_dialog_unregister(FileDialog *p_dialog);
|
||||||
static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
|
static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
|
||||||
|
|
|
@ -577,6 +577,24 @@ bool FileDialog::_is_open_should_be_disabled() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileDialog::_thumbnail_callback(const Ref<Texture2D> &p_texture, const String &p_path) {
|
||||||
|
if (display_mode == DISPLAY_LIST || p_texture.is_null()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p_path.begins_with(full_dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String file_name = p_path.get_file();
|
||||||
|
for (int i = 0; i < file_list->get_item_count(); i++) {
|
||||||
|
if (file_list->get_item_text(i) == file_name) {
|
||||||
|
file_list->set_item_icon(i, p_texture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FileDialog::_go_up() {
|
void FileDialog::_go_up() {
|
||||||
_change_dir("..");
|
_change_dir("..");
|
||||||
_push_history();
|
_push_history();
|
||||||
|
@ -778,7 +796,7 @@ void FileDialog::update_file_list() {
|
||||||
file_list->set_max_columns(1);
|
file_list->set_max_columns(1);
|
||||||
file_list->set_max_text_lines(1);
|
file_list->set_max_text_lines(1);
|
||||||
file_list->set_fixed_column_width(0);
|
file_list->set_fixed_column_width(0);
|
||||||
file_list->set_fixed_icon_size(Size2());
|
file_list->set_fixed_icon_size(theme_cache.file->get_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
dir_access->list_dir_begin();
|
dir_access->list_dir_begin();
|
||||||
|
@ -948,13 +966,44 @@ void FileDialog::update_file_list() {
|
||||||
|
|
||||||
for (const FileInfo &info : filtered_files) {
|
for (const FileInfo &info : filtered_files) {
|
||||||
file_list->add_item(info.name);
|
file_list->add_item(info.name);
|
||||||
if (get_icon_func) {
|
const String path = base_dir.path_join(info.name);
|
||||||
Ref<Texture2D> icon = get_icon_func(base_dir.path_join(info.name));
|
|
||||||
|
if (display_mode == DISPLAY_LIST) {
|
||||||
|
Ref<Texture2D> icon;
|
||||||
|
if (get_icon_callback.is_valid()) {
|
||||||
|
const Variant &v = path;
|
||||||
|
const Variant *argptrs[1] = { &v };
|
||||||
|
Variant vicon;
|
||||||
|
|
||||||
|
Callable::CallError ce;
|
||||||
|
get_icon_callback.callp(argptrs, 1, vicon, ce);
|
||||||
|
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||||
|
ERR_PRINT(vformat("Error calling FileDialog's icon callback: %s.", Variant::get_callable_error_text(get_icon_callback, argptrs, 1, ce)));
|
||||||
|
}
|
||||||
|
icon = vicon;
|
||||||
|
}
|
||||||
|
if (icon.is_null()) {
|
||||||
|
icon = theme_cache.file;
|
||||||
|
}
|
||||||
|
file_list->set_item_icon(-1, icon);
|
||||||
|
} else { // DISPLAY_THUMBNAILS
|
||||||
|
Ref<Texture2D> icon;
|
||||||
|
if (get_thumbnail_callback.is_valid()) {
|
||||||
|
const Variant &v = path;
|
||||||
|
const Variant *argptrs[1] = { &v };
|
||||||
|
Variant vicon;
|
||||||
|
|
||||||
|
Callable::CallError ce;
|
||||||
|
get_thumbnail_callback.callp(argptrs, 1, vicon, ce);
|
||||||
|
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
|
||||||
|
ERR_PRINT(vformat("Error calling FileDialog's thumbnail callback: %s.", Variant::get_callable_error_text(get_thumbnail_callback, argptrs, 1, ce)));
|
||||||
|
}
|
||||||
|
icon = vicon;
|
||||||
|
}
|
||||||
|
if (icon.is_null()) {
|
||||||
|
icon = theme_cache.file;
|
||||||
|
}
|
||||||
file_list->set_item_icon(-1, icon);
|
file_list->set_item_icon(-1, icon);
|
||||||
} else if (display_mode == DISPLAY_THUMBNAILS) {
|
|
||||||
file_list->set_item_icon(-1, theme_cache.file_thumbnail);
|
|
||||||
} else {
|
|
||||||
file_list->set_item_icon(-1, theme_cache.file);
|
|
||||||
}
|
}
|
||||||
file_list->set_item_icon_modulate(-1, theme_cache.file_icon_color);
|
file_list->set_item_icon_modulate(-1, theme_cache.file_icon_color);
|
||||||
|
|
||||||
|
@ -1983,6 +2032,8 @@ void FileDialog::_bind_methods() {
|
||||||
ClassDB::bind_static_method("FileDialog", D_METHOD("get_favorite_list"), &FileDialog::get_favorite_list);
|
ClassDB::bind_static_method("FileDialog", D_METHOD("get_favorite_list"), &FileDialog::get_favorite_list);
|
||||||
ClassDB::bind_static_method("FileDialog", D_METHOD("set_recent_list", "recents"), &FileDialog::set_recent_list);
|
ClassDB::bind_static_method("FileDialog", D_METHOD("set_recent_list", "recents"), &FileDialog::set_recent_list);
|
||||||
ClassDB::bind_static_method("FileDialog", D_METHOD("get_recent_list"), &FileDialog::get_recent_list);
|
ClassDB::bind_static_method("FileDialog", D_METHOD("get_recent_list"), &FileDialog::get_recent_list);
|
||||||
|
ClassDB::bind_static_method("FileDialog", D_METHOD("set_get_icon_callback", "callback"), &FileDialog::set_get_icon_callback);
|
||||||
|
ClassDB::bind_static_method("FileDialog", D_METHOD("set_get_thumbnail_callback", "callback"), &FileDialog::set_get_thumbnail_callback);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
|
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
|
||||||
|
|
||||||
|
@ -2118,6 +2169,14 @@ void FileDialog::set_default_show_hidden_files(bool p_show) {
|
||||||
default_show_hidden_files = p_show;
|
default_show_hidden_files = p_show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileDialog::set_get_icon_callback(const Callable &p_callback) {
|
||||||
|
get_icon_callback = p_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileDialog::set_get_thumbnail_callback(const Callable &p_callback) {
|
||||||
|
get_thumbnail_callback = p_callback;
|
||||||
|
}
|
||||||
|
|
||||||
void FileDialog::set_use_native_dialog(bool p_native) {
|
void FileDialog::set_use_native_dialog(bool p_native) {
|
||||||
use_native_dialog = p_native;
|
use_native_dialog = p_native;
|
||||||
|
|
||||||
|
@ -2143,6 +2202,7 @@ FileDialog::FileDialog() {
|
||||||
set_hide_on_ok(false);
|
set_hide_on_ok(false);
|
||||||
set_size(Size2(640, 360));
|
set_size(Size2(640, 360));
|
||||||
set_default_ok_text(ETR("Save")); // Default mode text.
|
set_default_ok_text(ETR("Save")); // Default mode text.
|
||||||
|
thumbnail_callback = callable_mp(this, &FileDialog::_thumbnail_callback);
|
||||||
|
|
||||||
for (int i = 0; i < CUSTOMIZATION_MAX; i++) {
|
for (int i = 0; i < CUSTOMIZATION_MAX; i++) {
|
||||||
customization_flags[i] = true;
|
customization_flags[i] = true;
|
||||||
|
|
|
@ -146,10 +146,11 @@ public:
|
||||||
CUSTOMIZATION_MAX
|
CUSTOMIZATION_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Ref<Texture2D> (*GetIconFunc)(const String &);
|
|
||||||
typedef void (*RegisterFunc)(FileDialog *);
|
typedef void (*RegisterFunc)(FileDialog *);
|
||||||
|
|
||||||
inline static GetIconFunc get_icon_func = nullptr;
|
inline static Callable get_icon_callback;
|
||||||
|
inline static Callable get_thumbnail_callback;
|
||||||
|
|
||||||
inline static RegisterFunc register_func = nullptr;
|
inline static RegisterFunc register_func = nullptr;
|
||||||
inline static RegisterFunc unregister_func = nullptr;
|
inline static RegisterFunc unregister_func = nullptr;
|
||||||
|
|
||||||
|
@ -189,6 +190,7 @@ private:
|
||||||
String root_prefix;
|
String root_prefix;
|
||||||
String full_dir;
|
String full_dir;
|
||||||
|
|
||||||
|
Callable thumbnail_callback;
|
||||||
bool is_invalidating = false;
|
bool is_invalidating = false;
|
||||||
|
|
||||||
VBoxContainer *main_vbox = nullptr;
|
VBoxContainer *main_vbox = nullptr;
|
||||||
|
@ -338,6 +340,7 @@ private:
|
||||||
void _native_dialog_cb_with_options(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options);
|
void _native_dialog_cb_with_options(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options);
|
||||||
|
|
||||||
bool _is_open_should_be_disabled();
|
bool _is_open_should_be_disabled();
|
||||||
|
void _thumbnail_callback(const Ref<Texture2D> &p_texture, const String &p_path);
|
||||||
|
|
||||||
TypedArray<Dictionary> _get_options() const;
|
TypedArray<Dictionary> _get_options() const;
|
||||||
void _update_option_controls();
|
void _update_option_controls();
|
||||||
|
@ -430,6 +433,9 @@ public:
|
||||||
|
|
||||||
static void set_default_show_hidden_files(bool p_show);
|
static void set_default_show_hidden_files(bool p_show);
|
||||||
|
|
||||||
|
static void set_get_icon_callback(const Callable &p_callback);
|
||||||
|
static void set_get_thumbnail_callback(const Callable &p_callback);
|
||||||
|
|
||||||
void invalidate();
|
void invalidate();
|
||||||
|
|
||||||
void deselect_all();
|
void deselect_all();
|
||||||
|
|
|
@ -208,11 +208,20 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
|
||||||
}
|
}
|
||||||
ERR_FAIL_INDEX(p_idx, items.size());
|
ERR_FAIL_INDEX(p_idx, items.size());
|
||||||
|
|
||||||
if (items[p_idx].icon == p_icon) {
|
Item &item = items.write[p_idx];
|
||||||
|
if (item.icon == p_icon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
items.write[p_idx].icon = p_icon;
|
const Callable redraw = callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw);
|
||||||
|
if (item.icon.is_valid()) {
|
||||||
|
item.icon->disconnect_changed(redraw);
|
||||||
|
}
|
||||||
|
item.icon = p_icon;
|
||||||
|
if (p_icon.is_valid()) {
|
||||||
|
p_icon->connect_changed(redraw);
|
||||||
|
}
|
||||||
|
|
||||||
queue_redraw();
|
queue_redraw();
|
||||||
shape_changed = true;
|
shape_changed = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue