Browse Source

Add filename filter field to FileDialog

Added possibility to filter files and folders through a text entry.
vPumpking 1 year ago
parent
commit
62edb4eee8

+ 19 - 0
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).
 				[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>
 			</description>
 		</method>
 		</method>
+		<method name="clear_filename_filter">
+			<return type="void" />
+			<description>
+				Clear the filter for file names.
+			</description>
+		</method>
 		<method name="clear_filters">
 		<method name="clear_filters">
 			<return type="void" />
 			<return type="void" />
 			<description>
 			<description>
@@ -134,6 +140,10 @@
 		<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. See [enum FileMode].
 			The dialog's open or save mode, which affects the selection behavior. See [enum FileMode].
 		</member>
 		</member>
+		<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.
+			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()">
 		<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.
 			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>
 		</member>
@@ -173,6 +183,12 @@
 				Emitted when the user selects a file by double-clicking it or pressing the [b]OK[/b] button.
 				Emitted when the user selects a file by double-clicking it or pressing the [b]OK[/b] button.
 			</description>
 			</description>
 		</signal>
 		</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">
 		<signal name="files_selected">
 			<param index="0" name="paths" type="PackedStringArray" />
 			<param index="0" name="paths" type="PackedStringArray" />
 			<description>
 			<description>
@@ -237,6 +253,9 @@
 		<theme_item name="reload" data_type="icon" type="Texture2D">
 		<theme_item name="reload" data_type="icon" type="Texture2D">
 			Custom icon for the reload button.
 			Custom icon for the reload button.
 		</theme_item>
 		</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">
 		<theme_item name="toggle_hidden" data_type="icon" type="Texture2D">
 			Custom icon for the toggle hidden button.
 			Custom icon for the toggle hidden button.
 		</theme_item>
 		</theme_item>

+ 138 - 10
scene/gui/file_dialog.cpp

@@ -208,6 +208,7 @@ void FileDialog::_notification(int p_what) {
 			refresh->set_icon(theme_cache.reload);
 			refresh->set_icon(theme_cache.reload);
 			show_hidden->set_icon(theme_cache.toggle_hidden);
 			show_hidden->set_icon(theme_cache.toggle_hidden);
 			makedir->set_icon(theme_cache.create_folder);
 			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->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_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->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color);
 			makedir->end_bulk_theme_override();
 			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();
 			invalidate();
 		} break;
 		} break;
 
 
@@ -276,6 +284,14 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
 						handled = false;
 						handled = false;
 					}
 					}
 
 
+				} 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;
 				} break;
 				case Key::F5: {
 				case Key::F5: {
 					invalidate();
 					invalidate();
@@ -694,18 +710,24 @@ void FileDialog::update_file_list() {
 	dirs.sort_custom<FileNoCaseComparator>();
 	dirs.sort_custom<FileNoCaseComparator>();
 	files.sort_custom<FileNoCaseComparator>();
 	files.sort_custom<FileNoCaseComparator>();
 
 
+	String filename_filter_lower = file_name_filter.to_lower();
+
 	while (!dirs.is_empty()) {
 	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();
 		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);
 			TreeItem *ti = tree->create_item(root);
 			ti->set_text(0, files.front()->get());
 			ti->set_text(0, files.front()->get());
 
 
@@ -792,6 +814,26 @@ void FileDialog::_filter_selected(int) {
 	update_file_list();
 	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() {
 void FileDialog::update_filters() {
 	filter->clear();
 	filter->clear();
 
 
@@ -827,6 +869,30 @@ void FileDialog::update_filters() {
 	filter->add_item(atr(ETR("All Files")) + " (*)");
 	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() {
 void FileDialog::clear_filters() {
 	filters.clear();
 	filters.clear();
 	update_filters();
 	update_filters();
@@ -853,10 +919,24 @@ void FileDialog::set_filters(const Vector<String> &p_filters) {
 	invalidate();
 	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 {
 Vector<String> FileDialog::get_filters() const {
 	return filters;
 	return filters;
 }
 }
 
 
+String FileDialog::get_filename_filter() const {
+	return file_name_filter;
+}
+
 String FileDialog::get_current_dir() const {
 String FileDialog::get_current_dir() const {
 	return dir->get_text();
 	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("add_filter", "filter", "description"), &FileDialog::add_filter, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("set_filters", "filters"), &FileDialog::set_filters);
 	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("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_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_values", "option"), &FileDialog::get_option_values);
 	ClassDB::bind_method(D_METHOD("get_option_default", "option"), &FileDialog::get_option_default);
 	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::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::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_ARRAY_COUNT("Options", "option_count", "set_option_count", "get_option_count", "option_");
 	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");
@@ -1315,6 +1399,7 @@ void FileDialog::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path")));
 	ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path")));
 	ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths")));
 	ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths")));
 	ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir")));
 	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_FILE);
 	BIND_ENUM_CONSTANT(FILE_MODE_OPEN_FILES);
 	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, reload);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, toggle_hidden);
 	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, 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, file);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, create_folder);
 	BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, create_folder);
 
 
@@ -1363,6 +1449,26 @@ void FileDialog::set_show_hidden_files(bool p_show) {
 	invalidate();
 	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 {
 bool FileDialog::is_showing_hidden_files() const {
 	return show_hidden_files;
 	return show_hidden_files;
 }
 }
@@ -1446,6 +1552,14 @@ FileDialog::FileDialog() {
 	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));
 	hbc->add_child(show_hidden);
 	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);
 	shortcuts_container = memnew(HBoxContainer);
 	hbc->add_child(shortcuts_container);
 	hbc->add_child(shortcuts_container);
 
 
@@ -1467,6 +1581,17 @@ FileDialog::FileDialog() {
 	message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
 	message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
 	tree->add_child(message);
 	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 = memnew(HBoxContainer);
 	file_box->add_child(memnew(Label(ETR("File:"))));
 	file_box->add_child(memnew(Label(ETR("File:"))));
 	file = memnew(LineEdit);
 	file = memnew(LineEdit);
@@ -1495,6 +1620,8 @@ FileDialog::FileDialog() {
 	tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated));
 	tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated));
 	tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all));
 	tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all));
 	dir->connect("text_submitted", callable_mp(this, &FileDialog::_dir_submitted));
 	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));
 	file->connect("text_submitted", callable_mp(this, &FileDialog::_file_submitted));
 	filter->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_filter_selected));
 	filter->connect(SceneStringName(item_selected), callable_mp(this, &FileDialog::_filter_selected));
 
 
@@ -1523,6 +1650,7 @@ FileDialog::FileDialog() {
 	add_child(exterr, false, INTERNAL_MODE_FRONT);
 	add_child(exterr, false, INTERNAL_MODE_FRONT);
 
 
 	update_filters();
 	update_filters();
+	update_filename_filter_gui();
 	update_dir();
 	update_dir();
 
 
 	set_hide_on_ok(false);
 	set_hide_on_ok(false);

+ 16 - 0
scene/gui/file_dialog.h

@@ -80,6 +80,8 @@ private:
 	HBoxContainer *shortcuts_container = nullptr;
 	HBoxContainer *shortcuts_container = nullptr;
 	OptionButton *drives = nullptr;
 	OptionButton *drives = nullptr;
 	Tree *tree = nullptr;
 	Tree *tree = nullptr;
+	HBoxContainer *filename_filter_box = nullptr;
+	LineEdit *filename_filter = nullptr;
 	HBoxContainer *file_box = nullptr;
 	HBoxContainer *file_box = nullptr;
 	LineEdit *file = nullptr;
 	LineEdit *file = nullptr;
 	OptionButton *filter = nullptr;
 	OptionButton *filter = nullptr;
@@ -96,8 +98,11 @@ private:
 
 
 	Button *refresh = nullptr;
 	Button *refresh = nullptr;
 	Button *show_hidden = nullptr;
 	Button *show_hidden = nullptr;
+	Button *show_filename_filter_button = nullptr;
 
 
 	Vector<String> filters;
 	Vector<String> filters;
+	String file_name_filter;
+	bool show_filename_filter = false;
 
 
 	Vector<String> local_history;
 	Vector<String> local_history;
 	int local_history_pos = 0;
 	int local_history_pos = 0;
@@ -119,6 +124,7 @@ private:
 		Ref<Texture2D> back_folder;
 		Ref<Texture2D> back_folder;
 		Ref<Texture2D> reload;
 		Ref<Texture2D> reload;
 		Ref<Texture2D> toggle_hidden;
 		Ref<Texture2D> toggle_hidden;
+		Ref<Texture2D> toggle_filename_filter;
 		Ref<Texture2D> folder;
 		Ref<Texture2D> folder;
 		Ref<Texture2D> file;
 		Ref<Texture2D> file;
 		Ref<Texture2D> create_folder;
 		Ref<Texture2D> create_folder;
@@ -149,6 +155,8 @@ private:
 	void update_dir();
 	void update_dir();
 	void update_file_name();
 	void update_file_name();
 	void update_file_list();
 	void update_file_list();
+	void update_filename_filter();
+	void update_filename_filter_gui();
 	void update_filters();
 	void update_filters();
 
 
 	void _focus_file_text();
 	void _focus_file_text();
@@ -164,6 +172,9 @@ private:
 	void _save_confirm_pressed();
 	void _save_confirm_pressed();
 	void _cancel_pressed();
 	void _cancel_pressed();
 	void _filter_selected(int);
 	void _filter_selected(int);
+	void _filename_filter_changed();
+	void _filename_filter_selected();
+	void _tree_select_first();
 	void _make_dir();
 	void _make_dir();
 	void _make_dir_confirm();
 	void _make_dir_confirm();
 	void _go_up();
 	void _go_up();
@@ -208,6 +219,9 @@ public:
 	void add_filter(const String &p_filter, const String &p_description = "");
 	void add_filter(const String &p_filter, const String &p_description = "");
 	void set_filters(const Vector<String> &p_filters);
 	void set_filters(const Vector<String> &p_filters);
 	Vector<String> get_filters() const;
 	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);
 	void set_enable_multiple_selection(bool p_enable);
 	Vector<String> get_selected_files() const;
 	Vector<String> get_selected_files() const;
@@ -253,6 +267,8 @@ public:
 
 
 	void set_show_hidden_files(bool p_show);
 	void set_show_hidden_files(bool p_show);
 	bool is_showing_hidden_files() const;
 	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);
 	static void set_default_show_hidden_files(bool p_show);
 
 

+ 1 - 0
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("forward_folder", "FileDialog", icons["arrow_right"]);
 	theme->set_icon("reload", "FileDialog", icons["reload"]);
 	theme->set_icon("reload", "FileDialog", icons["reload"]);
 	theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]);
 	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("folder", "FileDialog", icons["folder"]);
 	theme->set_icon("file", "FileDialog", icons["file"]);
 	theme->set_icon("file", "FileDialog", icons["file"]);
 	theme->set_icon("create_folder", "FileDialog", icons["folder_create"]);
 	theme->set_icon("create_folder", "FileDialog", icons["folder_create"]);

+ 1 - 0
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>