diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index 7989b357067..d5784d1e473 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -137,6 +137,9 @@
The currently selected file path of the file dialog.
+
+ Display mode of the dialog's file list.
+
The dialog's open or save mode, which affects the selection behavior. See [enum FileMode].
@@ -223,6 +226,12 @@
The dialog allows accessing files on the whole file system.
+
+ The dialog displays files as a grid of thumbnails. Use [theme_item thumbnail_size] to adjust their size.
+
+
+ The dialog displays files as a list of filenames.
+
@@ -234,6 +243,9 @@
The color modulation applied to the folder icon.
+
+ The size of thumbnail icons when [constant DISPLAY_THUMBNAILS] is enabled.
+
Custom icon for the back arrow.
@@ -252,12 +264,21 @@
Custom icon for files.
+
+ Icon for files when in thumbnail mode.
+
Custom icon for folders.
+
+ Icon for folders when in thumbnail mode.
+
Custom icon for the forward arrow.
+
+ Icon for the button that enables list mode.
+
Custom icon for the parent folder arrow.
@@ -267,6 +288,9 @@
Custom icon for the sorting options menu.
+
+ Icon for the button that enables thumbnail mode.
+
Custom icon for the toggle button for the filter for file names.
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index e0c28206dc8..249254b1571 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -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 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 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 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);
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 4b6e64c086d..e2670a998e7 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -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 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 parent_folder;
Ref forward_folder;
Ref back_folder;
Ref reload;
Ref toggle_hidden;
Ref toggle_filename_filter;
+ Ref thumbnail_mode;
+ Ref list_mode;
Ref folder;
Ref file;
Ref create_folder;
@@ -229,6 +241,8 @@ private:
Ref favorite;
Ref favorite_up;
Ref favorite_down;
+ Ref file_thumbnail;
+ Ref 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);
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index 641853cf6e4..3e99b3ae835 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -683,6 +683,7 @@ void fill_default_theme(Ref &theme, const Ref &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, const Ref &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));
diff --git a/scene/theme/icons/file_mode_list.svg b/scene/theme/icons/file_mode_list.svg
new file mode 100644
index 00000000000..11ce82897e3
--- /dev/null
+++ b/scene/theme/icons/file_mode_list.svg
@@ -0,0 +1 @@
+
diff --git a/scene/theme/icons/file_mode_thumbnail.svg b/scene/theme/icons/file_mode_thumbnail.svg
new file mode 100644
index 00000000000..b99c109771b
--- /dev/null
+++ b/scene/theme/icons/file_mode_thumbnail.svg
@@ -0,0 +1 @@
+
diff --git a/scene/theme/icons/file_thumbnail.svg b/scene/theme/icons/file_thumbnail.svg
new file mode 100644
index 00000000000..034f8b8a0d2
--- /dev/null
+++ b/scene/theme/icons/file_thumbnail.svg
@@ -0,0 +1 @@
+
diff --git a/scene/theme/icons/folder_thumbnail.svg b/scene/theme/icons/folder_thumbnail.svg
new file mode 100644
index 00000000000..db256910a3e
--- /dev/null
+++ b/scene/theme/icons/folder_thumbnail.svg
@@ -0,0 +1 @@
+