feat: updated engine
This commit is contained in:
parent
cbe99774ff
commit
f4cf6b3999
6607 changed files with 910135 additions and 430025 deletions
|
|
@ -31,11 +31,15 @@
|
|||
#include "editor_quick_open_dialog.h"
|
||||
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/string/fuzzy_search.h"
|
||||
#include "core/templates/fixed_vector.h"
|
||||
#include "editor/docks/filesystem_dock.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_string_names.h"
|
||||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "editor/file_system/editor_file_system.h"
|
||||
#include "editor/file_system/editor_paths.h"
|
||||
#include "editor/gui/editor_toaster.h"
|
||||
|
|
@ -146,17 +150,19 @@ String EditorQuickOpenDialog::get_dialog_title(const Vector<StringName> &p_base_
|
|||
return TTR("Select Scene");
|
||||
}
|
||||
|
||||
return TTR("Select") + " " + p_base_types[0];
|
||||
return vformat(TTR("Select %s"), p_base_types[0]);
|
||||
}
|
||||
|
||||
void EditorQuickOpenDialog::popup_dialog(const Vector<StringName> &p_base_types, const Callable &p_item_selected_callback) {
|
||||
void EditorQuickOpenDialog::popup_dialog(const Vector<StringName> &p_base_types, const Callable &p_item_selected_callback, bool p_allow_type_switching) {
|
||||
ERR_FAIL_COND(p_base_types.is_empty());
|
||||
ERR_FAIL_COND(!p_item_selected_callback.is_valid());
|
||||
|
||||
property_object = nullptr;
|
||||
property_path = "";
|
||||
item_selected_callback = p_item_selected_callback;
|
||||
allow_type_switching = p_allow_type_switching;
|
||||
|
||||
is_cycling_items = false;
|
||||
container->init(p_base_types);
|
||||
container->set_instant_preview_toggle_visible(false);
|
||||
_finish_dialog_setup(p_base_types);
|
||||
|
|
@ -171,6 +177,7 @@ void EditorQuickOpenDialog::popup_dialog_for_property(const Vector<StringName> &
|
|||
property_path = p_path;
|
||||
item_selected_callback = p_item_selected_callback;
|
||||
initial_property_value = property_object->get(property_path);
|
||||
allow_type_switching = false;
|
||||
|
||||
// Reset this, so that the property isn't updated immediately upon opening
|
||||
// the window.
|
||||
|
|
@ -182,6 +189,7 @@ void EditorQuickOpenDialog::popup_dialog_for_property(const Vector<StringName> &
|
|||
}
|
||||
|
||||
void EditorQuickOpenDialog::_finish_dialog_setup(const Vector<StringName> &p_base_types) {
|
||||
set_process_shortcut_input(allow_type_switching);
|
||||
get_ok_button()->set_disabled(container->has_nothing_selected());
|
||||
set_title(get_dialog_title(p_base_types));
|
||||
popup_centered_clamped(Size2(780, 650) * EDSCALE, 0.8f);
|
||||
|
|
@ -202,15 +210,14 @@ bool EditorQuickOpenDialog::_is_instant_preview_active() const {
|
|||
}
|
||||
|
||||
void EditorQuickOpenDialog::selection_changed() {
|
||||
if (!_is_instant_preview_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This prevents the property from being changed the first time the Quick Open
|
||||
// window is opened.
|
||||
if (!initial_selection_performed) {
|
||||
initial_selection_performed = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_is_instant_preview_active()) {
|
||||
preview_property();
|
||||
}
|
||||
}
|
||||
|
|
@ -230,8 +237,11 @@ void EditorQuickOpenDialog::item_pressed(bool p_double_click) {
|
|||
}
|
||||
|
||||
void EditorQuickOpenDialog::preview_property() {
|
||||
Ref<Resource> loaded_resource = ResourceLoader::load(container->get_selected());
|
||||
ERR_FAIL_COND_MSG(loaded_resource.is_null(), "Cannot load resource from path '" + container->get_selected() + "'.");
|
||||
ERR_FAIL_COND(container->get_selected() == ResourceUID::INVALID_ID);
|
||||
String path = container->get_selected_path();
|
||||
|
||||
Ref<Resource> loaded_resource = ResourceLoader::load(path);
|
||||
ERR_FAIL_COND_MSG(loaded_resource.is_null(), "Cannot load resource from path '" + path + "'.");
|
||||
|
||||
Resource *res = Object::cast_to<Resource>(property_object);
|
||||
if (res) {
|
||||
|
|
@ -274,7 +284,7 @@ void EditorQuickOpenDialog::update_property() {
|
|||
ERR_FAIL_MSG(err_msg);
|
||||
}
|
||||
|
||||
item_selected_callback.call(container->get_selected());
|
||||
item_selected_callback.call(container->get_selected_path());
|
||||
}
|
||||
|
||||
void EditorQuickOpenDialog::cancel_pressed() {
|
||||
|
|
@ -289,6 +299,55 @@ void EditorQuickOpenDialog::cancel_pressed() {
|
|||
search_box->clear();
|
||||
}
|
||||
|
||||
void EditorQuickOpenDialog::shortcut_input(const Ref<InputEvent> &p_event) {
|
||||
// If the user is cycling through items (with up/down arrows), confirm selection when releasing the keys.
|
||||
Ref<InputEventWithModifiers> iewm = p_event;
|
||||
if (is_cycling_items && iewm.is_valid() && p_event->is_released() && iewm->get_modifiers_mask().is_empty()) {
|
||||
ok_pressed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_event.is_null() || !p_event->is_pressed() || p_event->is_echo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<StringName> new_base_types;
|
||||
if (EditorSettings *settings = EditorSettings::get_singleton()) {
|
||||
if (settings->is_shortcut("editor/quick_open", p_event)) {
|
||||
new_base_types.push_back("Resource");
|
||||
} else if (settings->is_shortcut("editor/quick_open_scene", p_event)) {
|
||||
new_base_types.push_back("PackedScene");
|
||||
} else if (settings->is_shortcut("editor/quick_open_script", p_event)) {
|
||||
new_base_types.push_back("Script");
|
||||
}
|
||||
}
|
||||
|
||||
if (new_base_types.size() != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're already showing this dialog type.
|
||||
const Vector<StringName> ¤t_base_types = container->get_base_types();
|
||||
if (current_base_types.size() == 1 && current_base_types[0] == new_base_types[0]) {
|
||||
// Already showing the requested dialog type, move next.
|
||||
Ref<InputEventKey> down_event = memnew(InputEventKey);
|
||||
down_event->set_keycode(Key::DOWN);
|
||||
down_event->set_pressed(true);
|
||||
container->handle_search_box_input(down_event);
|
||||
is_cycling_items = true;
|
||||
} else {
|
||||
// Switch to the new dialog type.
|
||||
container->init(new_base_types);
|
||||
container->set_instant_preview_toggle_visible(false);
|
||||
is_cycling_items = false;
|
||||
set_title(get_dialog_title(new_base_types));
|
||||
search_box->clear();
|
||||
search_box->grab_focus();
|
||||
}
|
||||
|
||||
set_input_as_handled();
|
||||
}
|
||||
|
||||
void EditorQuickOpenDialog::_search_box_text_changed(const String &p_query) {
|
||||
container->set_query_and_update(p_query);
|
||||
get_ok_button()->set_disabled(container->has_nothing_selected());
|
||||
|
|
@ -357,7 +416,7 @@ QuickOpenResultContainer::QuickOpenResultContainer() {
|
|||
|
||||
file_context_menu = memnew(PopupMenu);
|
||||
file_context_menu->add_item(TTR("Show in FileSystem"), FILE_SHOW_IN_FILESYSTEM);
|
||||
file_context_menu->add_item(TTR("Show in File Manager"), FILE_SHOW_IN_FILE_MANAGER);
|
||||
file_context_menu->add_item(OS::get_singleton()->get_platform_string(OS::PLATFORM_STRING_FILE_MANAGER_SHOW), FILE_SHOW_IN_FILE_MANAGER);
|
||||
file_context_menu->connect(SceneStringName(id_pressed), callable_mp(this, &QuickOpenResultContainer::_menu_option));
|
||||
file_context_menu->hide();
|
||||
scroll_container->add_child(file_context_menu);
|
||||
|
|
@ -417,12 +476,15 @@ QuickOpenResultContainer::QuickOpenResultContainer() {
|
|||
}
|
||||
|
||||
void QuickOpenResultContainer::_menu_option(int p_option) {
|
||||
ERR_FAIL_COND(get_selected() == ResourceUID::INVALID_ID);
|
||||
String selected_path = get_selected_path();
|
||||
|
||||
switch (p_option) {
|
||||
case FILE_SHOW_IN_FILESYSTEM: {
|
||||
FileSystemDock::get_singleton()->navigate_to_path(get_selected());
|
||||
FileSystemDock::get_singleton()->navigate_to_path(selected_path);
|
||||
} break;
|
||||
case FILE_SHOW_IN_FILE_MANAGER: {
|
||||
String dir = ProjectSettings::get_singleton()->globalize_path(get_selected());
|
||||
String dir = ProjectSettings::get_singleton()->globalize_path(selected_path);
|
||||
OS::get_singleton()->shell_show_in_file_manager(dir, true);
|
||||
} break;
|
||||
}
|
||||
|
|
@ -473,111 +535,146 @@ void QuickOpenResultContainer::init(const Vector<StringName> &p_base_types) {
|
|||
E->enable_highlights = enable_highlights;
|
||||
}
|
||||
|
||||
bool history_modified = false;
|
||||
|
||||
if (first_open && history_file->load(_get_cache_file_path()) == OK) {
|
||||
// Load history when opening for the first time.
|
||||
file_type_icons.insert(SNAME("__default_icon"), get_editor_theme_icon(SNAME("Object")));
|
||||
|
||||
bool history_modified = false;
|
||||
Vector<String> history_keys = history_file->get_section_keys("selected_history");
|
||||
for (const String &type : history_keys) {
|
||||
const StringName type_name = type;
|
||||
const PackedStringArray paths = history_file->get_value("selected_history", type);
|
||||
const PackedStringArray history_uids = history_file->get_value("selected_history", type);
|
||||
|
||||
PackedStringArray cleaned_paths;
|
||||
cleaned_paths.resize(paths.size());
|
||||
PackedStringArray cleaned_text_uids;
|
||||
cleaned_text_uids.resize(history_uids.size());
|
||||
|
||||
Vector<ResourceUID::ID> cleaned_ids;
|
||||
cleaned_ids.resize(history_uids.size());
|
||||
|
||||
Vector<QuickOpenResultCandidate> loaded_candidates;
|
||||
loaded_candidates.resize(paths.size());
|
||||
{
|
||||
QuickOpenResultCandidate *candidates_write = loaded_candidates.ptrw();
|
||||
String *cleanup_write = cleaned_paths.ptrw();
|
||||
String *text_write = cleaned_text_uids.ptrw();
|
||||
ResourceUID::ID *id_write = cleaned_ids.ptrw();
|
||||
int i = 0;
|
||||
for (String path : paths) {
|
||||
if (path.begins_with("uid://")) {
|
||||
ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(path);
|
||||
if (!ResourceUID::get_singleton()->has_id(id)) {
|
||||
for (String uid : history_uids) {
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (!uid.begins_with("uid://")) {
|
||||
// uid might be a path here, if config was written by older editor version
|
||||
ResourceUID::ID id = EditorFileSystem::get_singleton()->get_file_uid(uid);
|
||||
if (id == ResourceUID::INVALID_ID) {
|
||||
continue;
|
||||
}
|
||||
path = ResourceUID::get_singleton()->get_id_path(id);
|
||||
uid = ResourceUID::get_singleton()->id_to_text(id);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ResourceLoader::exists(path)) {
|
||||
ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(uid);
|
||||
if (id == ResourceUID::INVALID_ID || !ResourceUID::get_singleton()->has_id(id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filetypes.insert(path, type_name);
|
||||
QuickOpenResultCandidate candidate;
|
||||
_setup_candidate(candidate, path);
|
||||
candidates_write[i] = candidate;
|
||||
cleanup_write[i] = path;
|
||||
filetypes.insert(id, type_name);
|
||||
text_write[i] = uid;
|
||||
id_write[i] = id;
|
||||
i++;
|
||||
}
|
||||
loaded_candidates.resize(i);
|
||||
cleaned_paths.resize(i);
|
||||
selected_history.insert(type, loaded_candidates);
|
||||
|
||||
if (i < paths.size()) {
|
||||
cleaned_text_uids.resize(i);
|
||||
selected_history.insert(type, cleaned_ids);
|
||||
|
||||
if (i < history_uids.size()) {
|
||||
// Some paths removed, need to update history.
|
||||
if (i == 0) {
|
||||
history_file->erase_section_key("selected_history", type);
|
||||
} else {
|
||||
history_file->set_value("selected_history", type, cleaned_paths);
|
||||
history_file->set_value("selected_history", type, cleaned_text_uids);
|
||||
}
|
||||
history_modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (history_modified) {
|
||||
history_file->save(_get_cache_file_path());
|
||||
} else if (!first_open && base_types.size() == 1) {
|
||||
const StringName &type = base_types[0];
|
||||
Vector<ResourceUID::ID> *history = selected_history.getptr(type);
|
||||
|
||||
if (history) {
|
||||
Vector<ResourceUID::ID> clean_history;
|
||||
|
||||
for (const ResourceUID::ID &uid : *history) {
|
||||
if (ResourceUID::get_singleton()->has_id(uid)) {
|
||||
clean_history.push_back(uid);
|
||||
} else {
|
||||
history_modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (clean_history.is_empty()) {
|
||||
selected_history.erase(type);
|
||||
} else if (history_modified) {
|
||||
*history = clean_history;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (history_modified) {
|
||||
history_file->save(_get_cache_file_path());
|
||||
}
|
||||
|
||||
_create_initial_results();
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_sort_filepaths(int p_max_results) {
|
||||
void QuickOpenResultContainer::_sort_uids(int p_max_results) {
|
||||
struct FilepathComparator {
|
||||
bool operator()(const String &p_lhs, const String &p_rhs) const {
|
||||
bool operator()(const ResourceUID::ID &p_lhs, const ResourceUID::ID &p_rhs) const {
|
||||
String lhs_path = ResourceUID::get_singleton()->get_id_path(p_lhs);
|
||||
String rhs_path = ResourceUID::get_singleton()->get_id_path(p_rhs);
|
||||
|
||||
// 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();
|
||||
return lhs_path.length() == rhs_path.length() ? lhs_path < rhs_path : lhs_path.length() < rhs_path.length();
|
||||
}
|
||||
};
|
||||
|
||||
SortArray<String, FilepathComparator> sorter;
|
||||
if (filepaths.size() > p_max_results) {
|
||||
sorter.partial_sort(0, filepaths.size(), p_max_results, filepaths.ptrw());
|
||||
SortArray<ResourceUID::ID, FilepathComparator> sorter{};
|
||||
|
||||
if ((int)uids.size() > p_max_results) {
|
||||
sorter.partial_sort(0, uids.size(), p_max_results, uids.ptr());
|
||||
} else {
|
||||
sorter.sort(filepaths.ptrw(), filepaths.size());
|
||||
sorter.sort(uids.ptr(), uids.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();
|
||||
uids.clear();
|
||||
filetypes.clear();
|
||||
history_set.clear();
|
||||
Vector<QuickOpenResultCandidate> *history = _get_history();
|
||||
|
||||
Vector<ResourceUID::ID> *history = _get_history();
|
||||
if (history) {
|
||||
for (const QuickOpenResultCandidate &candidate : *history) {
|
||||
history_set.insert(candidate.file_path);
|
||||
for (const ResourceUID::ID &uid : *history) {
|
||||
history_set.insert(uid);
|
||||
}
|
||||
}
|
||||
_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());
|
||||
|
||||
_find_uids_in_folder(EditorFileSystem::get_singleton()->get_filesystem(), include_addons_toggle->is_pressed());
|
||||
_sort_uids(result_items.size());
|
||||
max_total_results = MIN(uids.size(), result_items.size());
|
||||
update_results();
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_find_filepaths_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons) {
|
||||
void QuickOpenResultContainer::_find_uids_in_folder(EditorFileSystemDirectory *p_directory, bool p_include_addons) {
|
||||
for (int i = 0; i < p_directory->get_subdir_count(); i++) {
|
||||
if (p_include_addons || p_directory->get_name() != "addons") {
|
||||
_find_filepaths_in_folder(p_directory->get_subdir(i), p_include_addons);
|
||||
_find_uids_in_folder(p_directory->get_subdir(i), p_include_addons);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_directory->get_file_count(); i++) {
|
||||
String file_path = p_directory->get_file_path(i);
|
||||
ResourceUID::ID uid = p_directory->get_file_uid(i);
|
||||
if (uid == ResourceUID::INVALID_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const StringName engine_type = p_directory->get_file_type(i);
|
||||
const StringName script_type = p_directory->get_file_resource_script_class(i);
|
||||
|
|
@ -589,8 +686,8 @@ void QuickOpenResultContainer::_find_filepaths_in_folder(EditorFileSystemDirecto
|
|||
bool is_valid = ClassDB::is_parent_class(engine_type, parent_type) || (!is_engine_type && EditorNode::get_editor_data().script_class_is_parent(script_type, parent_type));
|
||||
|
||||
if (is_valid) {
|
||||
filepaths.append(file_path);
|
||||
filetypes.insert(file_path, actual_type);
|
||||
uids.push_back(uid);
|
||||
filetypes.insert(uid, actual_type);
|
||||
break; // Stop testing base types as soon as we get a match.
|
||||
}
|
||||
}
|
||||
|
|
@ -602,26 +699,69 @@ void QuickOpenResultContainer::set_query_and_update(const String &p_query) {
|
|||
update_results();
|
||||
}
|
||||
|
||||
Vector<QuickOpenResultCandidate> *QuickOpenResultContainer::_get_history() {
|
||||
Vector<ResourceUID::ID> *QuickOpenResultContainer::_get_history() {
|
||||
if (base_types.size() == 1) {
|
||||
return selected_history.getptr(base_types[0]);
|
||||
}
|
||||
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;
|
||||
QuickOpenResultCandidate QuickOpenResultCandidate::from_uid(const ResourceUID::ID &p_uid, bool &r_success) {
|
||||
if (p_uid == ResourceUID::INVALID_ID || !ResourceUID::get_singleton()->has_id(p_uid)) {
|
||||
r_success = false;
|
||||
return QuickOpenResultCandidate();
|
||||
}
|
||||
|
||||
QuickOpenResultCandidate candidate;
|
||||
candidate.uid = p_uid;
|
||||
candidate.result = nullptr;
|
||||
r_success = true;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
QuickOpenResultCandidate QuickOpenResultCandidate::from_result(Ref<FuzzySearchMatch> p_result, bool &r_success) {
|
||||
ResourceUID::ID uid = EditorFileSystem::get_singleton()->get_file_uid(p_result->get_target());
|
||||
|
||||
QuickOpenResultCandidate candidate = from_uid(uid, r_success);
|
||||
if (!r_success) {
|
||||
return QuickOpenResultCandidate();
|
||||
}
|
||||
|
||||
candidate.result = p_result;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_add_candidate(QuickOpenResultCandidate &p_candidate) {
|
||||
ERR_FAIL_COND(!ResourceUID::get_singleton()->has_id(p_candidate.uid));
|
||||
|
||||
StringName actual_type;
|
||||
{
|
||||
StringName *actual_type_ptr = filetypes.getptr(p_filepath);
|
||||
StringName *actual_type_ptr = filetypes.getptr(p_candidate.uid);
|
||||
if (actual_type_ptr) {
|
||||
actual_type = *actual_type_ptr;
|
||||
} else {
|
||||
ERR_PRINT(vformat("EditorQuickOpenDialog: No type for path %s.", p_candidate.file_path));
|
||||
ERR_PRINT(vformat("EditorQuickOpenDialog: No type for path %s.", ResourceUID::get_singleton()->get_id_path(p_candidate.uid)));
|
||||
}
|
||||
}
|
||||
EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(p_candidate.file_path);
|
||||
|
||||
String file_path = ResourceUID::get_singleton()->get_id_path(p_candidate.uid);
|
||||
|
||||
// Verify that a PackedScene is actually a "real" Scene if in a Open Scene context.
|
||||
if (base_types[0] == SNAME("PackedScene")) {
|
||||
static FixedVector<String, 3> valid_extensions = { "tscn", "scn", "res" };
|
||||
bool is_valid_type = false;
|
||||
for (const String &ext : valid_extensions) {
|
||||
if (file_path.has_extension(ext)) {
|
||||
is_valid_type = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_valid_type) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EditorResourcePreview::PreviewItem item = EditorResourcePreview::get_singleton()->get_resource_preview_if_available(file_path);
|
||||
if (item.preview.is_valid()) {
|
||||
p_candidate.thumbnail = item.preview;
|
||||
} else if (file_type_icons.has(actual_type)) {
|
||||
|
|
@ -632,67 +772,84 @@ void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_cand
|
|||
} else {
|
||||
p_candidate.thumbnail = *file_type_icons.getptr(SNAME("__default_icon"));
|
||||
}
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_setup_candidate(QuickOpenResultCandidate &p_candidate, const FuzzySearchResult &p_result) {
|
||||
_setup_candidate(p_candidate, p_result.target);
|
||||
p_candidate.result = &p_result;
|
||||
candidates.push_back(p_candidate);
|
||||
candidates_uids.insert(p_candidate.uid);
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::update_results() {
|
||||
candidates.clear();
|
||||
candidates_uids.clear();
|
||||
|
||||
if (query.is_empty()) {
|
||||
_use_default_candidates();
|
||||
} else {
|
||||
_score_and_sort_candidates();
|
||||
}
|
||||
|
||||
_update_result_items(MIN(candidates.size(), max_total_results), 0);
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_use_default_candidates() {
|
||||
HashSet<String> existing_paths;
|
||||
Vector<QuickOpenResultCandidate> *history = _get_history();
|
||||
Vector<ResourceUID::ID> *history = _get_history();
|
||||
if (history) {
|
||||
candidates.append_array(*history);
|
||||
for (const QuickOpenResultCandidate &candi : *history) {
|
||||
existing_paths.insert(candi.file_path);
|
||||
for (const ResourceUID::ID &uid : *history) {
|
||||
bool success;
|
||||
QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
_add_candidate(candidate);
|
||||
}
|
||||
}
|
||||
int i = candidates.size();
|
||||
|
||||
candidates.resize(MIN(max_total_results, filepaths.size()));
|
||||
QuickOpenResultCandidate *candidates_w = candidates.ptrw();
|
||||
int count = candidates.size();
|
||||
|
||||
for (const String &filepath : filepaths) {
|
||||
if (i >= count) {
|
||||
for (const ResourceUID::ID &uid : uids) {
|
||||
if (candidates.size() >= max_total_results) {
|
||||
break;
|
||||
}
|
||||
if (existing_paths.has(filepath)) {
|
||||
if (candidates_uids.has(uid)) {
|
||||
continue;
|
||||
}
|
||||
_setup_candidate(candidates_w[i++], filepath);
|
||||
|
||||
bool success;
|
||||
QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_uid(uid, success);
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_add_candidate(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_update_fuzzy_search_results() {
|
||||
Vector<Ref<FuzzySearchMatch>> QuickOpenResultContainer::_get_fuzzy_search_results() {
|
||||
FuzzySearch fuzzy_search;
|
||||
fuzzy_search.start_offset = 6; // Don't match against "res://" at the start of each filepath.
|
||||
fuzzy_search.set_query(query);
|
||||
fuzzy_search.max_results = max_total_results;
|
||||
fuzzy_search.set_start_offset(6); // Don't match against "res://" at the start of each filepath.
|
||||
fuzzy_search.set_case_sensitive(!query.is_lowercase());
|
||||
fuzzy_search.set_max_results(max_total_results);
|
||||
bool fuzzy_matching = EDITOR_GET("filesystem/quick_open_dialog/enable_fuzzy_matching");
|
||||
int max_misses = EDITOR_GET("filesystem/quick_open_dialog/max_fuzzy_misses");
|
||||
fuzzy_search.allow_subsequences = fuzzy_matching;
|
||||
fuzzy_search.max_misses = fuzzy_matching ? max_misses : 0;
|
||||
fuzzy_search.search_all(filepaths, search_results);
|
||||
fuzzy_search.set_use_exact_tokens(!fuzzy_matching);
|
||||
fuzzy_search.set_max_misses(fuzzy_matching ? max_misses : 0);
|
||||
|
||||
PackedStringArray paths;
|
||||
paths.reserve_exact(uids.size());
|
||||
|
||||
for (const ResourceUID::ID &uid : uids) {
|
||||
paths.push_back(ResourceUID::get_singleton()->get_id_path(uid));
|
||||
}
|
||||
|
||||
return fuzzy_search.search_all(query, paths);
|
||||
}
|
||||
|
||||
void QuickOpenResultContainer::_score_and_sort_candidates() {
|
||||
_update_fuzzy_search_results();
|
||||
candidates.resize(search_results.size());
|
||||
QuickOpenResultCandidate *candidates_write = candidates.ptrw();
|
||||
for (const FuzzySearchResult &result : search_results) {
|
||||
_setup_candidate(*candidates_write++, result);
|
||||
for (const Ref<FuzzySearchMatch> &result : _get_fuzzy_search_results()) {
|
||||
bool success;
|
||||
QuickOpenResultCandidate candidate = QuickOpenResultCandidate::from_result(result, success);
|
||||
if (!success) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_add_candidate(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -718,7 +875,7 @@ void QuickOpenResultContainer::_update_result_items(int p_new_visible_results_co
|
|||
no_results_container->set_visible(!any_results);
|
||||
|
||||
if (!any_results) {
|
||||
if (filepaths.is_empty()) {
|
||||
if (uids.is_empty()) {
|
||||
no_results_label->set_text(TTR("No files found for this type"));
|
||||
} else {
|
||||
no_results_label->set_text(TTR("No results found"));
|
||||
|
|
@ -815,8 +972,8 @@ void QuickOpenResultContainer::_select_item(int p_index) {
|
|||
}
|
||||
|
||||
result_items[selection_index]->highlight_item(true);
|
||||
bool in_history = history_set.has(candidates[selection_index].file_path);
|
||||
file_details_path->set_text(get_selected() + (in_history ? TTR(" (recently opened)") : ""));
|
||||
bool in_history = history_set.has(candidates[selection_index].uid);
|
||||
file_details_path->set_text(get_selected_path() + (in_history ? TTR(" (recently opened)") : ""));
|
||||
|
||||
emit_signal(SNAME("selection_changed"));
|
||||
|
||||
|
|
@ -926,9 +1083,20 @@ bool QuickOpenResultContainer::has_nothing_selected() const {
|
|||
return selection_index < 0;
|
||||
}
|
||||
|
||||
String QuickOpenResultContainer::get_selected() const {
|
||||
ERR_FAIL_COND_V_MSG(has_nothing_selected(), String(), "Tried to get selected file, but nothing was selected.");
|
||||
return candidates[selection_index].file_path;
|
||||
ResourceUID::ID QuickOpenResultContainer::get_selected() const {
|
||||
ERR_FAIL_COND_V_MSG(has_nothing_selected(), ResourceUID::INVALID_ID, "Tried to get selected file, but nothing was selected.");
|
||||
return candidates[selection_index].uid;
|
||||
}
|
||||
|
||||
String QuickOpenResultContainer::get_selected_path() const {
|
||||
ERR_FAIL_COND_V_MSG(has_nothing_selected(), "", "Tried to get selected file path, but nothing was selected.");
|
||||
String path = ResourceUID::get_singleton()->get_id_path(candidates[selection_index].uid);
|
||||
ERR_FAIL_COND_V_MSG(path.is_empty(), "", "Failed to get selected file path.");
|
||||
return path;
|
||||
}
|
||||
|
||||
const Vector<StringName> &QuickOpenResultContainer::get_base_types() const {
|
||||
return base_types;
|
||||
}
|
||||
|
||||
QuickOpenDisplayMode QuickOpenResultContainer::get_adaptive_display_mode(const Vector<StringName> &p_base_types) {
|
||||
|
|
@ -971,40 +1139,39 @@ void QuickOpenResultContainer::save_selected_item() {
|
|||
}
|
||||
|
||||
const StringName &base_type = base_types[0];
|
||||
QuickOpenResultCandidate &selected = candidates.write[selection_index];
|
||||
Vector<QuickOpenResultCandidate> *type_history = selected_history.getptr(base_type);
|
||||
ResourceUID::ID selected = get_selected();
|
||||
Vector<ResourceUID::ID> *type_history = selected_history.getptr(base_type);
|
||||
|
||||
if (!type_history) {
|
||||
selected_history.insert(base_type, Vector<QuickOpenResultCandidate>());
|
||||
selected_history.insert(base_type, Vector<ResourceUID::ID>());
|
||||
type_history = selected_history.getptr(base_type);
|
||||
} else {
|
||||
for (int i = 0; i < type_history->size(); i++) {
|
||||
if (selected.file_path == type_history->get(i).file_path) {
|
||||
if (selected == type_history->get(i)) {
|
||||
type_history->remove_at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selected.result = nullptr;
|
||||
history_set.insert(selected.file_path);
|
||||
history_set.insert(selected);
|
||||
type_history->insert(0, selected);
|
||||
if (type_history->size() > MAX_HISTORY_SIZE) {
|
||||
type_history->resize(MAX_HISTORY_SIZE);
|
||||
}
|
||||
|
||||
PackedStringArray paths;
|
||||
paths.resize(type_history->size());
|
||||
PackedStringArray history_uids;
|
||||
history_uids.resize(type_history->size());
|
||||
{
|
||||
String *paths_write = paths.ptrw();
|
||||
String *uids_write = history_uids.ptrw();
|
||||
|
||||
int i = 0;
|
||||
for (const QuickOpenResultCandidate &candidate : *type_history) {
|
||||
paths_write[i] = _get_uid_string(candidate.file_path);
|
||||
for (const ResourceUID::ID &uid : *type_history) {
|
||||
uids_write[i] = ResourceUID::get_singleton()->id_to_text(uid);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
history_file->set_value("selected_history", base_type, paths);
|
||||
history_file->set_value("selected_history", base_type, history_uids);
|
||||
history_file->save(_get_cache_file_path());
|
||||
}
|
||||
|
||||
|
|
@ -1200,16 +1367,18 @@ QuickOpenResultListItem::QuickOpenResultListItem() {
|
|||
|
||||
void QuickOpenResultListItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
|
||||
thumbnail->set_texture(p_candidate.thumbnail);
|
||||
name->set_text(p_candidate.file_path.get_file());
|
||||
path->set_text(p_candidate.file_path.get_base_dir());
|
||||
|
||||
String file_path = ResourceUID::get_singleton()->get_id_path(p_candidate.uid);
|
||||
name->set_text(file_path.get_file());
|
||||
path->set_text(file_path.get_base_dir());
|
||||
name->reset_highlights();
|
||||
path->reset_highlights();
|
||||
|
||||
if (p_highlight && p_candidate.result != nullptr) {
|
||||
for (const FuzzyTokenMatch &match : p_candidate.result->token_matches) {
|
||||
if (p_highlight && p_candidate.result.is_valid()) {
|
||||
for (const FuzzyTokenMatch &match : p_candidate.result->get_token_matches()) {
|
||||
for (const Vector2i &interval : match.substrings) {
|
||||
path->add_highlight(_get_path_interval(interval, p_candidate.result->dir_index));
|
||||
name->add_highlight(_get_name_interval(interval, p_candidate.result->dir_index));
|
||||
path->add_highlight(_get_path_interval(interval, p_candidate.result->get_dir_index()));
|
||||
name->add_highlight(_get_name_interval(interval, p_candidate.result->get_dir_index()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1271,14 +1440,16 @@ QuickOpenResultGridItem::QuickOpenResultGridItem() {
|
|||
|
||||
void QuickOpenResultGridItem::set_content(const QuickOpenResultCandidate &p_candidate, bool p_highlight) {
|
||||
thumbnail->set_texture(p_candidate.thumbnail);
|
||||
name->set_text(p_candidate.file_path.get_file());
|
||||
name->set_tooltip_text(p_candidate.file_path);
|
||||
|
||||
String file_path = ResourceUID::get_singleton()->get_id_path(p_candidate.uid);
|
||||
name->set_text(file_path.get_file());
|
||||
name->set_tooltip_text(file_path);
|
||||
name->reset_highlights();
|
||||
|
||||
if (p_highlight && p_candidate.result != nullptr) {
|
||||
for (const FuzzyTokenMatch &match : p_candidate.result->token_matches) {
|
||||
if (p_highlight && p_candidate.result.is_valid()) {
|
||||
for (const FuzzyTokenMatch &match : p_candidate.result->get_token_matches()) {
|
||||
for (const Vector2i &interval : match.substrings) {
|
||||
name->add_highlight(_get_name_interval(interval, p_candidate.result->dir_index));
|
||||
name->add_highlight(_get_name_interval(interval, p_candidate.result->get_dir_index()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue