diff options
-rw-r--r-- | doc/classes/FileDialog.xml | 19 | ||||
-rw-r--r-- | scene/gui/file_dialog.cpp | 148 | ||||
-rw-r--r-- | scene/gui/file_dialog.h | 16 | ||||
-rw-r--r-- | scene/theme/default_theme.cpp | 1 | ||||
-rw-r--r-- | scene/theme/icons/toggle_filename_filter.svg | 1 |
5 files changed, 175 insertions, 10 deletions
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 1ae889adc1..9529fac77e 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -29,6 +29,12 @@ [param default_value_index] should be an index of the value in the [param values]. If [param values] is empty it should be either [code]1[/code] (checked), or [code]0[/code] (unchecked). </description> </method> + <method name="clear_filename_filter"> + <return type="void" /> + <description> + Clear the filter for file names. + </description> + </method> <method name="clear_filters"> <return type="void" /> <description> @@ -134,6 +140,10 @@ <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. See [enum FileMode]. </member> + <member name="filename_filter" type="String" setter="set_filename_filter" getter="get_filename_filter" default=""""> + 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. + </member> <member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()"> The available file type filters. Each filter string in the array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted. </member> @@ -173,6 +183,12 @@ Emitted when the user selects a file by double-clicking it or pressing the [b]OK[/b] button. </description> </signal> + <signal name="filename_filter_changed"> + <param index="0" name="filter" type="String" /> + <description> + Emitted when the filter for file names changes. + </description> + </signal> <signal name="files_selected"> <param index="0" name="paths" type="PackedStringArray" /> <description> @@ -237,6 +253,9 @@ <theme_item name="reload" data_type="icon" type="Texture2D"> Custom icon for the reload button. </theme_item> + <theme_item name="toggle_filename_filter" data_type="icon" type="Texture2D"> + Custom icon for the toggle button for the filter for file names. + </theme_item> <theme_item name="toggle_hidden" data_type="icon" type="Texture2D"> Custom icon for the toggle hidden button. </theme_item> diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 6f61295a91..d8e9d1bcc0 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -208,6 +208,7 @@ void FileDialog::_notification(int p_what) { refresh->set_icon(theme_cache.reload); show_hidden->set_icon(theme_cache.toggle_hidden); makedir->set_icon(theme_cache.create_folder); + show_filename_filter_button->set_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); @@ -251,6 +252,13 @@ void FileDialog::_notification(int p_what) { 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(); + invalidate(); } break; @@ -277,6 +285,14 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) { } } break; + case Key::F: { + if (k->is_command_or_control_pressed()) { + show_filename_filter_button->set_pressed(!show_filename_filter_button->is_pressed()); + } else { + handled = false; + } + + } break; case Key::F5: { invalidate(); } break; @@ -694,18 +710,24 @@ void FileDialog::update_file_list() { dirs.sort_custom<FileNoCaseComparator>(); files.sort_custom<FileNoCaseComparator>(); + String filename_filter_lower = file_name_filter.to_lower(); + while (!dirs.is_empty()) { - String &dir_name = dirs.front()->get(); - TreeItem *ti = tree->create_item(root); - ti->set_text(0, dir_name); - ti->set_icon(0, theme_cache.folder); - ti->set_icon_modulate(0, theme_cache.folder_icon_color); + const String &dir_name = dirs.front()->get(); + + if (filename_filter_lower.is_empty() || dir_name.to_lower().contains(filename_filter_lower)) { + TreeItem *ti = tree->create_item(root); - Dictionary d; - d["name"] = dir_name; - d["dir"] = true; + ti->set_text(0, dir_name); + ti->set_icon(0, theme_cache.folder); + ti->set_icon_modulate(0, theme_cache.folder_icon_color); - ti->set_metadata(0, d); + Dictionary d; + d["name"] = dir_name; + d["dir"] = true; + + ti->set_metadata(0, d); + } dirs.pop_front(); } @@ -750,7 +772,7 @@ void FileDialog::update_file_list() { } } - if (match) { + if (match && (filename_filter_lower.is_empty() || files.front()->get().to_lower().contains(filename_filter_lower))) { TreeItem *ti = tree->create_item(root); ti->set_text(0, files.front()->get()); @@ -792,6 +814,26 @@ void FileDialog::_filter_selected(int) { update_file_list(); } +void FileDialog::_filename_filter_changed() { + update_filename_filter(); + update_file_list(); + callable_mp(this, &FileDialog::_tree_select_first).call_deferred(); +} + +void FileDialog::_tree_select_first() { + if (tree->get_root() && tree->get_root()->get_first_child()) { + tree->get_root()->get_first_child()->select(0); + } +} + +void FileDialog::_filename_filter_selected() { + TreeItem *item = tree->get_selected(); + if (item) { + file->set_text(item->get_text(0)); + file->emit_signal("text_submitted", file->get_text()); + } +} + void FileDialog::update_filters() { filter->clear(); @@ -827,6 +869,30 @@ void FileDialog::update_filters() { filter->add_item(atr(ETR("All Files")) + " (*)"); } +void FileDialog::clear_filename_filter() { + set_filename_filter(""); + update_filename_filter_gui(); + invalidate(); +} + +void FileDialog::update_filename_filter_gui() { + filename_filter_box->set_visible(show_filename_filter); + if (!show_filename_filter) { + file_name_filter.clear(); + } + if (filename_filter->get_text() == file_name_filter) { + return; + } + filename_filter->set_text(file_name_filter); +} + +void FileDialog::update_filename_filter() { + if (filename_filter->get_text() == file_name_filter) { + return; + } + set_filename_filter(filename_filter->get_text()); +} + void FileDialog::clear_filters() { filters.clear(); update_filters(); @@ -853,10 +919,24 @@ void FileDialog::set_filters(const Vector<String> &p_filters) { invalidate(); } +void FileDialog::set_filename_filter(const String &p_filename_filter) { + if (file_name_filter == p_filename_filter) { + return; + } + file_name_filter = p_filename_filter; + update_filename_filter_gui(); + emit_signal(SNAME("filename_filter_changed"), filter); + invalidate(); +} + Vector<String> FileDialog::get_filters() const { return filters; } +String FileDialog::get_filename_filter() const { + return file_name_filter; +} + String FileDialog::get_current_dir() const { return dir->get_text(); } @@ -1266,6 +1346,9 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &FileDialog::add_filter, DEFVAL("")); ClassDB::bind_method(D_METHOD("set_filters", "filters"), &FileDialog::set_filters); ClassDB::bind_method(D_METHOD("get_filters"), &FileDialog::get_filters); + ClassDB::bind_method(D_METHOD("clear_filename_filter"), &FileDialog::clear_filename_filter); + ClassDB::bind_method(D_METHOD("set_filename_filter", "filter"), &FileDialog::set_filename_filter); + ClassDB::bind_method(D_METHOD("get_filename_filter"), &FileDialog::get_filename_filter); ClassDB::bind_method(D_METHOD("get_option_name", "option"), &FileDialog::get_option_name); ClassDB::bind_method(D_METHOD("get_option_values", "option"), &FileDialog::get_option_values); ClassDB::bind_method(D_METHOD("get_option_default", "option"), &FileDialog::get_option_default); @@ -1305,6 +1388,7 @@ void FileDialog::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename_filter"), "set_filename_filter", "get_filename_filter"); ADD_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_native_dialog"), "set_use_native_dialog", "get_use_native_dialog"); @@ -1315,6 +1399,7 @@ void FileDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path"))); ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"))); ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir"))); + ADD_SIGNAL(MethodInfo("filename_filter_changed", PropertyInfo(Variant::STRING, "filter"))); BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILE); BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILES); @@ -1332,6 +1417,7 @@ void FileDialog::_bind_methods() { BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, reload); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, toggle_hidden); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, folder); + BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, toggle_filename_filter); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, file); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, create_folder); @@ -1363,6 +1449,26 @@ void FileDialog::set_show_hidden_files(bool p_show) { invalidate(); } +void FileDialog::set_show_filename_filter(bool p_show) { + if (p_show == show_filename_filter) { + return; + } + if (p_show) { + filename_filter->grab_focus(); + } else { + if (filename_filter->has_focus()) { + tree->call_deferred("grab_focus"); + } + } + show_filename_filter = p_show; + update_filename_filter_gui(); + invalidate(); +} + +bool FileDialog::get_show_filename_filter() const { + return show_filename_filter; +} + bool FileDialog::is_showing_hidden_files() const { return show_hidden_files; } @@ -1446,6 +1552,14 @@ FileDialog::FileDialog() { 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("FlatButton"); + show_filename_filter_button->set_toggle_mode(true); + show_filename_filter_button->set_pressed(false); + show_filename_filter_button->set_tooltip_text(RTR("Toggle the visibility of the filter for file names.")); + 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); @@ -1467,6 +1581,17 @@ FileDialog::FileDialog() { message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); tree->add_child(message); + filename_filter_box = memnew(HBoxContainer); + filename_filter_box->add_child(memnew(Label(RTR("Filter:")))); + filename_filter = memnew(LineEdit); + filename_filter->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); + filename_filter->set_stretch_ratio(4); + filename_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); + filename_filter->set_clear_button_enabled(true); + filename_filter_box->add_child(filename_filter); + filename_filter_box->set_visible(false); + vbox->add_child(filename_filter_box); + file_box = memnew(HBoxContainer); file_box->add_child(memnew(Label(ETR("File:")))); file = memnew(LineEdit); @@ -1495,6 +1620,8 @@ FileDialog::FileDialog() { tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated)); tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all)); dir->connect("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("text_submitted", callable_mp(this, &FileDialog::_filename_filter_selected).unbind(1)); file->connect("text_submitted", callable_mp(this, &FileDialog::_file_submitted)); filter->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_filter_selected)); @@ -1523,6 +1650,7 @@ FileDialog::FileDialog() { add_child(exterr, false, INTERNAL_MODE_FRONT); update_filters(); + update_filename_filter_gui(); update_dir(); set_hide_on_ok(false); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 9680157f0a..6ef60a0f4f 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -80,6 +80,8 @@ private: 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; @@ -96,8 +98,11 @@ private: Button *refresh = nullptr; Button *show_hidden = nullptr; + Button *show_filename_filter_button = nullptr; Vector<String> filters; + String file_name_filter; + bool show_filename_filter = false; Vector<String> local_history; int local_history_pos = 0; @@ -119,6 +124,7 @@ private: Ref<Texture2D> back_folder; Ref<Texture2D> reload; Ref<Texture2D> toggle_hidden; + Ref<Texture2D> toggle_filename_filter; Ref<Texture2D> folder; Ref<Texture2D> file; Ref<Texture2D> create_folder; @@ -149,6 +155,8 @@ private: void update_dir(); void update_file_name(); void update_file_list(); + void update_filename_filter(); + void update_filename_filter_gui(); void update_filters(); void _focus_file_text(); @@ -164,6 +172,9 @@ private: void _save_confirm_pressed(); void _cancel_pressed(); void _filter_selected(int); + void _filename_filter_changed(); + void _filename_filter_selected(); + void _tree_select_first(); void _make_dir(); void _make_dir_confirm(); void _go_up(); @@ -208,6 +219,9 @@ public: void add_filter(const String &p_filter, const String &p_description = ""); void set_filters(const Vector<String> &p_filters); Vector<String> get_filters() const; + void clear_filename_filter(); + void set_filename_filter(const String &p_filename_filter); + String get_filename_filter() const; void set_enable_multiple_selection(bool p_enable); Vector<String> get_selected_files() const; @@ -253,6 +267,8 @@ public: void set_show_hidden_files(bool p_show); bool is_showing_hidden_files() const; + void set_show_filename_filter(bool p_show); + bool get_show_filename_filter() const; static void set_default_show_hidden_files(bool p_show); diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index 0c211be9f9..caf44ac392 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -689,6 +689,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("forward_folder", "FileDialog", icons["arrow_right"]); theme->set_icon("reload", "FileDialog", icons["reload"]); theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]); + theme->set_icon("toggle_filename_filter", "FileDialog", icons["toggle_filename_filter"]); theme->set_icon("folder", "FileDialog", icons["folder"]); theme->set_icon("file", "FileDialog", icons["file"]); theme->set_icon("create_folder", "FileDialog", icons["folder_create"]); diff --git a/scene/theme/icons/toggle_filename_filter.svg b/scene/theme/icons/toggle_filename_filter.svg new file mode 100644 index 0000000000..351cc44ced --- /dev/null +++ b/scene/theme/icons/toggle_filename_filter.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#e0e0e0"><path d="m13.297.714h-13.013a.454.454 0 0 0 -.318.779l4.615 4.507v7.086a.45.45 0 0 0 .738.354l3.511-2.812a.454.454 0 0 0 .17-.354v-4.274l4.614-4.506a.454.454 0 0 0 -.317-.779z"/><path d="m11.085832 14.18196c3.399443 1.97457 6.855925-2.441094 4.074102-5.1815164-2.781825-2.7404217-7.2642008.6646174-5.2597994 4.0134654l-1.9001346 1.871854 1.1856973 1.168051zm1.699723-4.4945981c2.236109 0 2.236109 3.3042441 0 3.3042441-2.236108 0-2.236108-3.3042441 0-3.3042441z"/></g></svg>
\ No newline at end of file |