Make EditorFileDialog inherit FileDialog

This commit is contained in:
kobewi 2025-12-02 12:30:51 +01:00
parent f5918a9d35
commit c1cc178a82
23 changed files with 253 additions and 3285 deletions

View file

@ -49,7 +49,7 @@
#include "scene/theme/theme_db.h"
void FileDialog::popup_file_dialog() {
popup_centered_clamped(Size2i(700, 500), 0.8f);
popup_centered_clamped(Vector2(1050, 700) * get_theme_default_base_scale(), 0.8f);
_focus_file_text();
}
@ -88,30 +88,13 @@ void FileDialog::_native_popup() {
}
}
bool FileDialog::_can_use_native_popup() {
bool FileDialog::_can_use_native_popup() const {
if (access == ACCESS_RESOURCES || access == ACCESS_USERDATA || options.size() > 0) {
return DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_EXTRA);
}
return DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE);
}
void FileDialog::_popup_base(const Rect2i &p_rect) {
_update_option_controls();
#ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) {
ConfirmationDialog::_popup_base(p_rect);
return;
}
#endif
if (_can_use_native_popup() && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
_native_popup();
} else {
ConfirmationDialog::_popup_base(p_rect);
}
}
void FileDialog::set_visible(bool p_visible) {
if (p_visible) {
_update_option_controls();
@ -124,7 +107,7 @@ void FileDialog::set_visible(bool p_visible) {
}
#endif
if (_can_use_native_popup() && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
if (_should_use_native_popup()) {
if (p_visible) {
_native_popup();
}
@ -228,6 +211,10 @@ void FileDialog::_native_dialog_cb_with_options(bool p_ok, const Vector<String>
}
}
bool FileDialog::_should_use_native_popup() const {
return _can_use_native_popup() && (use_native_dialog || OS::get_singleton()->is_sandboxed());
}
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.
@ -245,7 +232,7 @@ void FileDialog::_notification(int p_what) {
#endif
// Replace the built-in dialog with the native one if it started visible.
if (is_visible() && _can_use_native_popup() && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
if (is_visible() && _should_use_native_popup()) {
ConfirmationDialog::set_visible(false);
_native_popup();
}
@ -259,6 +246,21 @@ void FileDialog::_notification(int p_what) {
}
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
update_filters();
[[fallthrough]];
}
case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
if (main_vbox->is_layout_rtl()) {
_setup_button(dir_prev, theme_cache.forward_folder);
_setup_button(dir_next, theme_cache.back_folder);
} else {
_setup_button(dir_prev, theme_cache.back_folder);
_setup_button(dir_next, theme_cache.forward_folder);
}
} break;
case NOTIFICATION_THEME_CHANGED: {
favorite_list->set_custom_minimum_size(Vector2(128 * get_theme_default_base_scale(), 0));
recent_list->set_custom_minimum_size(Vector2(128 * get_theme_default_base_scale(), 0));
@ -284,8 +286,22 @@ void FileDialog::_notification(int p_what) {
invalidate();
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
update_filters();
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
if (!is_visible()) {
return;
}
// Check if the current directory was removed externally (much less likely to happen while the window is focused).
const String previous_dir = get_current_dir();
while (!dir_access->dir_exists(get_current_dir())) {
_go_up();
// In case we can't go further up, use some fallback and break.
if (get_current_dir() == previous_dir) {
_dir_submitted(OS::get_singleton()->get_user_data_dir());
break;
}
}
} break;
}
}
@ -304,10 +320,6 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
void FileDialog::set_enable_multiple_selection(bool p_enable) {
file_list->set_select_mode(p_enable ? ItemList::SELECT_MULTI : ItemList::SELECT_SINGLE);
}
Vector<String> FileDialog::get_selected_files() const {
const String current_dir = dir_access->get_current_dir();
Vector<String> list;
@ -356,10 +368,6 @@ void FileDialog::_dir_submitted(String p_dir) {
_push_history();
}
void FileDialog::_file_submitted(const String &p_file) {
_action_pressed();
}
void FileDialog::_save_confirm_pressed() {
_save_to_recent();
@ -525,24 +533,6 @@ bool FileDialog::_is_open_should_be_disabled() {
return false;
}
void FileDialog::_thumbnail_callback(const Ref<Texture2D> &p_texture, const String &p_path) {
if (display_mode == DISPLAY_LIST || p_texture.is_null()) {
return;
}
if (!p_path.begins_with(full_dir)) {
return;
}
const String file_name = p_path.get_file();
for (int i = 0; i < file_list->get_item_count(); i++) {
if (file_list->get_item_text(i) == file_name) {
file_list->set_item_icon(i, p_texture);
break;
}
}
}
void FileDialog::_go_up() {
_change_dir("..");
_push_history();
@ -819,7 +809,6 @@ void FileDialog::update_file_list() {
LocalVector<String> files;
LocalVector<String> dirs;
bool is_hidden;
String item = dir_access->get_next();
while (!item.is_empty()) {
@ -828,9 +817,7 @@ void FileDialog::update_file_list() {
continue;
}
is_hidden = dir_access->current_is_hidden();
if (show_hidden_files || !is_hidden) {
if (show_hidden_files || (!dir_access->current_is_hidden() && !_should_hide_file(item))) {
if (!dir_access->current_is_dir()) {
files.push_back(item);
} else {
@ -913,7 +900,7 @@ void FileDialog::update_file_list() {
} else {
file_list->add_item(info.name, info.bundle ? theme_cache.file : theme_cache.folder);
}
file_list->set_item_icon_modulate(-1, theme_cache.folder_icon_color);
file_list->set_item_icon_modulate(-1, _get_folder_color(base_dir.path_join(info.name)));
Dictionary d;
d["name"] = info.name;
@ -977,26 +964,27 @@ void FileDialog::update_file_list() {
file_list->add_item(info.name);
const String path = base_dir.path_join(info.name);
if (display_mode == DISPLAY_LIST) {
Ref<Texture2D> icon;
if (get_icon_callback.is_valid()) {
const Variant &v = path;
const Variant *argptrs[1] = { &v };
Variant vicon;
Ref<Texture2D> icon;
if (get_icon_callback.is_valid()) {
const Variant &v = path;
const Variant *argptrs[1] = { &v };
Variant vicon;
Callable::CallError ce;
get_icon_callback.callp(argptrs, 1, vicon, ce);
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
ERR_PRINT(vformat("Error calling FileDialog's icon callback: %s.", Variant::get_callable_error_text(get_icon_callback, argptrs, 1, ce)));
}
icon = vicon;
Callable::CallError ce;
get_icon_callback.callp(argptrs, 1, vicon, ce);
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
ERR_PRINT(vformat("Error calling FileDialog's icon callback: %s.", Variant::get_callable_error_text(get_icon_callback, argptrs, 1, ce)));
}
icon = vicon;
}
if (display_mode == DISPLAY_LIST) {
if (icon.is_null()) {
icon = theme_cache.file;
}
file_list->set_item_icon(-1, icon);
} else { // DISPLAY_THUMBNAILS
Ref<Texture2D> icon;
Ref<Texture2D> thumbnail;
if (get_thumbnail_callback.is_valid()) {
const Variant &v = path;
const Variant *argptrs[1] = { &v };
@ -1007,12 +995,15 @@ void FileDialog::update_file_list() {
if (unlikely(ce.error != Callable::CallError::CALL_OK)) {
ERR_PRINT(vformat("Error calling FileDialog's thumbnail callback: %s.", Variant::get_callable_error_text(get_thumbnail_callback, argptrs, 1, ce)));
}
icon = vicon;
thumbnail = vicon;
}
if (icon.is_null()) {
icon = theme_cache.file;
if (thumbnail.is_null()) {
thumbnail = theme_cache.file;
}
file_list->set_item_icon(-1, thumbnail);
if (icon.is_valid()) {
file_list->set_item_tag_icon(-1, icon);
}
file_list->set_item_icon(-1, icon);
}
file_list->set_item_icon_modulate(-1, theme_cache.file_icon_color);
@ -1381,7 +1372,7 @@ FileDialog::FileMode FileDialog::get_file_mode() const {
}
void FileDialog::set_display_mode(DisplayMode p_mode) {
ERR_FAIL_INDEX((int)p_mode, 2);
ERR_FAIL_INDEX((int)p_mode, DISPLAY_MAX);
if (display_mode == p_mode) {
return;
}
@ -1731,6 +1722,7 @@ void FileDialog::_update_favorite_list() {
favorite_list->add_item(favorited_names[i], theme_cache.folder);
favorite_list->set_item_tooltip(-1, favorited_paths[i]);
favorite_list->set_item_metadata(-1, favorited_paths[i]);
favorite_list->set_item_icon_modulate(-1, _get_folder_color(favorited_paths[i]));
if (i == current_favorite) {
favorite_button->set_pressed(true);
@ -1818,6 +1810,7 @@ void FileDialog::_update_recent_list() {
recent_list->add_item(recent_dir_names[i], theme_cache.folder);
recent_list->set_item_tooltip(-1, recent_dir_paths[i]);
recent_list->set_item_metadata(-1, recent_dir_paths[i]);
recent_list->set_item_icon_modulate(-1, _get_folder_color(recent_dir_paths[i]));
}
}
@ -2053,6 +2046,7 @@ void FileDialog::_bind_methods() {
ClassDB::bind_static_method("FileDialog", D_METHOD("set_get_icon_callback", "callback"), &FileDialog::set_get_icon_callback);
ClassDB::bind_static_method("FileDialog", D_METHOD("set_get_thumbnail_callback", "callback"), &FileDialog::set_get_thumbnail_callback);
ClassDB::bind_method(D_METHOD("popup_file_dialog"), &FileDialog::popup_file_dialog);
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
@ -2213,7 +2207,7 @@ void FileDialog::set_use_native_dialog(bool p_native) {
#endif
// Replace the built-in dialog with the native one if it's currently visible.
if (is_inside_tree() && is_visible() && _can_use_native_popup() && (use_native_dialog || OS::get_singleton()->is_sandboxed())) {
if (is_inside_tree() && _should_use_native_popup()) {
ConfirmationDialog::set_visible(false);
_native_popup();
}
@ -2229,7 +2223,6 @@ FileDialog::FileDialog() {
set_size(Size2(640, 360));
set_default_ok_text(ETR("Save")); // Default mode text.
set_process_shortcut_input(true);
thumbnail_callback = callable_mp(this, &FileDialog::_thumbnail_callback);
for (int i = 0; i < CUSTOMIZATION_MAX; i++) {
customization_flags[i] = true;
@ -2336,6 +2329,7 @@ FileDialog::FileDialog() {
{
Label *label = memnew(Label(ETR("Favorites:")));
label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
label->set_theme_type_variation("HeaderSmall");
fav_hbox->add_child(label);
}
@ -2363,6 +2357,7 @@ FileDialog::FileDialog() {
{
Label *label = memnew(Label(ETR("Recent:")));
label->set_theme_type_variation("HeaderSmall");
recent_vbox->add_child(label);
}
@ -2503,7 +2498,7 @@ FileDialog::FileDialog() {
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));
filename_edit->connect(SceneStringName(text_submitted), callable_mp(this, &FileDialog::_action_pressed).unbind(1));
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);