diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index a016ba794a..a436767d4a 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -96,6 +96,21 @@ [b]Note:[/b] This method does nothing on native file dialogs. + + + + + Returns [code]true[/code] if the provided [param flag] is enabled. + + + + + + + + Toggles the specified customization [param flag], allowing to customize features available in this [FileDialog]. See [enum Customization] for options. + + @@ -140,9 +155,18 @@ Display mode of the dialog's file list. + + If [code]true[/code], shows the toggle favorite button and favorite list on the left side of the dialog. + + + If [code]true[/code], shows the toggle file filter button. + The dialog's open or save mode, which affects the selection behavior. + + If [code]true[/code], shows the file sorting options button. + The filter for file names (case-insensitive). When set to a non-empty string, only files that contains the substring will be shown. [member filename_filter] can be edited by the user with the filter button at the top of the file dialog. See also [member filters], which should be used to restrict the file types that can be selected instead of [member filename_filter] which is meant to be set by the user. @@ -151,12 +175,24 @@ The available file type filters. Each filter string in the array should be formatted like this: [code]*.png,*.jpg,*.jpeg;Image Files;image/png,image/jpeg[/code]. The description text of the filter is optional and can be omitted. Both file extensions and MIME type should be always set. [b]Note:[/b] Embedded file dialog and Windows file dialog support only file extensions, while Android, Linux, and macOS file dialogs also support MIME types. + + If [code]true[/code], shows the button for creating new directories (when using [constant FILE_MODE_OPEN_DIR], [constant FILE_MODE_OPEN_ANY], or [constant FILE_MODE_SAVE_FILE]). + + + If [code]true[/code], shows the toggle hidden files button. + + + If [code]true[/code], shows the layout switch buttons (list/thumbnails). + If [code]true[/code], changing the [member file_mode] property will set the window title accordingly (e.g. setting [member file_mode] to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File"). The number of additional [OptionButton]s and [CheckBox]es in the dialog. + + If [code]true[/code], shows the recent directories list on the left side of the dialog. + If non-empty, the given sub-folder will be "root" of this [FileDialog], i.e. user won't be able to go to its parent directory. [b]Note:[/b] This property is ignored by native file dialogs. @@ -232,6 +268,34 @@ The dialog displays files as a list of filenames. + + Toggles visibility of the favorite button, and the favorite list on the left side of the dialog. + Equivalent to [member hidden_files_toggle_enabled]. + + + If enabled, shows the button for creating new directories (when using [constant FILE_MODE_OPEN_DIR], [constant FILE_MODE_OPEN_ANY], or [constant FILE_MODE_SAVE_FILE]). + Equivalent to [member folder_creation_enabled]. + + + If enabled, shows the toggle file filter button. + Equivalent to [member file_filter_toggle_enabled]. + + + If enabled, shows the file sorting options button. + Equivalent to [member file_sort_options_enabled]. + + + If enabled, shows the toggle favorite button and favorite list on the left side of the dialog. + Equivalent to [member favorites_enabled]. + + + If enabled, shows the recent directories list on the left side of the dialog. + Equivalent to [member recent_list_enabled]. + + + If enabled, shows the layout switch buttons (list/thumbnails). + Equivalent to [member layout_toggle_enabled]. + diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index fb8a737d77..c4b7373347 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -260,6 +260,9 @@ void FileDialog::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: { + favorite_list->set_custom_minimum_size(Vector2(128 * get_theme_default_base_scale(), 0)); + recent_list->set_custom_minimum_size(Vector2(128 * get_theme_default_base_scale(), 0)); + if (main_vbox->is_layout_rtl()) { _setup_button(dir_prev, theme_cache.forward_folder); _setup_button(dir_next, theme_cache.back_folder); @@ -1104,6 +1107,19 @@ void FileDialog::update_filters() { processed_filters.push_back("*.*;" + f + ";application/octet-stream"); } +void FileDialog::update_customization() { + _update_make_dir_visible(); + show_hidden->set_visible(customization_flags[CUSTOMIZATION_HIDDEN_FILES]); + layout_container->set_visible(customization_flags[CUSTOMIZATION_LAYOUT]); + layout_separator->set_visible(customization_flags[CUSTOMIZATION_FILE_FILTER] || customization_flags[CUSTOMIZATION_FILE_SORT]); + show_filename_filter_button->set_visible(customization_flags[CUSTOMIZATION_FILE_FILTER]); + file_sort_button->set_visible(customization_flags[CUSTOMIZATION_FILE_SORT]); + show_hidden_separator->set_visible(customization_flags[CUSTOMIZATION_HIDDEN_FILES] && (customization_flags[CUSTOMIZATION_LAYOUT] || customization_flags[CUSTOMIZATION_FILE_FILTER] || customization_flags[CUSTOMIZATION_FILE_SORT])); + favorite_button->set_visible(customization_flags[CUSTOMIZATION_FAVORITES]); + favorite_vbox->set_visible(customization_flags[CUSTOMIZATION_FAVORITES]); + recent_vbox->set_visible(customization_flags[CUSTOMIZATION_RECENT]); +} + void FileDialog::clear_filename_filter() { set_filename_filter(""); update_filename_filter_gui(); @@ -1256,21 +1272,18 @@ void FileDialog::set_file_mode(FileMode p_mode) { if (mode_overrides_title) { set_title(ETR("Open a File")); } - make_dir_button->hide(); break; case FILE_MODE_OPEN_FILES: set_default_ok_text(ETR("Open")); if (mode_overrides_title) { set_title(ETR("Open File(s)")); } - make_dir_button->hide(); break; case FILE_MODE_OPEN_DIR: set_default_ok_text(ETR("Select Current Folder")); if (mode_overrides_title) { set_title(ETR("Open a Directory")); } - make_dir_button->show(); break; case FILE_MODE_OPEN_ANY: set_default_ok_text(ETR("Open")); @@ -1284,9 +1297,9 @@ void FileDialog::set_file_mode(FileMode p_mode) { if (mode_overrides_title) { set_title(ETR("Save a File")); } - make_dir_button->show(); break; } + _update_make_dir_visible(); if (mode == FILE_MODE_OPEN_FILES) { file_list->set_select_mode(ItemList::SELECT_MULTI); @@ -1322,6 +1335,20 @@ FileDialog::DisplayMode FileDialog::get_display_mode() const { return display_mode; } +void FileDialog::set_customization_flag_enabled(Customization p_flag, bool p_enabled) { + ERR_FAIL_INDEX(p_flag, CUSTOMIZATION_MAX); + if (customization_flags[p_flag] == p_enabled) { + return; + } + customization_flags[p_flag] = p_enabled; + update_customization(); +} + +bool FileDialog::is_customization_flag_enabled(Customization p_flag) const { + ERR_FAIL_INDEX_V(p_flag, CUSTOMIZATION_MAX, false); + return customization_flags[p_flag]; +} + void FileDialog::set_access(Access p_access) { ERR_FAIL_INDEX(p_access, 3); if (access == p_access) { @@ -1383,6 +1410,10 @@ void FileDialog::_setup_button(Button *p_button, const Ref &p_icon) { p_button->end_bulk_theme_override(); } +void FileDialog::_update_make_dir_visible() { + make_dir_container->set_visible(customization_flags[CUSTOMIZATION_CREATE_FOLDER] && mode != FILE_MODE_OPEN_FILE && mode != FILE_MODE_OPEN_FILES); +} + FileDialog::Access FileDialog::get_access() const { return access; } @@ -1886,6 +1917,8 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("is_showing_hidden_files"), &FileDialog::is_showing_hidden_files); ClassDB::bind_method(D_METHOD("set_use_native_dialog", "native"), &FileDialog::set_use_native_dialog); ClassDB::bind_method(D_METHOD("get_use_native_dialog"), &FileDialog::get_use_native_dialog); + ClassDB::bind_method(D_METHOD("set_customization_flag_enabled", "flag", "enabled"), &FileDialog::set_customization_flag_enabled); + ClassDB::bind_method(D_METHOD("is_customization_flag_enabled", "flag"), &FileDialog::is_customization_flag_enabled); ClassDB::bind_method(D_METHOD("deselect_all"), &FileDialog::deselect_all); ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate); @@ -1897,9 +1930,20 @@ void FileDialog::_bind_methods() { 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"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename_filter"), "set_filename_filter", "get_filename_filter"); - ADD_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_native_dialog"), "set_use_native_dialog", "get_use_native_dialog"); + + ADD_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_"); + + ADD_GROUP("Customization", ""); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "hidden_files_toggle_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_HIDDEN_FILES); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "file_filter_toggle_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_FILE_FILTER); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "file_sort_options_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_FILE_SORT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "folder_creation_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_CREATE_FOLDER); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "favorites_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_FAVORITES); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "recent_list_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_RECENT); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "layout_toggle_enabled"), "set_customization_flag_enabled", "is_customization_flag_enabled", CUSTOMIZATION_LAYOUT); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*", PROPERTY_USAGE_NONE), "set_current_file", "get_current_file"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_path", "get_current_path"); @@ -1922,8 +1966,15 @@ void FileDialog::_bind_methods() { BIND_ENUM_CONSTANT(DISPLAY_THUMBNAILS); BIND_ENUM_CONSTANT(DISPLAY_LIST); - BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, FileDialog, thumbnail_size); + BIND_ENUM_CONSTANT(CUSTOMIZATION_HIDDEN_FILES); + BIND_ENUM_CONSTANT(CUSTOMIZATION_CREATE_FOLDER); + BIND_ENUM_CONSTANT(CUSTOMIZATION_FILE_FILTER); + BIND_ENUM_CONSTANT(CUSTOMIZATION_FILE_SORT); + BIND_ENUM_CONSTANT(CUSTOMIZATION_FAVORITES); + BIND_ENUM_CONSTANT(CUSTOMIZATION_RECENT); + BIND_ENUM_CONSTANT(CUSTOMIZATION_LAYOUT); + 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); @@ -2030,6 +2081,10 @@ FileDialog::FileDialog() { set_size(Size2(640, 360)); set_default_ok_text(ETR("Save")); // Default mode text. + for (int i = 0; i < CUSTOMIZATION_MAX; i++) { + customization_flags[i] = true; + } + show_hidden_files = default_show_hidden_files; dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); @@ -2097,13 +2152,16 @@ FileDialog::FileDialog() { top_toolbar->add_child(favorite_button); favorite_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_favorite_pressed)); - top_toolbar->add_child(memnew(VSeparator)); + make_dir_container = memnew(HBoxContainer); + top_toolbar->add_child(make_dir_container); + + make_dir_container->add_child(memnew(VSeparator)); make_dir_button = memnew(Button); make_dir_button->set_theme_type_variation(SceneStringName(FlatButton)); make_dir_button->set_accessibility_name(ETR("Create New Folder")); make_dir_button->set_tooltip_text(ETR("Create a new folder.")); - top_toolbar->add_child(make_dir_button); + make_dir_container->add_child(make_dir_button); make_dir_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_make_dir)); HSplitContainer *main_split = memnew(HSplitContainer); @@ -2114,12 +2172,12 @@ FileDialog::FileDialog() { VSplitContainer *fav_split = memnew(VSplitContainer); main_split->add_child(fav_split); - VBoxContainer *fav_vbox = memnew(VBoxContainer); - fav_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); - fav_split->add_child(fav_vbox); + favorite_vbox = memnew(VBoxContainer); + favorite_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); + fav_split->add_child(favorite_vbox); HBoxContainer *fav_hbox = memnew(HBoxContainer); - fav_vbox->add_child(fav_hbox); + favorite_vbox->add_child(fav_hbox); { Label *label = memnew(Label(ETR("Favorites:"))); @@ -2141,10 +2199,10 @@ FileDialog::FileDialog() { favorite_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); favorite_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); favorite_list->set_accessibility_name(ETR("Favorites")); - fav_vbox->add_child(favorite_list); + favorite_vbox->add_child(favorite_list); favorite_list->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_favorite_selected)); - VBoxContainer *recent_vbox = memnew(VBoxContainer); + recent_vbox = memnew(VBoxContainer); recent_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); fav_split->add_child(recent_vbox); @@ -2183,7 +2241,11 @@ FileDialog::FileDialog() { lower_toolbar->add_child(show_hidden); show_hidden->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_hidden_files)); - lower_toolbar->add_child(memnew(VSeparator)); + show_hidden_separator = memnew(VSeparator); + lower_toolbar->add_child(show_hidden_separator); + + layout_container = memnew(HBoxContainer); + lower_toolbar->add_child(layout_container); Ref view_mode_group; view_mode_group.instantiate(); @@ -2195,7 +2257,7 @@ FileDialog::FileDialog() { 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); + layout_container->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); @@ -2204,10 +2266,11 @@ FileDialog::FileDialog() { 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); + layout_container->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)); + layout_separator = memnew(VSeparator); + layout_container->add_child(layout_separator); show_filename_filter_button = memnew(Button); show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton)); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index e2670a998e..f69356f019 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -43,6 +43,7 @@ class MenuButton; class OptionButton; class PopupMenu; class VBoxContainer; +class VSeparator; class FileDialog : public ConfirmationDialog { GDCLASS(FileDialog, ConfirmationDialog); @@ -134,6 +135,17 @@ public: ITEM_MENU_SHOW_BUNDLE_CONTENT, }; + enum Customization { + CUSTOMIZATION_HIDDEN_FILES, + CUSTOMIZATION_CREATE_FOLDER, + CUSTOMIZATION_FILE_FILTER, + CUSTOMIZATION_FILE_SORT, + CUSTOMIZATION_FAVORITES, + CUSTOMIZATION_RECENT, + CUSTOMIZATION_LAYOUT, + CUSTOMIZATION_MAX + }; + typedef Ref (*GetIconFunc)(const String &); typedef void (*RegisterFunc)(FileDialog *); @@ -148,6 +160,7 @@ private: inline static bool default_show_hidden_files = false; bool show_hidden_files = false; bool use_native_dialog = false; + bool customization_flags[CUSTOMIZATION_MAX]; // Initialized to true in the constructor. inline static LocalVector global_favorites; inline static LocalVector global_recents; @@ -191,16 +204,23 @@ private: Button *refresh_button = nullptr; Button *favorite_button = nullptr; + HBoxContainer *make_dir_container = nullptr; Button *make_dir_button = nullptr; + Button *show_hidden = nullptr; + VSeparator *show_hidden_separator = nullptr; + HBoxContainer *layout_container = nullptr; + VSeparator *layout_separator = nullptr; Button *thumbnail_mode_button = nullptr; Button *list_mode_button = nullptr; Button *show_filename_filter_button = nullptr; MenuButton *file_sort_button = nullptr; + VBoxContainer *favorite_vbox = nullptr; Button *fav_up_button = nullptr; Button *fav_down_button = nullptr; ItemList *favorite_list = nullptr; + VBoxContainer *recent_vbox = nullptr; ItemList *recent_list = nullptr; ItemList *file_list = nullptr; @@ -260,6 +280,7 @@ private: void update_filename_filter(); void update_filename_filter_gui(); void update_filters(); + void update_customization(); void _item_menu_id_pressed(int p_option); void _empty_clicked(const Vector2 &p_pos, MouseButton p_button); @@ -307,6 +328,7 @@ private: void _invalidate(); void _setup_button(Button *p_button, const Ref &p_icon); + void _update_make_dir_visible(); virtual void shortcut_input(const Ref &p_event) override; @@ -386,6 +408,9 @@ public: void set_display_mode(DisplayMode p_mode); DisplayMode get_display_mode() const; + void set_customization_flag_enabled(Customization p_flag, bool p_enabled); + bool is_customization_flag_enabled(Customization p_flag) const; + VBoxContainer *get_vbox() { return main_vbox; } LineEdit *get_line_edit() { return filename_edit; } @@ -410,3 +435,4 @@ public: VARIANT_ENUM_CAST(FileDialog::FileMode); VARIANT_ENUM_CAST(FileDialog::Access); VARIANT_ENUM_CAST(FileDialog::DisplayMode); +VARIANT_ENUM_CAST(FileDialog::Customization);