Repository: godotengine/godot (language: cpp)

Issue:
File selection dialog initially empty when instancing sub-scenes or selecting styles (requires manual search to display content)
### Tested versions

v4.4.stable.mono.official [4c311cbee]

### System information

Godot v4.4.stable.mono - Windows 10 (build 19045) - Multi-window, 1 monitor - OpenGL 3 (Compatibility) - NVIDIA GeForce GTX 1050 (NVIDIA; 31.0.15.5178) - Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz (4 threads)

### Issue description

When opening file selection dialogs for operations like instancing sub-scenes or selecting style resources, the window initially appears empty. Users must manually type in the search box to see relevant files, rather than having all valid files displayed by default with subsequent search filtering. This behavior differs from standard file selection patterns and creates an inefficient workflow.

![Image](https://github.com/user-attachments/assets/fca2279f-aead-424a-aa91-e852ac6cbe81)
![Image](https://github.com/user-attachments/assets/e4292921-d424-4560-b072-5f646187bd50)

### Steps to reproduce

Create/new a scene with child nodes requiring sub-scenes/styles

### Minimal reproduction project (MRP)

no need


Discussion / hints:

Fix patch:
diff --git a/editor/gui/editor_quick_open_dialog.cpp b/editor/gui/editor_quick_open_dialog.cpp
index 40b2242f460f..71b92045b28c 100644
--- a/editor/gui/editor_quick_open_dialog.cpp
+++ b/editor/gui/editor_quick_open_dialog.cpp
@@ -373,12 +373,36 @@ void QuickOpenResultContainer::init(const Vector<StringName> &p_base_types) {
 	_create_initial_results();
 }
 
+void QuickOpenResultContainer::_sort_filepaths(int p_max_results) {
+	struct FilepathComparator {
+		bool operator()(const String &p_lhs, const String &p_rhs) const {
+			// Sort on (length, alphanumeric) to prioritize shorter filepaths
+			return p_lhs.length() == p_rhs.length() ? p_lhs < p_rhs : p_lhs.length() < p_rhs.length();
+		}
+	};
+
+	SortArray<String, FilepathComparator> sorter;
+	if (filepaths.size() > p_max_results) {
+		sorter.partial_sort(0, filepaths.size(), p_max_results, filepaths.ptrw());
+	} else {
+		sorter.sort(filepaths.ptrw(), filepaths.size());
+	}
+}
+
 void QuickOpenResultContainer::_create_initial_results() {
 	file_type_icons.clear();
 	file_type_icons.insert(SNAME("__default_icon"), get_editor_theme_icon(SNAME("Object")));
 	filepaths.clear();
 	filetypes.clear();
+	history_set.clear();
+	Vector<QuickOpenResultCandidate> *history = _get_history();
+	if (history) {
+		for (const QuickOpenResultCandidate &candidate : *history) {
+			history_set.insert(candidate.file_path);
+		}
+	}
 	_find_filepaths_in_folder(EditorFileSystem::get_singleton()->get_filesystem(), include_addons_toggle->is_pressed());
+	_sort_filepaths(result_items.size());
 	max_total_results = MIN(filepaths.size(), result_items.size());
 	update_results();
 }
@@ -416,25 +440,26 @@ void QuickOpenResultContainer::set_query_and_update(const String &p_query) {
 	update_results();
 }
 
-void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_candidate, const String &p_filepath) {
-	ResourceUID::ID id = EditorFileSystem::get_singleton()->get_file_uid(p_filepath);
-	if (id == ResourceUID::INVALID_ID) {
-		p_candidate.file_path = p_filepath;
-	} else {
-		p_candidate.file_path = ResourceUID::get_singleton()->id_to_text(id);
+Vector<QuickOpenResultCandidate> *QuickOpenResultContainer::_get_history() {
+	if (base_types.size() == 1) {
+		return selected_history.lookup_ptr(base_types[0]);
 	}
-	p_candidate.result = nullptr;
+	return nullptr;
+}
 
+void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_candidate, const String &p_filepath) {
+	p_candidate.file_path = ResourceUID::ensure_path(p_filepath);
+	p_candidate.result = nullptr;
 	StringName actual_type;
 	{
 		StringName *actual_type_ptr = filetypes.lookup_ptr(p_filepath);
 		if (actual_type_ptr) {
 			actual_type = *actual_type_ptr;
 		} else {
-			ERR_PRINT(vformat("EditorQuickOpenDialog: No type for path %s.", p_filepath));
+			ERR_PRINT(vformat("EditorQuickOpenDialog: No type for path %s.", p_candidate.file_path));
 		}
 	}
-	EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(p_filepath);
+	EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(p_candidate.file_path);
 	if (item.preview.is_valid()) {
 		p_candidate.thumbnail = item.preview;
 	} else if (file_type_icons.has(actual_type)) {
@@ -453,7 +478,6 @@ void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_cand
 }
 
 void QuickOpenResultContainer::update_results() {
-	showing_history = false;
 	candidates.clear();
 	if (query.is_empty()) {
 		_use_default_candidates();
@@ -464,17 +488,18 @@ void QuickOpenResultContainer::update_results() {
 }
 
 void QuickOpenResultContainer::_use_default_candidates() {
-	if (filepaths.size() <= SHOW_ALL_FILES_THRESHOLD) {
-		candidates.resize(filepaths.size());
-		QuickOpenResultCandidate *candidates_write = candidates.ptrw();
-		for (const String &filepath : filepaths) {
-			_setup_candidate(*candidates_write++, filepath);
+	Vector<QuickOpenResultCandidate> *history = _get_history();
+	if (history) {
+		candidates.append_array(*history);
+	}
+	int count = candidates.size();
+	candidates.resize(MIN(max_total_results, filepaths.size()));
+	for (const String &filepath : filepaths) {
+		if (count >= max_total_results) {
+			break;
 		}
-	} else if (base_types.size() == 1) {
-		Vector<QuickOpenResultCandidate> *history = selected_history.lookup_ptr(base_types[0]);
-		if (history) {
-			showing_history = true;
-			candidates.append_array(*history);
+		if (!history || !history_set.has(filepath)) {
+			_setup_candidate(candidates.write[count++], filepath);
 		}
 	}
 }
@@ -524,8 +549,6 @@ void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_co
 	if (!any_results) {
 		if (filepaths.is_empty()) {
 			no_results_label->set_text(TTR("No files found for this type"));
-		} else if (query.is_empty()) {
-			no_results_label->set_text(TTR("Start searching to find files..."));
 		} else {
 			no_results_label->set_text(TTR("No results found"));
 		}
@@ -621,7 +644,8 @@ void QuickOpenResultContainer::_select_item(int p_index) {
 	}
 
 	result_items[selection_index]->highlight_item(true);
-	file_details_path->set_text(get_selected() + (showing_history ? TTR(" (recently opened)") : ""));
+	bool in_history = history_set.has(candidates[selection_index].file_path);
+	file_details_path->set_text(get_selected() + (in_history ? TTR(" (recently opened)") : ""));
 
 	const QuickOpenResultItem *item = result_items[selection_index];
 
@@ -727,7 +751,7 @@ bool QuickOpenResultContainer::has_nothing_selected() const {
 
 String QuickOpenResultContainer::get_selected() const {
 	ERR_FAIL_COND_V_MSG(has_nothing_selected(), String(), "Tried to get selected file, but nothing was selected.");
-	return ResourceUID::ensure_path(candidates[selection_index].file_path);
+	return candidates[selection_index].file_path;
 }
 
 QuickOpenDisplayMode QuickOpenResultContainer::get_adaptive_display_mode(const Vector<StringName> &p_base_types) {
@@ -749,6 +773,11 @@ QuickOpenDisplayMode QuickOpenResultContainer::get_adaptive_display_mode(const V
 	return QuickOpenDisplayMode::LIST;
 }
 
+String _get_uid_string(const String &p_filepath) {
+	ResourceUID::ID id = EditorFileSystem::get_singleton()->get_file_uid(p_filepath);
+	return id == ResourceUID::INVALID_ID ? p_filepath : ResourceUID::get_singleton()->id_to_text(id);
+}
+
 void QuickOpenResultContainer::save_selected_item() {
 	if (base_types.size() > 1) {
 		// Getting the type of the file and checking which base type it belongs to should be possible.
@@ -773,6 +802,7 @@ void QuickOpenResultContainer::save_selected_item() {
 	}
 
 	selected.result = nullptr;
+	history_set.insert(selected.file_path);
 	type_history->insert(0, selected);
 	if (type_history->size() > MAX_HISTORY_SIZE) {
 		type_history->resize(MAX_HISTORY_SIZE);
@@ -785,7 +815,7 @@ void QuickOpenResultContainer::save_selected_item() {
 
 		int i = 0;
 		for (const QuickOpenResultCandidate &candidate : *type_history) {
-			paths_write[i] = candidate.file_path;
+			paths_write[i] = _get_uid_string(candidate.file_path);
 			i++;
 		}
 	}
@@ -796,6 +826,7 @@ void QuickOpenResultContainer::save_selected_item() {
 void QuickOpenResultContainer::cleanup() {
 	num_visible_results = 0;
 	candidates.clear();
+	history_set.clear();
 	_select_item(-1);
 
 	for (QuickOpenResultItem *item : result_items) {
@@ -981,9 +1012,8 @@ QuickOpenResultListItem::QuickOpenResultListItem() {
 
 void QuickOpenResultListItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
 	thumbnail->set_texture(p_candidate.thumbnail);
-	const String file_path = ResourceUID::ensure_path(p_candidate.file_path);
-	name->set_text(file_path.get_file());
-	path->set_text(file_path.get_base_dir());
+	name->set_text(p_candidate.file_path.get_file());
+	path->set_text(p_candidate.file_path.get_base_dir());
 	name->reset_highlights();
 	path->reset_highlights();
 
@@ -1053,9 +1083,8 @@ QuickOpenResultGridItem::QuickOpenResultGridItem() {
 
 void QuickOpenResultGridItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
 	thumbnail->set_texture(p_candidate.thumbnail);
-	const String file_path = ResourceUID::ensure_path(p_candidate.file_path);
-	name->set_text(file_path.get_file());
-	name->set_tooltip_text(file_path);
+	name->set_text(p_candidate.file_path.get_file());
+	name->set_tooltip_text(p_candidate.file_path);
 	name->reset_highlights();
 
 	if (p_highlight && p_candidate.result != nullptr) {
diff --git a/editor/gui/editor_quick_open_dialog.h b/editor/gui/editor_quick_open_dialog.h
index 9cffae5dc8da..a730e7921fb5 100644
--- a/editor/gui/editor_quick_open_dialog.h
+++ b/editor/gui/editor_quick_open_dialog.h
@@ -106,7 +106,6 @@ class QuickOpenResultContainer : public VBoxContainer {
 	void _notification(int p_what);
 
 private:
-	static constexpr int SHOW_ALL_FILES_THRESHOLD = 30;
 	static constexpr int MAX_HISTORY_SIZE = 20;
 
 	Vector<FuzzySearchResult> search_results;
@@ -116,13 +115,13 @@ class QuickOpenResultContainer : public VBoxContainer {
 	Vector<QuickOpenResultCandidate> candidates;
 
 	OAHashMap<StringName, Vector<QuickOpenResultCandidate>> selected_history;
+	HashSet<String> history_set;
 
 	String query;
 	int selection_index = -1;
 	int num_visible_results = 0;
 	int max_total_results = 0;
 
-	bool showing_history = false;
 	bool never_opened = true;
 	Ref<ConfigFile> history_file;
 
@@ -148,9 +147,11 @@ class QuickOpenResultContainer : public VBoxContainer {
 	static QuickOpenDisplayMode get_adaptive_display_mode(const Vector<StringName> &p_base_types);
 
 	void _ensure_result_vector_capacity();
+	void _sort_filepaths(int p_max_results);
 	void _create_initial_results();
 	void _find_filepaths_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons);
 
+	Vector<QuickOpenResultCandidate> *_get_history();
 	void _setup_candidate(QuickOpenResultCandidate &p_candidate, const String &p_filepath);
 	void _setup_candidate(QuickOpenResultCandidate &p_candidate, const FuzzySearchResult &p_result);
 	void _update_fuzzy_search_results();


Test patch: