Sfoglia il codice sorgente

FileDialog code cleanup

kobewi 3 mesi fa
parent
commit
e565ee86ce
3 ha cambiato i file con 246 aggiunte e 266 eliminazioni
  1. 1 0
      editor/export/export_template_manager.cpp
  2. 176 205
      scene/gui/file_dialog.cpp
  3. 69 61
      scene/gui/file_dialog.h

+ 1 - 0
editor/export/export_template_manager.cpp

@@ -45,6 +45,7 @@
 #include "scene/gui/file_dialog.h"
 #include "scene/gui/link_button.h"
 #include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
 #include "scene/gui/separator.h"
 #include "scene/gui/tree.h"
 #include "scene/main/http_request.h"

+ 176 - 205
scene/gui/file_dialog.cpp

@@ -31,29 +31,28 @@
 #include "file_dialog.h"
 
 #include "core/config/project_settings.h"
+#include "core/io/dir_access.h"
 #include "core/os/keyboard.h"
+#include "scene/gui/box_container.h"
 #include "scene/gui/check_box.h"
 #include "scene/gui/grid_container.h"
 #include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
 #include "scene/gui/option_button.h"
+#include "scene/gui/tree.h"
 #include "scene/theme/theme_db.h"
 
-FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr;
-
-FileDialog::RegisterFunc FileDialog::register_func = nullptr;
-FileDialog::RegisterFunc FileDialog::unregister_func = nullptr;
-
 void FileDialog::popup_file_dialog() {
 	popup_centered_clamped(Size2i(700, 500), 0.8f);
 	_focus_file_text();
 }
 
 void FileDialog::_focus_file_text() {
-	int lp = file->get_text().rfind_char('.');
+	int lp = filename_edit->get_text().rfind_char('.');
 	if (lp != -1) {
-		file->select(0, lp);
-		if (file->is_inside_tree() && !is_part_of_edited_scene()) {
-			file->grab_focus();
+		filename_edit->select(0, lp);
+		if (filename_edit->is_inside_tree() && !is_part_of_edited_scene()) {
+			filename_edit->grab_focus();
 		}
 	}
 }
@@ -77,9 +76,9 @@ void FileDialog::_native_popup() {
 	DisplayServer::WindowID wid = w ? w->get_window_id() : DisplayServer::INVALID_WINDOW_ID;
 
 	if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_EXTRA)) {
-		DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(full_dir), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb_with_options), wid);
+		DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(full_dir), root, filename_edit->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb_with_options), wid);
 	} else {
-		DisplayServer::get_singleton()->file_dialog_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(full_dir), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, callable_mp(this, &FileDialog::_native_dialog_cb), wid);
+		DisplayServer::get_singleton()->file_dialog_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(full_dir), filename_edit->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, callable_mp(this, &FileDialog::_native_dialog_cb), wid);
 	}
 }
 
@@ -134,7 +133,7 @@ void FileDialog::_native_dialog_cb(bool p_ok, const Vector<String> &p_files, int
 
 void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options) {
 	if (!p_ok) {
-		file->set_text("");
+		filename_edit->set_text("");
 		emit_signal(SNAME("canceled"));
 		return;
 	}
@@ -153,8 +152,8 @@ void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector<String>
 
 	String f = files[0];
 	filter->select(p_filter);
-	dir->set_text(f.get_base_dir());
-	file->set_text(f.get_file());
+	directory_edit->set_text(f.get_base_dir());
+	filename_edit->set_text(f.get_file());
 	_change_dir(f.get_base_dir());
 
 	if (mode == FILE_MODE_OPEN_FILES) {
@@ -199,7 +198,7 @@ void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector<String>
 					if (!valid && filter_slice_count > 0) {
 						String str = flt.get_slicec(',', 0).strip_edges();
 						f += str.substr(1);
-						file->set_text(f.get_file());
+						filename_edit->set_text(f.get_file());
 						valid = true;
 					}
 				} else {
@@ -223,10 +222,6 @@ void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector<String>
 	}
 }
 
-VBoxContainer *FileDialog::get_vbox() {
-	return vbox;
-}
-
 void FileDialog::_validate_property(PropertyInfo &p_property) const {
 	if (p_property.name == "dialog_text") {
 		// File dialogs have a custom layout, and dialog nodes can't have both a text and a layout.
@@ -259,68 +254,18 @@ void FileDialog::_notification(int p_what) {
 		} break;
 
 		case NOTIFICATION_THEME_CHANGED: {
-			dir_up->set_button_icon(theme_cache.parent_folder);
-			if (vbox->is_layout_rtl()) {
-				dir_prev->set_button_icon(theme_cache.forward_folder);
-				dir_next->set_button_icon(theme_cache.back_folder);
+			if (main_vbox->is_layout_rtl()) {
+				_setup_button(dir_prev, theme_cache.forward_folder);
+				_setup_button(dir_next, theme_cache.back_folder);
 			} else {
-				dir_prev->set_button_icon(theme_cache.back_folder);
-				dir_next->set_button_icon(theme_cache.forward_folder);
+				_setup_button(dir_prev, theme_cache.back_folder);
+				_setup_button(dir_next, theme_cache.forward_folder);
 			}
-			refresh->set_button_icon(theme_cache.reload);
-			show_hidden->set_button_icon(theme_cache.toggle_hidden);
-			makedir->set_button_icon(theme_cache.create_folder);
-			show_filename_filter_button->set_button_icon(theme_cache.toggle_filename_filter);
-
-			dir_up->begin_bulk_theme_override();
-			dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			dir_up->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			dir_up->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			dir_up->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			dir_up->end_bulk_theme_override();
-
-			dir_prev->begin_bulk_theme_override();
-			dir_prev->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			dir_prev->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			dir_prev->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			dir_prev->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			dir_prev->end_bulk_theme_override();
-
-			dir_next->begin_bulk_theme_override();
-			dir_next->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			dir_next->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			dir_next->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			dir_next->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			dir_next->end_bulk_theme_override();
-
-			refresh->begin_bulk_theme_override();
-			refresh->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			refresh->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			refresh->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			refresh->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			refresh->end_bulk_theme_override();
-
-			show_hidden->begin_bulk_theme_override();
-			show_hidden->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			show_hidden->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			show_hidden->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			show_hidden->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			show_hidden->end_bulk_theme_override();
-
-			makedir->begin_bulk_theme_override();
-			makedir->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			makedir->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			makedir->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			makedir->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			makedir->end_bulk_theme_override();
-
-			show_filename_filter_button->begin_bulk_theme_override();
-			show_filename_filter_button->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color);
-			show_filename_filter_button->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color);
-			show_filename_filter_button->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color);
-			show_filename_filter_button->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
-			show_filename_filter_button->end_bulk_theme_override();
-
+			_setup_button(dir_up, theme_cache.parent_folder);
+			_setup_button(refresh_button, theme_cache.reload);
+			_setup_button(show_hidden, theme_cache.toggle_hidden);
+			_setup_button(make_dir_button, theme_cache.create_folder);
+			_setup_button(show_filename_filter_button, theme_cache.toggle_filename_filter);
 			invalidate();
 		} break;
 
@@ -365,8 +310,8 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
 				// Cmd + Shift + G (matches Finder's "Go To" shortcut).
 				case Key::G: {
 					if (k->is_command_or_control_pressed() && k->is_shift_pressed()) {
-						dir->grab_focus();
-						dir->select_all();
+						directory_edit->grab_focus();
+						directory_edit->select_all();
 					} else {
 						handled = false;
 					}
@@ -376,8 +321,8 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
 				// plus macOS Safari's "focus on address bar" shortcut).
 				case Key::L: {
 					if (k->is_command_or_control_pressed()) {
-						dir->grab_focus();
-						dir->select_all();
+						directory_edit->grab_focus();
+						directory_edit->select_all();
 					} else {
 						handled = false;
 					}
@@ -414,9 +359,9 @@ Vector<String> FileDialog::get_selected_files() const {
 void FileDialog::update_dir() {
 	full_dir = dir_access->get_current_dir();
 	if (root_prefix.is_empty()) {
-		dir->set_text(dir_access->get_current_dir(false));
+		directory_edit->set_text(dir_access->get_current_dir(false));
 	} else {
-		dir->set_text(dir_access->get_current_dir(false).trim_prefix(root_prefix).trim_prefix("/"));
+		directory_edit->set_text(dir_access->get_current_dir(false).trim_prefix(root_prefix).trim_prefix("/"));
 	}
 
 	if (drives->is_visible()) {
@@ -446,7 +391,7 @@ void FileDialog::_dir_submitted(String p_dir) {
 		new_dir = root_prefix.path_join(new_dir);
 	}
 	_change_dir(new_dir);
-	file->set_text("");
+	filename_edit->set_text("");
 	_push_history();
 }
 
@@ -455,7 +400,7 @@ void FileDialog::_file_submitted(const String &p_file) {
 }
 
 void FileDialog::_save_confirm_pressed() {
-	String f = dir_access->get_current_dir().path_join(file->get_text());
+	String f = dir_access->get_current_dir().path_join(filename_edit->get_text());
 	emit_signal(SNAME("file_selected"), f);
 	hide();
 }
@@ -463,7 +408,7 @@ void FileDialog::_save_confirm_pressed() {
 void FileDialog::_post_popup() {
 	ConfirmationDialog::_post_popup();
 	if (mode == FILE_MODE_SAVE_FILE) {
-		file->grab_focus();
+		filename_edit->grab_focus();
 	} else {
 		tree->grab_focus();
 	}
@@ -513,7 +458,7 @@ void FileDialog::_action_pressed() {
 		return;
 	}
 
-	String file_text = file->get_text();
+	String file_text = filename_edit->get_text();
 	String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
 
 	if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && (dir_access->file_exists(f) || dir_access->is_bundle(f))) {
@@ -574,7 +519,7 @@ void FileDialog::_action_pressed() {
 				if (!valid && filter_slice_count > 0) {
 					String str = flt.get_slicec(',', 0).strip_edges();
 					f += str.substr(1);
-					file->set_text(f.get_file());
+					filename_edit->set_text(f.get_file());
 					valid = true;
 				}
 			} else {
@@ -599,7 +544,7 @@ void FileDialog::_action_pressed() {
 }
 
 void FileDialog::_cancel_pressed() {
-	file->set_text("");
+	filename_edit->set_text("");
 	invalidate();
 	hide();
 }
@@ -696,14 +641,14 @@ void FileDialog::_tree_selected() {
 	Dictionary d = ti->get_metadata(0);
 
 	if (!d["dir"]) {
-		file->set_text(d["name"]);
+		filename_edit->set_text(d["name"]);
 		if (mode == FILE_MODE_SAVE_FILE) {
 			set_internal_ok_text(ETR("Save"));
 		} else {
 			set_internal_ok_text(ETR("Open"));
 		}
-	} else if (mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY || !dir_access->file_exists(file->get_text())) {
-		file->set_text("");
+	} else if (mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY || !dir_access->file_exists(filename_edit->get_text())) {
+		filename_edit->set_text("");
 		if (mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) {
 			set_internal_ok_text(ETR("Select This Folder"));
 		}
@@ -723,7 +668,7 @@ void FileDialog::_tree_item_activated() {
 	if (d["dir"]) {
 		_change_dir(d["name"]);
 		if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) {
-			file->set_text("");
+			filename_edit->set_text("");
 		}
 		_push_history();
 	} else {
@@ -738,7 +683,7 @@ void FileDialog::update_file_name() {
 			idx += 1;
 		}
 		String filter_str = filters[idx];
-		String file_str = file->get_text();
+		String file_str = filename_edit->get_text();
 		String base_name = file_str.get_basename();
 		Vector<String> filter_substr = filter_str.split(";");
 		if (filter_substr.size() >= 2) {
@@ -746,7 +691,7 @@ void FileDialog::update_file_name() {
 		} else {
 			file_str = base_name + "." + filter_str.strip_edges().get_extension().to_lower();
 		}
-		file->set_text(file_str);
+		filename_edit->set_text(file_str);
 	}
 }
 
@@ -773,7 +718,7 @@ void FileDialog::_item_menu_id_pressed(int p_option) {
 			Dictionary d = ti->get_metadata(0);
 			_change_dir(d["name"]);
 			if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) {
-				file->set_text("");
+				filename_edit->set_text("");
 			}
 			_push_history();
 		} break;
@@ -959,7 +904,7 @@ void FileDialog::update_file_list() {
 			d["bundle"] = false;
 			ti->set_metadata(0, d);
 
-			if (file->get_text() == files.front()->get() || match_str == files.front()->get()) {
+			if (filename_edit->get_text() == files.front()->get() || match_str == files.front()->get()) {
 				ti->select(0);
 			}
 		}
@@ -997,8 +942,8 @@ void FileDialog::_tree_select_first() {
 void FileDialog::_filename_filter_selected() {
 	TreeItem *item = tree->get_selected();
 	if (item) {
-		file->set_text(item->get_text(0));
-		file->emit_signal(SceneStringName(text_submitted), file->get_text());
+		filename_edit->set_text(item->get_text(0));
+		filename_edit->emit_signal(SceneStringName(text_submitted), filename_edit->get_text());
 	}
 }
 
@@ -1160,11 +1105,11 @@ String FileDialog::get_current_dir() const {
 }
 
 String FileDialog::get_current_file() const {
-	return file->get_text();
+	return filename_edit->get_text();
 }
 
 String FileDialog::get_current_path() const {
-	return full_dir.path_join(file->get_text());
+	return full_dir.path_join(filename_edit->get_text());
 }
 
 void FileDialog::set_current_dir(const String &p_dir) {
@@ -1174,10 +1119,10 @@ void FileDialog::set_current_dir(const String &p_dir) {
 }
 
 void FileDialog::set_current_file(const String &p_file) {
-	if (file->get_text() == p_file) {
+	if (filename_edit->get_text() == p_file) {
 		return;
 	}
-	file->set_text(p_file);
+	filename_edit->set_text(p_file);
 	update_dir();
 	invalidate();
 	_focus_file_text();
@@ -1239,35 +1184,35 @@ void FileDialog::set_file_mode(FileMode p_mode) {
 			if (mode_overrides_title) {
 				set_title(ETR("Open a File"));
 			}
-			makedir->hide();
+			make_dir_button->hide();
 			break;
 		case FILE_MODE_OPEN_FILES:
 			set_internal_ok_text(ETR("Open"));
 			if (mode_overrides_title) {
 				set_title(ETR("Open File(s)"));
 			}
-			makedir->hide();
+			make_dir_button->hide();
 			break;
 		case FILE_MODE_OPEN_DIR:
 			set_internal_ok_text(ETR("Select Current Folder"));
 			if (mode_overrides_title) {
 				set_title(ETR("Open a Directory"));
 			}
-			makedir->show();
+			make_dir_button->show();
 			break;
 		case FILE_MODE_OPEN_ANY:
 			set_internal_ok_text(ETR("Open"));
 			if (mode_overrides_title) {
 				set_title(ETR("Open a File or Directory"));
 			}
-			makedir->show();
+			make_dir_button->show();
 			break;
 		case FILE_MODE_SAVE_FILE:
 			set_internal_ok_text(ETR("Save"));
 			if (mode_overrides_title) {
 				set_title(ETR("Save a File"));
 			}
-			makedir->show();
+			make_dir_button->show();
 			break;
 	}
 
@@ -1332,31 +1277,42 @@ void FileDialog::_invalidate() {
 	is_invalidating = false;
 }
 
+void FileDialog::_setup_button(Button *p_button, const Ref<Texture2D> &p_icon) {
+	p_button->set_button_icon(p_icon);
+
+	p_button->begin_bulk_theme_override();
+	p_button->add_theme_color_override(SNAME("icon_normal_color"), theme_cache.icon_normal_color);
+	p_button->add_theme_color_override(SNAME("icon_hover_color"), theme_cache.icon_hover_color);
+	p_button->add_theme_color_override(SNAME("icon_focus_color"), theme_cache.icon_focus_color);
+	p_button->add_theme_color_override(SNAME("icon_pressed_color"), theme_cache.icon_pressed_color);
+	p_button->end_bulk_theme_override();
+}
+
 FileDialog::Access FileDialog::get_access() const {
 	return access;
 }
 
 void FileDialog::_make_dir_confirm() {
-	Error err = dir_access->make_dir(makedirname->get_text().strip_edges());
+	Error err = dir_access->make_dir(new_dir_name->get_text().strip_edges());
 	if (err == OK) {
-		_change_dir(makedirname->get_text().strip_edges());
+		_change_dir(new_dir_name->get_text().strip_edges());
 		update_filters();
 		_push_history();
 	} else {
 		mkdirerr->popup_centered(Size2(250, 50));
 	}
-	makedirname->set_text(""); // reset label
+	new_dir_name->set_text(""); // reset label
 }
 
 void FileDialog::_make_dir() {
-	makedialog->popup_centered(Size2(250, 80));
-	makedirname->grab_focus();
+	make_dir_dialog->popup_centered(Size2(250, 80));
+	new_dir_name->grab_focus();
 }
 
 void FileDialog::_select_drive(int p_idx) {
 	String d = drives->get_item_text(p_idx);
 	_change_dir(d);
-	file->set_text("");
+	filename_edit->set_text("");
 	_push_history();
 }
 
@@ -1400,8 +1356,6 @@ void FileDialog::_update_drives(bool p_select) {
 	}
 }
 
-bool FileDialog::default_show_hidden_files = false;
-
 TypedArray<Dictionary> FileDialog::_get_options() const {
 	TypedArray<Dictionary> out;
 	for (const FileDialog::Option &opt : options) {
@@ -1722,58 +1676,70 @@ bool FileDialog::get_use_native_dialog() const {
 }
 
 FileDialog::FileDialog() {
-	show_hidden_files = default_show_hidden_files;
+	set_title(ETR("Save a File"));
+	set_hide_on_ok(false);
+	set_size(Size2(640, 360));
+	set_internal_ok_text(ETR("Save")); // Default mode text.
 
-	vbox = memnew(VBoxContainer);
-	add_child(vbox, false, INTERNAL_MODE_FRONT);
+	show_hidden_files = default_show_hidden_files;
+	dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
 
-	mode = FILE_MODE_SAVE_FILE;
-	set_title(TTRC("Save a File"));
+	main_vbox = memnew(VBoxContainer);
+	add_child(main_vbox, false, INTERNAL_MODE_FRONT);
 
-	HBoxContainer *hbc = memnew(HBoxContainer);
+	HBoxContainer *top_toolbar = memnew(HBoxContainer);
+	main_vbox->add_child(top_toolbar);
 
 	dir_prev = memnew(Button);
 	dir_prev->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_prev->set_accessibility_name(ETR("Previous"));
 	dir_prev->set_tooltip_text(ETR("Go to previous folder."));
+	top_toolbar->add_child(dir_prev);
+	dir_prev->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_back));
+
 	dir_next = memnew(Button);
 	dir_next->set_accessibility_name(ETR("Next"));
 	dir_next->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_next->set_tooltip_text(ETR("Go to next folder."));
+	top_toolbar->add_child(dir_next);
+	dir_next->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_forward));
+
 	dir_up = memnew(Button);
 	dir_up->set_accessibility_name(ETR("Parent Folder"));
 	dir_up->set_theme_type_variation(SceneStringName(FlatButton));
 	dir_up->set_tooltip_text(ETR("Go to parent folder."));
-	hbc->add_child(dir_prev);
-	hbc->add_child(dir_next);
-	hbc->add_child(dir_up);
-	dir_prev->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_back));
-	dir_next->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_forward));
+	top_toolbar->add_child(dir_up);
 	dir_up->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_up));
 
-	Label *lbl_path = memnew(Label(ETR("Path:")));
-	hbc->add_child(lbl_path);
+	{
+		Label *label = memnew(Label(ETR("Path:")));
+		top_toolbar->add_child(label);
+	}
 
 	drives_container = memnew(HBoxContainer);
-	hbc->add_child(drives_container);
+	top_toolbar->add_child(drives_container);
 
 	drives = memnew(OptionButton);
 	drives->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_select_drive));
 	drives->set_accessibility_name(ETR("Drive"));
-	hbc->add_child(drives);
+	top_toolbar->add_child(drives);
 
-	dir = memnew(LineEdit);
-	dir->set_accessibility_name(ETR("Directory Path"));
-	dir->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
-	hbc->add_child(dir);
-	dir->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+	directory_edit = memnew(LineEdit);
+	directory_edit->set_accessibility_name(ETR("Directory Path"));
+	directory_edit->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
+	directory_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+	top_toolbar->add_child(directory_edit);
+	directory_edit->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_dir_submitted));
 
-	refresh = memnew(Button);
-	refresh->set_theme_type_variation(SceneStringName(FlatButton));
-	refresh->set_accessibility_name(ETR("Refresh"));
-	refresh->set_tooltip_text(ETR("Refresh files."));
-	refresh->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::update_file_list));
-	hbc->add_child(refresh);
+	shortcuts_container = memnew(HBoxContainer);
+	top_toolbar->add_child(shortcuts_container);
+
+	refresh_button = memnew(Button);
+	refresh_button->set_theme_type_variation(SceneStringName(FlatButton));
+	refresh_button->set_accessibility_name(ETR("Refresh"));
+	refresh_button->set_tooltip_text(ETR("Refresh files."));
+	top_toolbar->add_child(refresh_button);
+	refresh_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::update_file_list));
 
 	show_hidden = memnew(Button);
 	show_hidden->set_theme_type_variation(SceneStringName(FlatButton));
@@ -1781,8 +1747,8 @@ FileDialog::FileDialog() {
 	show_hidden->set_pressed(is_showing_hidden_files());
 	show_hidden->set_accessibility_name(ETR("Show Hidden Files"));
 	show_hidden->set_tooltip_text(ETR("Toggle the visibility of hidden files."));
+	top_toolbar->add_child(show_hidden);
 	show_hidden->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_hidden_files));
-	hbc->add_child(show_hidden);
 
 	show_filename_filter_button = memnew(Button);
 	show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton));
@@ -1790,25 +1756,35 @@ FileDialog::FileDialog() {
 	show_filename_filter_button->set_pressed(false);
 	show_filename_filter_button->set_accessibility_name(ETR("Filter File Names"));
 	show_filename_filter_button->set_tooltip_text(ETR("Toggle the visibility of the filter for file names."));
+	top_toolbar->add_child(show_filename_filter_button);
 	show_filename_filter_button->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_filename_filter));
-	hbc->add_child(show_filename_filter_button);
 
-	shortcuts_container = memnew(HBoxContainer);
-	hbc->add_child(shortcuts_container);
+	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_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_make_dir));
 
-	makedir = memnew(Button);
-	makedir->set_theme_type_variation(SceneStringName(FlatButton));
-	makedir->set_accessibility_name(ETR("Create New Folder"));
-	makedir->set_tooltip_text(ETR("Create a new folder."));
-	makedir->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_make_dir));
-	hbc->add_child(makedir);
-	vbox->add_child(hbc);
+	{
+		Label *label = memnew(Label(ETR("Directories & Files:")));
+		label->set_theme_type_variation("HeaderSmall");
+		main_vbox->add_child(label);
+	}
 
 	tree = memnew(Tree);
 	tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+	tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	tree->set_accessibility_name(ETR("Directories and Files"));
 	tree->set_hide_root(true);
-	vbox->add_margin_child(ETR("Directories & Files:"), tree, true);
+	tree->set_allow_rmb_select(true);
+	main_vbox->add_child(tree);
+	tree->connect("multi_selected", callable_mp(this, &FileDialog::_tree_multi_selected), CONNECT_DEFERRED);
+	tree->connect("cell_selected", callable_mp(this, &FileDialog::_tree_selected), CONNECT_DEFERRED);
+	tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated));
+	tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all));
+	tree->connect("item_mouse_selected", callable_mp(this, &FileDialog::_rmb_select));
+	tree->connect("empty_clicked", callable_mp(this, &FileDialog::_empty_clicked));
 
 	message = memnew(Label);
 	message->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
@@ -1819,7 +1795,14 @@ FileDialog::FileDialog() {
 	tree->add_child(message);
 
 	filename_filter_box = memnew(HBoxContainer);
-	filename_filter_box->add_child(memnew(Label(ETR("Filter:"))));
+	filename_filter_box->set_visible(false);
+	main_vbox->add_child(filename_filter_box);
+
+	{
+		Label *label = memnew(Label(ETR("Filter:")));
+		filename_filter_box->add_child(label);
+	}
+
 	filename_filter = memnew(LineEdit);
 	filename_filter->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
 	filename_filter->set_stretch_ratio(4);
@@ -1827,65 +1810,54 @@ FileDialog::FileDialog() {
 	filename_filter->set_clear_button_enabled(true);
 	filename_filter->set_accessibility_name(ETR("Filename Filter"));
 	filename_filter_box->add_child(filename_filter);
-	filename_filter_box->set_visible(false);
-	vbox->add_child(filename_filter_box);
+	filename_filter->connect(SceneStringName(text_changed), callable_mp(this, &FileDialog::_filename_filter_changed).unbind(1));
+	filename_filter->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_filename_filter_selected).unbind(1));
 
 	file_box = memnew(HBoxContainer);
-	Label *lbl_file = memnew(Label(ETR("File:")));
-	file_box->add_child(lbl_file);
-
-	file = memnew(LineEdit);
-	file->set_accessibility_name(ETR("File Name"));
-	file->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
-	file->set_stretch_ratio(4);
-	file->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-	file_box->add_child(file);
+	main_vbox->add_child(file_box);
+
+	{
+		Label *label = memnew(Label(ETR("File:")));
+		file_box->add_child(label);
+	}
+
+	filename_edit = memnew(LineEdit);
+	filename_edit->set_accessibility_name(ETR("File Name"));
+	filename_edit->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
+	filename_edit->set_stretch_ratio(4);
+	filename_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+	file_box->add_child(filename_edit);
+	filename_edit->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_file_submitted));
+
 	filter = memnew(OptionButton);
 	filter->set_stretch_ratio(3);
 	filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-	filter->set_clip_text(true); // too many extensions overflows it
+	filter->set_clip_text(true); // Too many extensions overflows it.
 	file_box->add_child(filter);
-	vbox->add_child(file_box);
+	filter->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_filter_selected));
 
 	grid_options = memnew(GridContainer);
 	grid_options->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
 	grid_options->set_columns(2);
-	vbox->add_child(grid_options);
-
-	dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-	_update_drives();
-
-	connect(SceneStringName(confirmed), callable_mp(this, &FileDialog::_action_pressed));
-	tree->set_allow_rmb_select(true);
-	tree->connect("multi_selected", callable_mp(this, &FileDialog::_tree_multi_selected), CONNECT_DEFERRED);
-	tree->connect("cell_selected", callable_mp(this, &FileDialog::_tree_selected), CONNECT_DEFERRED);
-	tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated));
-	tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all));
-	tree->connect("item_mouse_selected", callable_mp(this, &FileDialog::_rmb_select));
-	tree->connect("empty_clicked", callable_mp(this, &FileDialog::_empty_clicked));
-
-	dir->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_dir_submitted));
-	filename_filter->connect(SceneStringName(text_changed), callable_mp(this, &FileDialog::_filename_filter_changed).unbind(1));
-	filename_filter->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_filename_filter_selected).unbind(1));
-	file->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_file_submitted));
-	filter->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_filter_selected));
+	main_vbox->add_child(grid_options);
 
 	confirm_save = memnew(ConfirmationDialog);
 	add_child(confirm_save, false, INTERNAL_MODE_FRONT);
-
 	confirm_save->connect(SceneStringName(confirmed), callable_mp(this, &FileDialog::_save_confirm_pressed));
 
-	makedialog = memnew(ConfirmationDialog);
-	makedialog->set_title(ETR("Create Folder"));
+	make_dir_dialog = memnew(ConfirmationDialog);
+	make_dir_dialog->set_title(ETR("Create Folder"));
+	add_child(make_dir_dialog, false, INTERNAL_MODE_FRONT);
+	make_dir_dialog->connect(SceneStringName(confirmed), callable_mp(this, &FileDialog::_make_dir_confirm));
+
 	VBoxContainer *makevb = memnew(VBoxContainer);
-	makedialog->add_child(makevb);
-
-	makedirname = memnew(LineEdit);
-	makedirname->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
-	makevb->add_margin_child(ETR("Name:"), makedirname);
-	add_child(makedialog, false, INTERNAL_MODE_FRONT);
-	makedialog->register_text_enter(makedirname);
-	makedialog->connect(SceneStringName(confirmed), callable_mp(this, &FileDialog::_make_dir_confirm));
+	make_dir_dialog->add_child(makevb);
+
+	new_dir_name = memnew(LineEdit);
+	new_dir_name->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
+	makevb->add_margin_child(ETR("Name:"), new_dir_name);
+	make_dir_dialog->register_text_enter(new_dir_name);
+
 	mkdirerr = memnew(AcceptDialog);
 	mkdirerr->set_text(ETR("Could not create folder."));
 	add_child(mkdirerr, false, INTERNAL_MODE_FRONT);
@@ -1896,16 +1868,15 @@ FileDialog::FileDialog() {
 
 	item_menu = memnew(PopupMenu);
 	item_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FileDialog::_item_menu_id_pressed));
-	add_child(item_menu);
+	add_child(item_menu, false, INTERNAL_MODE_FRONT);
 
+	connect(SceneStringName(confirmed), callable_mp(this, &FileDialog::_action_pressed));
+
+	_update_drives();
 	update_filters();
 	update_filename_filter_gui();
 	update_dir();
 
-	set_hide_on_ok(false);
-	set_size(Size2(640, 360));
-	set_internal_ok_text(ETR("Save")); // Default mode text.
-
 	if (register_func) {
 		register_func(this);
 	}

+ 69 - 61
scene/gui/file_dialog.h

@@ -30,25 +30,32 @@
 
 #pragma once
 
-#include "box_container.h"
-#include "core/io/dir_access.h"
 #include "scene/gui/dialogs.h"
-#include "scene/gui/line_edit.h"
-#include "scene/gui/option_button.h"
-#include "scene/gui/tree.h"
 #include "scene/property_list_helper.h"
 
+class DirAccess;
 class GridContainer;
+class HBoxContainer;
+class LineEdit;
+class OptionButton;
 class PopupMenu;
+class VBoxContainer;
+class Tree;
 
 class FileDialog : public ConfirmationDialog {
 	GDCLASS(FileDialog, ConfirmationDialog);
 
+	struct Option {
+		String name;
+		Vector<String> values;
+		int default_idx = 0;
+	};
+
 public:
 	enum Access {
 		ACCESS_RESOURCES,
 		ACCESS_USERDATA,
-		ACCESS_FILESYSTEM
+		ACCESS_FILESYSTEM,
 	};
 
 	enum FileMode {
@@ -56,7 +63,7 @@ public:
 		FILE_MODE_OPEN_FILES,
 		FILE_MODE_OPEN_DIR,
 		FILE_MODE_OPEN_ANY,
-		FILE_MODE_SAVE_FILE
+		FILE_MODE_SAVE_FILE,
 	};
 
 	enum ItemMenu {
@@ -68,64 +75,77 @@ public:
 	typedef Ref<Texture2D> (*GetIconFunc)(const String &);
 	typedef void (*RegisterFunc)(FileDialog *);
 
-	static GetIconFunc get_icon_func;
-	static RegisterFunc register_func;
-	static RegisterFunc unregister_func;
+	inline static GetIconFunc get_icon_func = nullptr;
+	inline static RegisterFunc register_func = nullptr;
+	inline static RegisterFunc unregister_func = nullptr;
 
 private:
-	ConfirmationDialog *makedialog = nullptr;
-	LineEdit *makedirname = nullptr;
+	static inline PropertyListHelper base_property_helper;
+	PropertyListHelper property_helper;
+
+	inline static bool default_show_hidden_files = false;
+	bool show_hidden_files = false;
+	bool use_native_dialog = false;
 
-	Button *makedir = nullptr;
 	Access access = ACCESS_RESOURCES;
-	VBoxContainer *vbox = nullptr;
-	GridContainer *grid_options = nullptr;
-	FileMode mode;
-	LineEdit *dir = nullptr;
-	HBoxContainer *drives_container = nullptr;
-	HBoxContainer *shortcuts_container = nullptr;
-	OptionButton *drives = nullptr;
-	Tree *tree = nullptr;
-	HBoxContainer *filename_filter_box = nullptr;
-	LineEdit *filename_filter = nullptr;
-	HBoxContainer *file_box = nullptr;
-	LineEdit *file = nullptr;
-	OptionButton *filter = nullptr;
-	AcceptDialog *mkdirerr = nullptr;
-	AcceptDialog *exterr = nullptr;
+	FileMode mode = FILE_MODE_SAVE_FILE;
 	Ref<DirAccess> dir_access;
-	ConfirmationDialog *confirm_save = nullptr;
-	PopupMenu *item_menu = nullptr;
-
-	Label *message = nullptr;
-
-	Button *dir_prev = nullptr;
-	Button *dir_next = nullptr;
-	Button *dir_up = nullptr;
-
-	Button *refresh = nullptr;
-	Button *show_hidden = nullptr;
-	Button *show_filename_filter_button = nullptr;
 
 	Vector<String> filters;
 	Vector<String> processed_filters;
+
+	Vector<Option> options;
+	Dictionary selected_options;
+	bool options_dirty = false;
+
 	String file_name_filter;
 	bool show_filename_filter = false;
 
 	Vector<String> local_history;
 	int local_history_pos = 0;
-	void _push_history();
 
 	bool mode_overrides_title = true;
 	String root_subfolder;
 	String root_prefix;
-
-	static bool default_show_hidden_files;
-	bool show_hidden_files = false;
-	bool use_native_dialog = false;
+	String full_dir;
 
 	bool is_invalidating = false;
 
+	VBoxContainer *main_vbox = nullptr;
+
+	Button *dir_prev = nullptr;
+	Button *dir_next = nullptr;
+	Button *dir_up = nullptr;
+
+	HBoxContainer *drives_container = nullptr;
+	OptionButton *drives = nullptr;
+	LineEdit *directory_edit = nullptr;
+	HBoxContainer *shortcuts_container = nullptr;
+
+	Button *refresh_button = nullptr;
+	Button *show_hidden = nullptr;
+	Button *show_filename_filter_button = nullptr;
+	Button *make_dir_button = nullptr;
+
+	Tree *tree = nullptr;
+	Label *message = nullptr;
+	PopupMenu *item_menu = nullptr;
+
+	HBoxContainer *filename_filter_box = nullptr;
+	LineEdit *filename_filter = nullptr;
+
+	HBoxContainer *file_box = nullptr;
+	LineEdit *filename_edit = nullptr;
+	OptionButton *filter = nullptr;
+
+	GridContainer *grid_options = nullptr;
+
+	ConfirmationDialog *make_dir_dialog = nullptr;
+	LineEdit *new_dir_name = nullptr;
+	AcceptDialog *mkdirerr = nullptr;
+	AcceptDialog *exterr = nullptr;
+	ConfirmationDialog *confirm_save = nullptr;
+
 	struct ThemeCache {
 		Ref<Texture2D> parent_folder;
 		Ref<Texture2D> forward_folder;
@@ -147,20 +167,6 @@ private:
 		Color icon_pressed_color;
 	} theme_cache;
 
-	struct Option {
-		String name;
-		Vector<String> values;
-		int default_idx = 0;
-	};
-
-	static inline PropertyListHelper base_property_helper;
-	PropertyListHelper property_helper;
-
-	Vector<Option> options;
-	Dictionary selected_options;
-	bool options_dirty = false;
-	String full_dir;
-
 	void update_dir();
 	void update_file_name();
 	void update_file_list();
@@ -193,11 +199,13 @@ private:
 	void _go_up();
 	void _go_back();
 	void _go_forward();
+	void _push_history();
 
 	void _change_dir(const String &p_new_dir);
 	void _update_drives(bool p_select = true);
 
 	void _invalidate();
+	void _setup_button(Button *p_button, const Ref<Texture2D> &p_icon);
 
 	virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
 
@@ -274,8 +282,8 @@ public:
 	void set_file_mode(FileMode p_mode);
 	FileMode get_file_mode() const;
 
-	VBoxContainer *get_vbox();
-	LineEdit *get_line_edit() { return file; }
+	VBoxContainer *get_vbox() { return main_vbox; }
+	LineEdit *get_line_edit() { return filename_edit; }
 
 	void set_access(Access p_access);
 	Access get_access() const;