Add thumbnail mode to FIleDialog

This commit is contained in:
kobewi
2025-04-28 14:57:50 +02:00
parent e45cc68092
commit 706bfd810b
8 changed files with 140 additions and 5 deletions

View File

@ -137,6 +137,9 @@
The currently selected file path of the file dialog.
</member>
<member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" overrides="AcceptDialog" default="false" />
<member name="display_mode" type="int" setter="set_display_mode" getter="get_display_mode" enum="FileDialog.DisplayMode" default="0">
Display mode of the dialog's file list.
</member>
<member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="FileDialog.FileMode" default="4">
The dialog's open or save mode, which affects the selection behavior. See [enum FileMode].
</member>
@ -223,6 +226,12 @@
<constant name="ACCESS_FILESYSTEM" value="2" enum="Access">
The dialog allows accessing files on the whole file system.
</constant>
<constant name="DISPLAY_THUMBNAILS" value="0" enum="DisplayMode">
The dialog displays files as a grid of thumbnails. Use [theme_item thumbnail_size] to adjust their size.
</constant>
<constant name="DISPLAY_LIST" value="1" enum="DisplayMode">
The dialog displays files as a list of filenames.
</constant>
</constants>
<theme_items>
<theme_item name="file_disabled_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.25)">
@ -234,6 +243,9 @@
<theme_item name="folder_icon_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The color modulation applied to the folder icon.
</theme_item>
<theme_item name="thumbnail_size" data_type="constant" type="int" default="64">
The size of thumbnail icons when [constant DISPLAY_THUMBNAILS] is enabled.
</theme_item>
<theme_item name="back_folder" data_type="icon" type="Texture2D">
Custom icon for the back arrow.
</theme_item>
@ -252,12 +264,21 @@
<theme_item name="file" data_type="icon" type="Texture2D">
Custom icon for files.
</theme_item>
<theme_item name="file_thumbnail" data_type="icon" type="Texture2D">
Icon for files when in thumbnail mode.
</theme_item>
<theme_item name="folder" data_type="icon" type="Texture2D">
Custom icon for folders.
</theme_item>
<theme_item name="folder_thumbnail" data_type="icon" type="Texture2D">
Icon for folders when in thumbnail mode.
</theme_item>
<theme_item name="forward_folder" data_type="icon" type="Texture2D">
Custom icon for the forward arrow.
</theme_item>
<theme_item name="list_mode" data_type="icon" type="Texture2D">
Icon for the button that enables list mode.
</theme_item>
<theme_item name="parent_folder" data_type="icon" type="Texture2D">
Custom icon for the parent folder arrow.
</theme_item>
@ -267,6 +288,9 @@
<theme_item name="sort" data_type="icon" type="Texture2D">
Custom icon for the sorting options menu.
</theme_item>
<theme_item name="thumbnail_mode" data_type="icon" type="Texture2D">
Icon for the button that enables thumbnail mode.
</theme_item>
<theme_item name="toggle_filename_filter" data_type="icon" type="Texture2D">
Custom icon for the toggle button for the filter for file names.
</theme_item>

View File

@ -270,8 +270,10 @@ void FileDialog::_notification(int p_what) {
_setup_button(dir_up, theme_cache.parent_folder);
_setup_button(refresh_button, theme_cache.reload);
_setup_button(favorite_button, theme_cache.favorite);
_setup_button(show_hidden, theme_cache.toggle_hidden);
_setup_button(make_dir_button, theme_cache.create_folder);
_setup_button(show_hidden, theme_cache.toggle_hidden);
_setup_button(thumbnail_mode_button, theme_cache.thumbnail_mode);
_setup_button(list_mode_button, theme_cache.list_mode);
_setup_button(show_filename_filter_button, theme_cache.toggle_filename_filter);
_setup_button(file_sort_button, theme_cache.sort);
_setup_button(fav_up_button, theme_cache.favorite_up);
@ -761,8 +763,22 @@ void FileDialog::update_file_list() {
// Scroll back to the top after opening a directory
file_list->get_v_scroll_bar()->set_value(0);
dir_access->list_dir_begin();
if (display_mode == DISPLAY_THUMBNAILS) {
file_list->set_max_columns(0);
file_list->set_icon_mode(ItemList::ICON_MODE_TOP);
file_list->set_fixed_column_width(theme_cache.thumbnail_size * 3 / 2);
file_list->set_max_text_lines(2);
file_list->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
file_list->set_fixed_icon_size(Size2(theme_cache.thumbnail_size, theme_cache.thumbnail_size));
} else {
file_list->set_icon_mode(ItemList::ICON_MODE_LEFT);
file_list->set_max_columns(1);
file_list->set_max_text_lines(1);
file_list->set_fixed_column_width(0);
file_list->set_fixed_icon_size(Size2());
}
dir_access->list_dir_begin();
if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) {
message->hide();
} else {
@ -862,7 +878,11 @@ void FileDialog::update_file_list() {
}
for (const DirInfo &info : filtered_dirs) {
file_list->add_item(info.name, theme_cache.folder);
if (display_mode == DISPLAY_THUMBNAILS) {
file_list->add_item(info.name, theme_cache.folder_thumbnail);
} else {
file_list->add_item(info.name, theme_cache.folder);
}
file_list->set_item_icon_modulate(-1, theme_cache.folder_icon_color);
Dictionary d;
@ -924,8 +944,15 @@ void FileDialog::update_file_list() {
}
for (const FileInfo &info : filtered_files) {
const Ref<Texture2D> icon = get_icon_func ? get_icon_func(base_dir.path_join(info.name)) : theme_cache.file;
file_list->add_item(info.name, icon);
file_list->add_item(info.name);
if (get_icon_func) {
Ref<Texture2D> icon = get_icon_func(base_dir.path_join(info.name));
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);
if (mode == FILE_MODE_OPEN_DIR) {
@ -1274,6 +1301,27 @@ FileDialog::FileMode FileDialog::get_file_mode() const {
return mode;
}
void FileDialog::set_display_mode(DisplayMode p_mode) {
ERR_FAIL_INDEX((int)p_mode, 2);
if (display_mode == p_mode) {
return;
}
display_mode = p_mode;
if (p_mode == DISPLAY_THUMBNAILS) {
thumbnail_mode_button->set_pressed(true);
list_mode_button->set_pressed(false);
} else {
thumbnail_mode_button->set_pressed(false);
list_mode_button->set_pressed(true);
}
invalidate();
}
FileDialog::DisplayMode FileDialog::get_display_mode() const {
return display_mode;
}
void FileDialog::set_access(Access p_access) {
ERR_FAIL_INDEX(p_access, 3);
if (access == p_access) {
@ -1826,6 +1874,8 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_mode_overriding_title"), &FileDialog::is_mode_overriding_title);
ClassDB::bind_method(D_METHOD("set_file_mode", "mode"), &FileDialog::set_file_mode);
ClassDB::bind_method(D_METHOD("get_file_mode"), &FileDialog::get_file_mode);
ClassDB::bind_method(D_METHOD("set_display_mode", "mode"), &FileDialog::set_display_mode);
ClassDB::bind_method(D_METHOD("get_display_mode"), &FileDialog::get_display_mode);
ClassDB::bind_method(D_METHOD("get_vbox"), &FileDialog::get_vbox);
ClassDB::bind_method(D_METHOD("get_line_edit"), &FileDialog::get_line_edit);
ClassDB::bind_method(D_METHOD("set_access", "access"), &FileDialog::set_access);
@ -1842,6 +1892,7 @@ void FileDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_file_mode", "get_file_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"), "set_display_mode", "get_display_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
@ -1868,6 +1919,11 @@ void FileDialog::_bind_methods() {
BIND_ENUM_CONSTANT(ACCESS_USERDATA);
BIND_ENUM_CONSTANT(ACCESS_FILESYSTEM);
BIND_ENUM_CONSTANT(DISPLAY_THUMBNAILS);
BIND_ENUM_CONSTANT(DISPLAY_LIST);
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, FileDialog, thumbnail_size);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, parent_folder);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, forward_folder);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, back_folder);
@ -1881,6 +1937,10 @@ void FileDialog::_bind_methods() {
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, sort);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, favorite_up);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, favorite_down);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, thumbnail_mode);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, list_mode);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, file_thumbnail);
BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, folder_thumbnail);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, folder_icon_color);
BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, file_icon_color);
@ -2119,6 +2179,30 @@ FileDialog::FileDialog() {
lower_toolbar->add_child(memnew(VSeparator));
Ref<ButtonGroup> view_mode_group;
view_mode_group.instantiate();
thumbnail_mode_button = memnew(Button);
thumbnail_mode_button->set_toggle_mode(true);
thumbnail_mode_button->set_pressed(true);
thumbnail_mode_button->set_button_group(view_mode_group);
thumbnail_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
thumbnail_mode_button->set_accessibility_name(ETR("View as Thumbnails"));
thumbnail_mode_button->set_tooltip_text(ETR("View items as a grid of thumbnails."));
lower_toolbar->add_child(thumbnail_mode_button);
thumbnail_mode_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::set_display_mode).bind(DISPLAY_THUMBNAILS));
list_mode_button = memnew(Button);
list_mode_button->set_toggle_mode(true);
list_mode_button->set_button_group(view_mode_group);
list_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
list_mode_button->set_accessibility_name(ETR("View as List"));
list_mode_button->set_tooltip_text(ETR("View items as a list."));
lower_toolbar->add_child(list_mode_button);
list_mode_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::set_display_mode).bind(DISPLAY_LIST));
lower_toolbar->add_child(memnew(VSeparator));
show_filename_filter_button = memnew(Button);
show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton));
show_filename_filter_button->set_toggle_mode(true);

View File

@ -123,6 +123,11 @@ public:
FILE_MODE_SAVE_FILE,
};
enum DisplayMode {
DISPLAY_THUMBNAILS,
DISPLAY_LIST,
};
enum ItemMenu {
ITEM_MENU_COPY_PATH,
ITEM_MENU_SHOW_IN_EXPLORER,
@ -149,6 +154,7 @@ private:
Access access = ACCESS_RESOURCES;
FileMode mode = FILE_MODE_SAVE_FILE;
DisplayMode display_mode = DISPLAY_THUMBNAILS;
FileSortOption file_sort = FileSortOption::NAME;
Ref<DirAccess> dir_access;
@ -187,6 +193,8 @@ private:
Button *favorite_button = nullptr;
Button *make_dir_button = nullptr;
Button *show_hidden = nullptr;
Button *thumbnail_mode_button = nullptr;
Button *list_mode_button = nullptr;
Button *show_filename_filter_button = nullptr;
MenuButton *file_sort_button = nullptr;
@ -216,12 +224,16 @@ private:
ConfirmationDialog *confirm_save = nullptr;
struct ThemeCache {
int thumbnail_size = 64;
Ref<Texture2D> parent_folder;
Ref<Texture2D> forward_folder;
Ref<Texture2D> back_folder;
Ref<Texture2D> reload;
Ref<Texture2D> toggle_hidden;
Ref<Texture2D> toggle_filename_filter;
Ref<Texture2D> thumbnail_mode;
Ref<Texture2D> list_mode;
Ref<Texture2D> folder;
Ref<Texture2D> file;
Ref<Texture2D> create_folder;
@ -229,6 +241,8 @@ private:
Ref<Texture2D> favorite;
Ref<Texture2D> favorite_up;
Ref<Texture2D> favorite_down;
Ref<Texture2D> file_thumbnail;
Ref<Texture2D> folder_thumbnail;
Color folder_icon_color;
Color file_icon_color;
@ -369,6 +383,9 @@ public:
void set_file_mode(FileMode p_mode);
FileMode get_file_mode() const;
void set_display_mode(DisplayMode p_mode);
DisplayMode get_display_mode() const;
VBoxContainer *get_vbox() { return main_vbox; }
LineEdit *get_line_edit() { return filename_edit; }
@ -392,3 +409,4 @@ public:
VARIANT_ENUM_CAST(FileDialog::FileMode);
VARIANT_ENUM_CAST(FileDialog::Access);
VARIANT_ENUM_CAST(FileDialog::DisplayMode);

View File

@ -683,6 +683,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// File Dialog
theme->set_constant("thumbnail_size", "FileDialog", 64);
theme->set_icon("load", "FileDialog", icons["load"]);
theme->set_icon("save", "FileDialog", icons["save"]);
theme->set_icon("clear", "FileDialog", icons["clear"]);
@ -695,11 +696,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("toggle_filename_filter", "FileDialog", icons["toggle_filename_filter"]);
theme->set_icon("folder", "FileDialog", icons["folder"]);
theme->set_icon("file", "FileDialog", icons["file"]);
theme->set_icon("thumbnail_mode", "FileDialog", icons["file_mode_thumbnail"]);
theme->set_icon("list_mode", "FileDialog", icons["file_mode_list"]);
theme->set_icon("create_folder", "FileDialog", icons["folder_create"]);
theme->set_icon("sort", "FileDialog", icons["sort"]);
theme->set_icon("favorite_up", "FileDialog", icons["move_up"]);
theme->set_icon("favorite_down", "FileDialog", icons["move_down"]);
theme->set_icon("file_thumbnail", "FileDialog", icons["file_thumbnail"]);
theme->set_icon("folder_thumbnail", "FileDialog", icons["folder_thumbnail"]);
theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1));
theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1));
theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25));

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m2 2v2h2v-2zm4 0v2h8v-2zm-4 5v2h2v-2zm4 0v2h8v-2zm-4 5v2h2v-2zm4 0v2h8v-2z"/></svg>

After

Width:  |  Height:  |  Size: 171 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#e0e0e0" d="m2 2v5h5v-5zm7 0v5h5v-5zm-7 7v5h5v-5zm7 0v5h5v-5z"/></svg>

After

Width:  |  Height:  |  Size: 146 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path fill="#fff" fill-opacity=".6" d="M14 5a4 4 0 0 0-4 4v46a4 4 0 0 0 4 4h36a4 4 0 0 0 4-4V22a1 1 0 0 0-.29-.707l-16-16a1 1 0 0 0-.707-.29V5H14zm0 2h22v12a4 4 0 0 0 4 4h12v32a2 2 0 0 1-2 2H14a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2z"/></svg>

After

Width:  |  Height:  |  Size: 297 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path fill="#e0e0e0" d="M12 10a4 4 0 0 0-4 4v36a4 4 0 0 0 4 4h40a4 4 0 0 0 4-4V22a4 4 0 0 0-4-4H36l-2-4c-1-2-2-4-4-4z"/></svg>

After

Width:  |  Height:  |  Size: 190 B