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