Browse Source

Allow customizing FileDialog's features

kobewi 2 months ago
parent
commit
4b1d5b55c7
3 changed files with 171 additions and 18 deletions
  1. 64 0
      doc/classes/FileDialog.xml
  2. 81 18
      scene/gui/file_dialog.cpp
  3. 26 0
      scene/gui/file_dialog.h

+ 64 - 0
doc/classes/FileDialog.xml

@@ -96,6 +96,21 @@
 				[b]Note:[/b] This method does nothing on native file dialogs.
 				[b]Note:[/b] This method does nothing on native file dialogs.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="is_customization_flag_enabled" qualifiers="const">
+			<return type="bool" />
+			<param index="0" name="flag" type="int" enum="FileDialog.Customization" />
+			<description>
+				Returns [code]true[/code] if the provided [param flag] is enabled.
+			</description>
+		</method>
+		<method name="set_customization_flag_enabled">
+			<return type="void" />
+			<param index="0" name="flag" type="int" enum="FileDialog.Customization" />
+			<param index="1" name="enabled" type="bool" />
+			<description>
+				Toggles the specified customization [param flag], allowing to customize features available in this [FileDialog]. See [enum Customization] for options.
+			</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" />
@@ -140,9 +155,18 @@
 		<member name="display_mode" type="int" setter="set_display_mode" getter="get_display_mode" enum="FileDialog.DisplayMode" default="0">
 		<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.
 			Display mode of the dialog's file list.
 		</member>
 		</member>
+		<member name="favorites_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the toggle favorite button and favorite list on the left side of the dialog.
+		</member>
+		<member name="file_filter_toggle_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the toggle file filter button.
+		</member>
 		<member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="FileDialog.FileMode" default="4">
 		<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.
 			The dialog's open or save mode, which affects the selection behavior.
 		</member>
 		</member>
+		<member name="file_sort_options_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the file sorting options button.
+		</member>
 		<member name="filename_filter" type="String" setter="set_filename_filter" getter="get_filename_filter" default="&quot;&quot;">
 		<member name="filename_filter" type="String" setter="set_filename_filter" getter="get_filename_filter" default="&quot;&quot;">
 			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.
 			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.
 			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.
 			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.
 			[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.
 		</member>
 		</member>
+		<member name="folder_creation_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			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]).
+		</member>
+		<member name="hidden_files_toggle_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the toggle hidden files button.
+		</member>
+		<member name="layout_toggle_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the layout switch buttons (list/thumbnails).
+		</member>
 		<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
 		<member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true">
 			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").
 			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").
 		</member>
 		</member>
 		<member name="option_count" type="int" setter="set_option_count" getter="get_option_count" default="0">
 		<member name="option_count" type="int" setter="set_option_count" getter="get_option_count" default="0">
 			The number of additional [OptionButton]s and [CheckBox]es in the dialog.
 			The number of additional [OptionButton]s and [CheckBox]es in the dialog.
 		</member>
 		</member>
+		<member name="recent_list_enabled" type="bool" setter="set_customization_flag_enabled" getter="is_customization_flag_enabled" default="true">
+			If [code]true[/code], shows the recent directories list on the left side of the dialog.
+		</member>
 		<member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default="&quot;&quot;">
 		<member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default="&quot;&quot;">
 			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.
 			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.
 			[b]Note:[/b] This property is ignored by native file dialogs.
@@ -232,6 +268,34 @@
 		<constant name="DISPLAY_LIST" value="1" enum="DisplayMode">
 		<constant name="DISPLAY_LIST" value="1" enum="DisplayMode">
 			The dialog displays files as a list of filenames.
 			The dialog displays files as a list of filenames.
 		</constant>
 		</constant>
+		<constant name="CUSTOMIZATION_HIDDEN_FILES" value="0" enum="Customization">
+			Toggles visibility of the favorite button, and the favorite list on the left side of the dialog.
+			Equivalent to [member hidden_files_toggle_enabled].
+		</constant>
+		<constant name="CUSTOMIZATION_CREATE_FOLDER" value="1" enum="Customization">
+			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].
+		</constant>
+		<constant name="CUSTOMIZATION_FILE_FILTER" value="2" enum="Customization">
+			If enabled, shows the toggle file filter button.
+			Equivalent to [member file_filter_toggle_enabled].
+		</constant>
+		<constant name="CUSTOMIZATION_FILE_SORT" value="3" enum="Customization">
+			If enabled, shows the file sorting options button.
+			Equivalent to [member file_sort_options_enabled].
+		</constant>
+		<constant name="CUSTOMIZATION_FAVORITES" value="4" enum="Customization">
+			If enabled, shows the toggle favorite button and favorite list on the left side of the dialog.
+			Equivalent to [member favorites_enabled].
+		</constant>
+		<constant name="CUSTOMIZATION_RECENT" value="5" enum="Customization">
+			If enabled, shows the recent directories list on the left side of the dialog.
+			Equivalent to [member recent_list_enabled].
+		</constant>
+		<constant name="CUSTOMIZATION_LAYOUT" value="6" enum="Customization">
+			If enabled, shows the layout switch buttons (list/thumbnails).
+			Equivalent to [member layout_toggle_enabled].
+		</constant>
 	</constants>
 	</constants>
 	<theme_items>
 	<theme_items>
 		<theme_item name="file_disabled_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.25)">
 		<theme_item name="file_disabled_color" data_type="color" type="Color" default="Color(1, 1, 1, 0.25)">

+ 81 - 18
scene/gui/file_dialog.cpp

@@ -260,6 +260,9 @@ void FileDialog::_notification(int p_what) {
 		} break;
 		} break;
 
 
 		case NOTIFICATION_THEME_CHANGED: {
 		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()) {
 			if (main_vbox->is_layout_rtl()) {
 				_setup_button(dir_prev, theme_cache.forward_folder);
 				_setup_button(dir_prev, theme_cache.forward_folder);
 				_setup_button(dir_next, theme_cache.back_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");
 	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() {
 void FileDialog::clear_filename_filter() {
 	set_filename_filter("");
 	set_filename_filter("");
 	update_filename_filter_gui();
 	update_filename_filter_gui();
@@ -1256,21 +1272,18 @@ void FileDialog::set_file_mode(FileMode p_mode) {
 			if (mode_overrides_title) {
 			if (mode_overrides_title) {
 				set_title(ETR("Open a File"));
 				set_title(ETR("Open a File"));
 			}
 			}
-			make_dir_button->hide();
 			break;
 			break;
 		case FILE_MODE_OPEN_FILES:
 		case FILE_MODE_OPEN_FILES:
 			set_default_ok_text(ETR("Open"));
 			set_default_ok_text(ETR("Open"));
 			if (mode_overrides_title) {
 			if (mode_overrides_title) {
 				set_title(ETR("Open File(s)"));
 				set_title(ETR("Open File(s)"));
 			}
 			}
-			make_dir_button->hide();
 			break;
 			break;
 		case FILE_MODE_OPEN_DIR:
 		case FILE_MODE_OPEN_DIR:
 			set_default_ok_text(ETR("Select Current Folder"));
 			set_default_ok_text(ETR("Select Current Folder"));
 			if (mode_overrides_title) {
 			if (mode_overrides_title) {
 				set_title(ETR("Open a Directory"));
 				set_title(ETR("Open a Directory"));
 			}
 			}
-			make_dir_button->show();
 			break;
 			break;
 		case FILE_MODE_OPEN_ANY:
 		case FILE_MODE_OPEN_ANY:
 			set_default_ok_text(ETR("Open"));
 			set_default_ok_text(ETR("Open"));
@@ -1284,9 +1297,9 @@ void FileDialog::set_file_mode(FileMode p_mode) {
 			if (mode_overrides_title) {
 			if (mode_overrides_title) {
 				set_title(ETR("Save a File"));
 				set_title(ETR("Save a File"));
 			}
 			}
-			make_dir_button->show();
 			break;
 			break;
 	}
 	}
+	_update_make_dir_visible();
 
 
 	if (mode == FILE_MODE_OPEN_FILES) {
 	if (mode == FILE_MODE_OPEN_FILES) {
 		file_list->set_select_mode(ItemList::SELECT_MULTI);
 		file_list->set_select_mode(ItemList::SELECT_MULTI);
@@ -1322,6 +1335,20 @@ FileDialog::DisplayMode FileDialog::get_display_mode() const {
 	return display_mode;
 	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) {
 void FileDialog::set_access(Access p_access) {
 	ERR_FAIL_INDEX(p_access, 3);
 	ERR_FAIL_INDEX(p_access, 3);
 	if (access == p_access) {
 	if (access == p_access) {
@@ -1383,6 +1410,10 @@ void FileDialog::_setup_button(Button *p_button, const Ref<Texture2D> &p_icon) {
 	p_button->end_bulk_theme_override();
 	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 {
 FileDialog::Access FileDialog::get_access() const {
 	return access;
 	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("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("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("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("deselect_all"), &FileDialog::deselect_all);
 
 
 	ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
 	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::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::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename_filter"), "set_filename_filter", "get_filename_filter");
 	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, "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_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_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_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");
 	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_THUMBNAILS);
 	BIND_ENUM_CONSTANT(DISPLAY_LIST);
 	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, parent_folder);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, forward_folder);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, forward_folder);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, back_folder);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, back_folder);
@@ -2030,6 +2081,10 @@ FileDialog::FileDialog() {
 	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.
 
 
+	for (int i = 0; i < CUSTOMIZATION_MAX; i++) {
+		customization_flags[i] = true;
+	}
+
 	show_hidden_files = default_show_hidden_files;
 	show_hidden_files = default_show_hidden_files;
 	dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
 	dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
 
 
@@ -2097,13 +2152,16 @@ FileDialog::FileDialog() {
 	top_toolbar->add_child(favorite_button);
 	top_toolbar->add_child(favorite_button);
 	favorite_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_favorite_pressed));
 	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 = memnew(Button);
 	make_dir_button->set_theme_type_variation(SceneStringName(FlatButton));
 	make_dir_button->set_theme_type_variation(SceneStringName(FlatButton));
 	make_dir_button->set_accessibility_name(ETR("Create New Folder"));
 	make_dir_button->set_accessibility_name(ETR("Create New Folder"));
 	make_dir_button->set_tooltip_text(ETR("Create a 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));
 	make_dir_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_make_dir));
 
 
 	HSplitContainer *main_split = memnew(HSplitContainer);
 	HSplitContainer *main_split = memnew(HSplitContainer);
@@ -2114,12 +2172,12 @@ FileDialog::FileDialog() {
 		VSplitContainer *fav_split = memnew(VSplitContainer);
 		VSplitContainer *fav_split = memnew(VSplitContainer);
 		main_split->add_child(fav_split);
 		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);
 		HBoxContainer *fav_hbox = memnew(HBoxContainer);
-		fav_vbox->add_child(fav_hbox);
+		favorite_vbox->add_child(fav_hbox);
 
 
 		{
 		{
 			Label *label = memnew(Label(ETR("Favorites:")));
 			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_v_size_flags(Control::SIZE_EXPAND_FILL);
 		favorite_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
 		favorite_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
 		favorite_list->set_accessibility_name(ETR("Favorites"));
 		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));
 		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);
 		recent_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 		fav_split->add_child(recent_vbox);
 		fav_split->add_child(recent_vbox);
 
 
@@ -2183,7 +2241,11 @@ FileDialog::FileDialog() {
 	lower_toolbar->add_child(show_hidden);
 	lower_toolbar->add_child(show_hidden);
 	show_hidden->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_hidden_files));
 	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<ButtonGroup> view_mode_group;
 	Ref<ButtonGroup> view_mode_group;
 	view_mode_group.instantiate();
 	view_mode_group.instantiate();
@@ -2195,7 +2257,7 @@ FileDialog::FileDialog() {
 	thumbnail_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
 	thumbnail_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
 	thumbnail_mode_button->set_accessibility_name(ETR("View as Thumbnails"));
 	thumbnail_mode_button->set_accessibility_name(ETR("View as Thumbnails"));
 	thumbnail_mode_button->set_tooltip_text(ETR("View items as a grid of 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));
 	thumbnail_mode_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::set_display_mode).bind(DISPLAY_THUMBNAILS));
 
 
 	list_mode_button = memnew(Button);
 	list_mode_button = memnew(Button);
@@ -2204,10 +2266,11 @@ FileDialog::FileDialog() {
 	list_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
 	list_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
 	list_mode_button->set_accessibility_name(ETR("View as List"));
 	list_mode_button->set_accessibility_name(ETR("View as List"));
 	list_mode_button->set_tooltip_text(ETR("View items as a 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));
 	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 = memnew(Button);
 	show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton));
 	show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton));

+ 26 - 0
scene/gui/file_dialog.h

@@ -43,6 +43,7 @@ class MenuButton;
 class OptionButton;
 class OptionButton;
 class PopupMenu;
 class PopupMenu;
 class VBoxContainer;
 class VBoxContainer;
+class VSeparator;
 
 
 class FileDialog : public ConfirmationDialog {
 class FileDialog : public ConfirmationDialog {
 	GDCLASS(FileDialog, ConfirmationDialog);
 	GDCLASS(FileDialog, ConfirmationDialog);
@@ -134,6 +135,17 @@ public:
 		ITEM_MENU_SHOW_BUNDLE_CONTENT,
 		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<Texture2D> (*GetIconFunc)(const String &);
 	typedef Ref<Texture2D> (*GetIconFunc)(const String &);
 	typedef void (*RegisterFunc)(FileDialog *);
 	typedef void (*RegisterFunc)(FileDialog *);
 
 
@@ -148,6 +160,7 @@ private:
 	inline static bool default_show_hidden_files = false;
 	inline static bool default_show_hidden_files = false;
 	bool show_hidden_files = false;
 	bool show_hidden_files = false;
 	bool use_native_dialog = false;
 	bool use_native_dialog = false;
+	bool customization_flags[CUSTOMIZATION_MAX]; // Initialized to true in the constructor.
 
 
 	inline static LocalVector<String> global_favorites;
 	inline static LocalVector<String> global_favorites;
 	inline static LocalVector<String> global_recents;
 	inline static LocalVector<String> global_recents;
@@ -191,16 +204,23 @@ private:
 
 
 	Button *refresh_button = nullptr;
 	Button *refresh_button = nullptr;
 	Button *favorite_button = nullptr;
 	Button *favorite_button = nullptr;
+	HBoxContainer *make_dir_container = nullptr;
 	Button *make_dir_button = nullptr;
 	Button *make_dir_button = nullptr;
+
 	Button *show_hidden = nullptr;
 	Button *show_hidden = nullptr;
+	VSeparator *show_hidden_separator = nullptr;
+	HBoxContainer *layout_container = nullptr;
+	VSeparator *layout_separator = nullptr;
 	Button *thumbnail_mode_button = nullptr;
 	Button *thumbnail_mode_button = nullptr;
 	Button *list_mode_button = nullptr;
 	Button *list_mode_button = nullptr;
 	Button *show_filename_filter_button = nullptr;
 	Button *show_filename_filter_button = nullptr;
 	MenuButton *file_sort_button = nullptr;
 	MenuButton *file_sort_button = nullptr;
 
 
+	VBoxContainer *favorite_vbox = nullptr;
 	Button *fav_up_button = nullptr;
 	Button *fav_up_button = nullptr;
 	Button *fav_down_button = nullptr;
 	Button *fav_down_button = nullptr;
 	ItemList *favorite_list = nullptr;
 	ItemList *favorite_list = nullptr;
+	VBoxContainer *recent_vbox = nullptr;
 	ItemList *recent_list = nullptr;
 	ItemList *recent_list = nullptr;
 
 
 	ItemList *file_list = nullptr;
 	ItemList *file_list = nullptr;
@@ -260,6 +280,7 @@ private:
 	void update_filename_filter();
 	void update_filename_filter();
 	void update_filename_filter_gui();
 	void update_filename_filter_gui();
 	void update_filters();
 	void update_filters();
+	void update_customization();
 
 
 	void _item_menu_id_pressed(int p_option);
 	void _item_menu_id_pressed(int p_option);
 	void _empty_clicked(const Vector2 &p_pos, MouseButton p_button);
 	void _empty_clicked(const Vector2 &p_pos, MouseButton p_button);
@@ -307,6 +328,7 @@ private:
 
 
 	void _invalidate();
 	void _invalidate();
 	void _setup_button(Button *p_button, const Ref<Texture2D> &p_icon);
 	void _setup_button(Button *p_button, const Ref<Texture2D> &p_icon);
+	void _update_make_dir_visible();
 
 
 	virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
 	virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
 
 
@@ -386,6 +408,9 @@ public:
 	void set_display_mode(DisplayMode p_mode);
 	void set_display_mode(DisplayMode p_mode);
 	DisplayMode get_display_mode() const;
 	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; }
 	VBoxContainer *get_vbox() { return main_vbox; }
 	LineEdit *get_line_edit() { return filename_edit; }
 	LineEdit *get_line_edit() { return filename_edit; }
 
 
@@ -410,3 +435,4 @@ public:
 VARIANT_ENUM_CAST(FileDialog::FileMode);
 VARIANT_ENUM_CAST(FileDialog::FileMode);
 VARIANT_ENUM_CAST(FileDialog::Access);
 VARIANT_ENUM_CAST(FileDialog::Access);
 VARIANT_ENUM_CAST(FileDialog::DisplayMode);
 VARIANT_ENUM_CAST(FileDialog::DisplayMode);
+VARIANT_ENUM_CAST(FileDialog::Customization);