diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index 874ecda2745..4e47f163001 100644 --- a/editor/export/export_template_manager.cpp +++ b/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" diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index a3e2291a786..b69ad9c5fce 100644 --- a/scene/gui/file_dialog.cpp +++ b/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 &p_files, int void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector &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 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 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 } } -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 &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 &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 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 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 &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 FileDialog::_get_options() const { TypedArray out; for (const FileDialog::Option &opt : options) { @@ -1722,58 +1676,70 @@ bool FileDialog::get_use_native_dialog() const { } FileDialog::FileDialog() { + 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. + show_hidden_files = default_show_hidden_files; + dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); - vbox = memnew(VBoxContainer); - add_child(vbox, false, INTERNAL_MODE_FRONT); + main_vbox = memnew(VBoxContainer); + add_child(main_vbox, false, INTERNAL_MODE_FRONT); - mode = FILE_MODE_SAVE_FILE; - set_title(TTRC("Save a File")); - - 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); + 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)); - 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); 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")); - VBoxContainer *makevb = memnew(VBoxContainer); - makedialog->add_child(makevb); + 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); + 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); - 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)); 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); } diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 7f822be9249..c9dfb9c9143 100644 --- a/scene/gui/file_dialog.h +++ b/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 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 (*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 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 filters; Vector processed_filters; + + Vector