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

@ -1,36 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorFileDialog" inherits="ConfirmationDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<class name="EditorFileDialog" inherits="FileDialog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modified version of [FileDialog] used by the editor.
</brief_description>
<description>
[EditorFileDialog] is an enhanced version of [FileDialog] available only to editor plugins. Additional features include list of favorited/recent files and the ability to see files as thumbnails grid instead of list.
Unlike [FileDialog], [EditorFileDialog] does not have a property for using native dialogs. Instead, native dialogs can be enabled globally via the [member EditorSettings.interface/editor/use_native_file_dialogs] editor setting. They are also enabled automatically when running in sandbox (e.g. on macOS).
[EditorFileDialog] is a [FileDialog] tweaked to work in the editor. It automatically handles favorite and recent directory lists, and synchronizes some properties with their corresponding editor settings.
[EditorFileDialog] will automatically show a native dialog based on the [member EditorSettings.interface/editor/use_native_file_dialogs] editor setting and ignores [member FileDialog.use_native_dialog].
[b]Note:[/b] [EditorFileDialog] is invisible by default. To make it visible, call one of the [code]popup_*[/code] methods from [Window] on the node, such as [method Window.popup_centered_clamped].
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_filter">
<return type="void" />
<param index="0" name="filter" type="String" />
<param index="1" name="description" type="String" default="&quot;&quot;" />
<description>
Adds a comma-separated file name [param filter] option to the [EditorFileDialog] with an optional [param description], which restricts what files can be picked.
A [param filter] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
For example, a [param filter] of [code]"*.tscn, *.scn"[/code] and a [param description] of [code]"Scenes"[/code] results in filter text "Scenes (*.tscn, *.scn)".
</description>
</method>
<method name="add_option">
<return type="void" />
<param index="0" name="name" type="String" />
<param index="1" name="values" type="PackedStringArray" />
<param index="2" name="default_value_index" type="int" />
<description>
Adds an additional [OptionButton] to the file dialog. If [param values] is empty, a [CheckBox] is added instead.
[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="add_side_menu" deprecated="This feature is no longer supported.">
<return type="void" />
<param index="0" name="menu" type="Control" />
@ -39,199 +19,10 @@
This method is kept for compatibility and does nothing. As an alternative, you can display another dialog after showing the file dialog.
</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>
Removes all filters except for "All Files (*.*)".
</description>
</method>
<method name="get_filename_filter" qualifiers="const">
<return type="String" />
<description>
Returns the value of the filter for file names.
</description>
</method>
<method name="get_line_edit">
<return type="LineEdit" />
<description>
Returns the LineEdit for the selected file.
[b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member CanvasItem.visible] property.
</description>
</method>
<method name="get_option_default" qualifiers="const">
<return type="int" />
<param index="0" name="option" type="int" />
<description>
Returns the default value index of the [OptionButton] or [CheckBox] with index [param option].
</description>
</method>
<method name="get_option_name" qualifiers="const">
<return type="String" />
<param index="0" name="option" type="int" />
<description>
Returns the name of the [OptionButton] or [CheckBox] with index [param option].
</description>
</method>
<method name="get_option_values" qualifiers="const">
<return type="PackedStringArray" />
<param index="0" name="option" type="int" />
<description>
Returns an array of values of the [OptionButton] with index [param option].
</description>
</method>
<method name="get_selected_options" qualifiers="const">
<return type="Dictionary" />
<description>
Returns a [Dictionary] with the selected values of the additional [OptionButton]s and/or [CheckBox]es. [Dictionary] keys are names and values are selected value indices.
</description>
</method>
<method name="get_vbox">
<return type="VBoxContainer" />
<description>
Returns the [VBoxContainer] used to display the file system.
[b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member CanvasItem.visible] property.
</description>
</method>
<method name="invalidate">
<return type="void" />
<description>
Notify the [EditorFileDialog] that its view of the data is no longer accurate. Updates the view contents on next view update.
</description>
</method>
<method name="popup_file_dialog">
<return type="void" />
<description>
Shows the [EditorFileDialog] at the default size and position for file dialogs in the editor, and selects the file name if there is a current file.
</description>
</method>
<method name="set_filename_filter">
<return type="void" />
<param index="0" name="filter" type="String" />
<description>
Sets the value of the filter for file names.
</description>
</method>
<method name="set_option_default">
<return type="void" />
<param index="0" name="option" type="int" />
<param index="1" name="default_value_index" type="int" />
<description>
Sets the default value index of the [OptionButton] or [CheckBox] with index [param option].
</description>
</method>
<method name="set_option_name">
<return type="void" />
<param index="0" name="option" type="int" />
<param index="1" name="name" type="String" />
<description>
Sets the name of the [OptionButton] or [CheckBox] with index [param option].
</description>
</method>
<method name="set_option_values">
<return type="void" />
<param index="0" name="option" type="int" />
<param index="1" name="values" type="PackedStringArray" />
<description>
Sets the option values of the [OptionButton] with index [param option].
</description>
</method>
</methods>
<members>
<member name="access" type="int" setter="set_access" getter="get_access" enum="EditorFileDialog.Access" default="0">
The location from which the user may select a file, including [code]res://[/code], [code]user://[/code], and the local file system.
</member>
<member name="current_dir" type="String" setter="set_current_dir" getter="get_current_dir">
The currently occupied directory.
</member>
<member name="current_file" type="String" setter="set_current_file" getter="get_current_file">
The currently selected file.
</member>
<member name="current_path" type="String" setter="set_current_path" getter="get_current_path">
The file system path in the address bar.
</member>
<member name="dialog_hide_on_ok" type="bool" setter="set_hide_on_ok" getter="get_hide_on_ok" overrides="AcceptDialog" default="false" />
<member name="disable_overwrite_warning" type="bool" setter="set_disable_overwrite_warning" getter="is_overwrite_warning_disabled" default="false">
<member name="disable_overwrite_warning" type="bool" setter="set_disable_overwrite_warning" getter="is_overwrite_warning_disabled" default="false" deprecated="Use [member FileDialog.overwrite_warning_enabled] instead.">
If [code]true[/code], the [EditorFileDialog] will not warn the user before overwriting files.
</member>
<member name="display_mode" type="int" setter="set_display_mode" getter="get_display_mode" enum="EditorFileDialog.DisplayMode" default="0">
The view format in which the [EditorFileDialog] displays resources to the user.
</member>
<member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="EditorFileDialog.FileMode" default="4">
The dialog's open or save mode, which affects the selection behavior.
</member>
<member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()">
The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code]. Multiple file types can also be specified in a single filter. [code]"*.png, *.jpg, *.jpeg ; Supported Images"[/code] will show both PNG and JPEG files when selected.
</member>
<member name="option_count" type="int" setter="set_option_count" getter="get_option_count" default="0">
The number of additional [OptionButton]s and [CheckBox]es in the dialog.
</member>
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog]. This property is synchronized with [member EditorSettings.filesystem/file_dialog/show_hidden_files].
</member>
<member name="title" type="String" setter="set_title" getter="get_title" overrides="Window" default="&quot;Save a File&quot;" />
</members>
<signals>
<signal name="dir_selected">
<param index="0" name="dir" type="String" />
<description>
Emitted when a directory is selected.
</description>
</signal>
<signal name="file_selected">
<param index="0" name="path" type="String" />
<description>
Emitted when a file is selected.
</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>
Emitted when multiple files are selected.
</description>
</signal>
</signals>
<constants>
<constant name="FILE_MODE_OPEN_FILE" value="0" enum="FileMode">
The [EditorFileDialog] can select only one file. Accepting the window will open the file.
</constant>
<constant name="FILE_MODE_OPEN_FILES" value="1" enum="FileMode">
The [EditorFileDialog] can select multiple files. Accepting the window will open all files.
</constant>
<constant name="FILE_MODE_OPEN_DIR" value="2" enum="FileMode">
The [EditorFileDialog] can select only one directory. Accepting the window will open the directory.
</constant>
<constant name="FILE_MODE_OPEN_ANY" value="3" enum="FileMode">
The [EditorFileDialog] can select a file or directory. Accepting the window will open it.
</constant>
<constant name="FILE_MODE_SAVE_FILE" value="4" enum="FileMode">
The [EditorFileDialog] can select only one file. Accepting the window will save the file.
</constant>
<constant name="ACCESS_RESOURCES" value="0" enum="Access">
The [EditorFileDialog] can only view [code]res://[/code] directory contents.
</constant>
<constant name="ACCESS_USERDATA" value="1" enum="Access">
The [EditorFileDialog] can only view [code]user://[/code] directory contents.
</constant>
<constant name="ACCESS_FILESYSTEM" value="2" enum="Access">
The [EditorFileDialog] can view the entire local file system.
</constant>
<constant name="DISPLAY_THUMBNAILS" value="0" enum="DisplayMode">
The [EditorFileDialog] displays resources as thumbnails.
</constant>
<constant name="DISPLAY_LIST" value="1" enum="DisplayMode">
The [EditorFileDialog] displays resources as a list of filenames.
</constant>
</constants>
</class>

View file

@ -118,6 +118,12 @@
Returns [code]true[/code] if the provided [param flag] is enabled.
</description>
</method>
<method name="popup_file_dialog">
<return type="void" />
<description>
Shows the [FileDialog] using the default size and position for file dialogs, and selects the file name if there is a current file.
</description>
</method>
<method name="set_customization_flag_enabled">
<return type="void" />
<param index="0" name="flag" type="int" enum="FileDialog.Customization" />
@ -274,6 +280,7 @@
[b]Note:[/b] On Linux and macOS, sandboxed apps always use native dialogs to access the host file system.
[b]Note:[/b] On macOS, sandboxed apps will save security-scoped bookmarks to retain access to the opened folders across multiple sessions. Use [method OS.get_granted_permissions] to get a list of saved bookmarks.
[b]Note:[/b] Native dialogs are isolated from the base process, file dialog properties can't be modified once the dialog is shown.
[b]Note:[/b] This property is ignored in [EditorFileDialog].
</member>
</members>
<signals>

View file

@ -30,6 +30,7 @@
#include "asset_library_editor_plugin.h"
#include "core/io/dir_access.h"
#include "core/io/json.h"
#include "core/io/stream_peer_tls.h"
#include "core/os/keyboard.h"

View file

@ -2695,7 +2695,7 @@ int FileSystemDock::_get_menu_option_from_key(const Ref<InputEventKey> &p_key) {
return FILE_MENU_OPEN_EXTERNAL;
} else if (ED_IS_SHORTCUT("filesystem_dock/open_in_terminal", p_key)) {
return FILE_MENU_OPEN_IN_TERMINAL;
} else if (ED_IS_SHORTCUT("file_dialog/focus_path", p_key)) {
} else if (ED_IS_SHORTCUT("filesystem_dock/focus_path", p_key)) {
return EXTRA_FOCUS_PATH;
} else if (ED_IS_SHORTCUT("editor/open_search", p_key)) {
return EXTRA_FOCUS_FILTER;
@ -4234,6 +4234,11 @@ FileSystemDock::FileSystemDock() {
ED_SHORTCUT("filesystem_dock/open_in_terminal", TTRC("Open in Terminal"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::T);
#endif
ED_SHORTCUT("filesystem_dock/focus_path", TTRC("Focus Path"), KeyModifierMask::CMD_OR_CTRL | Key::L);
// Allow both Cmd + L and Cmd + Shift + G to match Safari's and Finder's shortcuts respectively.
ED_SHORTCUT_OVERRIDE_ARRAY("filesystem_dock/focus_path", "macos",
{ int32_t(KeyModifierMask::META | Key::L), int32_t(KeyModifierMask::META | KeyModifierMask::SHIFT | Key::G) });
// Properly translating color names would require a separate HashMap, so for simplicity they are provided as comments.
folder_colors["red"] = Color(1.0, 0.271, 0.271); // TTR("Red")
folder_colors["orange"] = Color(1.0, 0.561, 0.271); // TTR("Orange")

View file

@ -1029,8 +1029,6 @@ void EditorNode::_notification(int p_what) {
if (EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog")) {
FileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
FileDialog::set_default_display_mode(EDITOR_GET("filesystem/file_dialog/display_mode"));
EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
}
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/tablet_driver")) {
@ -1251,10 +1249,6 @@ void EditorNode::_fs_changed() {
E->invalidate();
}
for (EditorFileDialog *E : editor_file_dialogs) {
E->invalidate();
}
_mark_unsaved_scenes();
// FIXME: Move this to a cleaner location, it's hacky to do this in _fs_changed.
@ -5967,14 +5961,6 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog) {
singleton->file_dialogs.erase(p_dialog);
}
void EditorNode::_editor_file_dialog_register(EditorFileDialog *p_dialog) {
singleton->editor_file_dialogs.insert(p_dialog);
}
void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) {
singleton->editor_file_dialogs.erase(p_dialog);
}
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
void EditorNode::_begin_first_scan() {
@ -8038,8 +8024,6 @@ EditorNode::EditorNode() {
FileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
FileDialog::set_default_display_mode(EDITOR_GET("filesystem/file_dialog/display_mode"));
EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
int swap_cancel_ok = EDITOR_GET("interface/editor/accept_dialog_cancel_ok_buttons");
if (swap_cancel_ok != 0) { // 0 is auto, set in register_scene based on DisplayServer.
@ -8182,10 +8166,6 @@ EditorNode::EditorNode() {
FileDialog::register_func = _file_dialog_register;
FileDialog::unregister_func = _file_dialog_unregister;
EditorFileDialog::get_icon_func = _file_dialog_get_icon;
EditorFileDialog::register_func = _editor_file_dialog_register;
EditorFileDialog::unregister_func = _editor_file_dialog_unregister;
editor_export = memnew(EditorExport);
add_child(editor_export);
@ -9263,12 +9243,7 @@ EditorNode::~EditorNode() {
FileDialog::register_func = nullptr;
FileDialog::unregister_func = nullptr;
EditorFileDialog::get_icon_func = nullptr;
EditorFileDialog::register_func = nullptr;
EditorFileDialog::unregister_func = nullptr;
file_dialogs.clear();
editor_file_dialogs.clear();
singleton = nullptr;
}

View file

@ -481,7 +481,6 @@ private:
HashSet<String> textfile_extensions;
HashSet<String> other_file_extensions;
HashSet<FileDialog *> file_dialogs;
HashSet<EditorFileDialog *> editor_file_dialogs;
Vector<Ref<EditorResourceConversionPlugin>> resource_conversion_plugins;
PrintHandlerList print_handler;
@ -521,8 +520,6 @@ private:
static void _file_dialog_register(FileDialog *p_dialog);
static void _file_dialog_unregister(FileDialog *p_dialog);
static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
static void _file_access_close_error_notify(const String &p_str);
static void _file_access_close_error_notify_impl(const String &p_str);

View file

@ -1401,27 +1401,6 @@ void ProjectExportDialog::_open_export_template_manager() {
EditorNode::get_singleton()->open_export_template_manager();
}
void ProjectExportDialog::_validate_export_path(const String &p_path) {
// Disable export via OK button or Enter key if LineEdit has an empty filename
bool invalid_path = (p_path.get_file().get_basename().is_empty());
// Check if state change before needlessly messing with signals
if (invalid_path && export_project->get_ok_button()->is_disabled()) {
return;
}
if (!invalid_path && !export_project->get_ok_button()->is_disabled()) {
return;
}
if (invalid_path) {
export_project->get_ok_button()->set_disabled(true);
export_project->get_line_edit()->disconnect(SceneStringName(text_submitted), callable_mp(export_project, &EditorFileDialog::_file_submitted));
} else {
export_project->get_ok_button()->set_disabled(false);
export_project->get_line_edit()->connect(SceneStringName(text_submitted), callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
}
void ProjectExportDialog::_export_project() {
Ref<EditorExportPreset> current = get_current_preset();
ERR_FAIL_COND(current.is_null());
@ -1446,16 +1425,6 @@ void ProjectExportDialog::_export_project() {
export_project->set_current_file(default_filename);
}
}
// Ensure that signal is connected if previous attempt left it disconnected
// with _validate_export_path.
// FIXME: This is a hack, we should instead change EditorFileDialog to allow
// disabling validation by the "text_submitted" signal.
if (!export_project->get_line_edit()->is_connected(SceneStringName(text_submitted), callable_mp(export_project, &EditorFileDialog::_file_submitted))) {
export_project->get_ok_button()->set_disabled(false);
export_project->get_line_edit()->connect(SceneStringName(text_submitted), callable_mp(export_project, &EditorFileDialog::_file_submitted));
}
export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
export_project->popup_file_dialog();
}
@ -2041,7 +2010,6 @@ ProjectExportDialog::ProjectExportDialog() {
export_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(export_project);
export_project->connect("file_selected", callable_mp(this, &ProjectExportDialog::_export_project_to_path));
export_project->get_line_edit()->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_validate_export_path));
export_project->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));
export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));

View file

@ -199,7 +199,6 @@ class ProjectExportDialog : public ConfirmationDialog {
void _export_pck_zip();
void _export_pck_zip_selected(const String &p_path);
void _validate_export_path(const String &p_path);
void _export_project();
void _export_project_to_path(const String &p_path);
void _export_all_dialog();

File diff suppressed because it is too large Load diff

View file

@ -30,348 +30,30 @@
#pragma once
#include "core/io/dir_access.h"
#include "editor/file_system/file_info.h"
#include "scene/gui/dialogs.h"
#include "scene/property_list_helper.h"
#include "scene/gui/file_dialog.h"
class DependencyRemoveDialog;
class GridContainer;
class HSplitContainer;
class HFlowContainer;
class ItemList;
class MenuButton;
class OptionButton;
class PopupMenu;
class TextureRect;
class VSeparator;
class EditorFileDialog : public ConfirmationDialog {
GDCLASS(EditorFileDialog, ConfirmationDialog);
class EditorFileDialog : public FileDialog {
GDCLASS(EditorFileDialog, FileDialog);
public:
enum DisplayMode {
DISPLAY_THUMBNAILS,
DISPLAY_LIST
};
enum Access {
ACCESS_RESOURCES,
ACCESS_USERDATA,
ACCESS_FILESYSTEM
};
enum FileMode {
FILE_MODE_OPEN_FILE,
FILE_MODE_OPEN_FILES,
FILE_MODE_OPEN_DIR,
FILE_MODE_OPEN_ANY,
FILE_MODE_SAVE_FILE
};
typedef Ref<Texture2D> (*GetIconFunc)(const String &);
typedef void (*RegisterFunc)(EditorFileDialog *);
static inline GetIconFunc get_icon_func = nullptr;
static inline GetIconFunc get_thumbnail_func = nullptr;
static inline RegisterFunc register_func = nullptr;
static inline RegisterFunc unregister_func = nullptr;
private:
enum ItemMenu {
ITEM_MENU_COPY_PATH,
ITEM_MENU_DELETE,
ITEM_MENU_REFRESH,
ITEM_MENU_NEW_FOLDER,
ITEM_MENU_SHOW_IN_EXPLORER,
ITEM_MENU_SHOW_BUNDLE_CONTENT,
};
ConfirmationDialog *makedialog = nullptr;
LineEdit *makedirname = nullptr;
VSeparator *makedir_sep = nullptr;
Button *makedir = nullptr;
Access access = ACCESS_RESOURCES;
HFlowContainer *flow_checkbox_options = nullptr;
GridContainer *grid_select_options = nullptr;
VBoxContainer *vbox = nullptr;
FileMode mode = FILE_MODE_SAVE_FILE;
bool can_create_dir = false;
LineEdit *dir = nullptr;
Button *dir_prev = nullptr;
Button *dir_next = nullptr;
Button *dir_up = nullptr;
HBoxContainer *drives_container = nullptr;
HBoxContainer *shortcuts_container = nullptr;
OptionButton *drives = nullptr;
ItemList *item_list = nullptr;
PopupMenu *item_menu = nullptr;
TextureRect *preview = nullptr;
VBoxContainer *preview_vb = nullptr;
HSplitContainer *body_hsplit = nullptr;
HSplitContainer *list_hb = nullptr;
HBoxContainer *file_box = nullptr;
LineEdit *file = nullptr;
OptionButton *filter = nullptr;
AcceptDialog *error_dialog = nullptr;
Ref<DirAccess> dir_access;
ConfirmationDialog *confirm_save = nullptr;
DependencyRemoveDialog *dep_remove_dialog = nullptr;
ConfirmationDialog *global_remove_dialog = nullptr;
VBoxContainer *vbc = nullptr;
HBoxContainer *pathhb = nullptr;
Button *mode_thumbnails = nullptr;
Button *mode_list = nullptr;
Button *refresh = nullptr;
Button *favorite = nullptr;
Button *show_hidden = nullptr;
Button *show_search_filter_button = nullptr;
String search_string;
bool show_search_filter = false;
HBoxContainer *filter_hb = nullptr;
LineEdit *filter_box = nullptr;
FileSortOption file_sort = FileSortOption::FILE_SORT_NAME;
MenuButton *file_sort_button = nullptr;
Button *fav_up = nullptr;
Button *fav_down = nullptr;
ItemList *favorites = nullptr;
ItemList *recent = nullptr;
Vector<String> local_history;
int local_history_pos = 0;
void _push_history();
Vector<String> filters;
Vector<String> processed_filters;
bool previews_enabled = true;
bool preview_waiting = false;
int preview_wheel_index = 0;
float preview_wheel_timeout = 0.0f;
static inline bool default_show_hidden_files = false;
static inline DisplayMode default_display_mode = DISPLAY_THUMBNAILS;
bool show_hidden_files;
DisplayMode display_mode;
bool disable_overwrite_warning = false;
bool is_invalidating = false;
struct ThemeCache {
Ref<Texture2D> parent_folder;
Ref<Texture2D> forward_folder;
Ref<Texture2D> back_folder;
Ref<Texture2D> open_folder;
Ref<Texture2D> reload;
Ref<Texture2D> toggle_hidden;
Ref<Texture2D> toggle_filename_filter;
Ref<Texture2D> favorite;
Ref<Texture2D> mode_thumbnails;
Ref<Texture2D> mode_list;
Ref<Texture2D> create_folder;
Ref<Texture2D> favorites_up;
Ref<Texture2D> favorites_down;
Ref<Texture2D> filter_box;
Ref<Texture2D> file_sort_button;
Ref<Texture2D> file;
Ref<Texture2D> folder;
Color folder_icon_color;
Ref<Texture2D> action_copy;
Ref<Texture2D> action_delete;
Ref<Texture2D> filesystem;
Ref<Texture2D> folder_medium_thumbnail;
Ref<Texture2D> file_medium_thumbnail;
Ref<Texture2D> folder_big_thumbnail;
Ref<Texture2D> file_big_thumbnail;
Ref<Texture2D> progress[8]{};
} theme_cache;
struct Option {
String name;
Vector<String> values;
int default_idx = 0;
};
static inline PropertyListHelper base_property_helper;
PropertyListHelper property_helper;
Vector<Option> options;
Dictionary selected_options;
bool options_dirty = false;
String full_dir;
void update_dir();
void update_file_name();
void update_file_list();
void update_search_filter_gui();
void update_filters();
void _focus_file_text();
void _update_favorites();
void _favorite_pressed();
void _favorite_selected(int p_idx);
void _favorite_move_up();
void _favorite_move_down();
void _update_recent();
void _recent_selected(int p_idx);
void _item_selected(int p_item);
void _multi_selected(int p_item, bool p_selected);
void _items_clear_selection(const Vector2 &p_pos, MouseButton p_mouse_button_index);
void _item_dc_selected(int p_item);
void _item_list_item_rmb_clicked(int p_item, const Vector2 &p_pos, MouseButton p_mouse_button_index);
void _item_list_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index);
void _item_menu_id_pressed(int p_option);
void _select_drive(int p_idx);
void _dir_submitted(const String &p_dir);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
void _filter_selected(int);
void _make_dir();
void _make_dir_confirm();
void _focus_filter_box();
void _filter_changed(const String &p_text);
void _search_filter_selected();
void _file_sort_popup(int p_id);
void _delete_items();
void _delete_files_global();
void _update_drives(bool p_select = true);
void _update_icons();
void _go_up();
void _go_back();
void _go_forward();
void _invalidate();
virtual void _post_popup() override;
void _save_to_recent();
// Callback function is callback(String p_path,Ref<Texture2D> preview,Variant udata) preview null if could not load.
void _thumbnail_result(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview);
void _thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview);
void _request_single_thumbnail(const String &p_path);
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool _is_open_should_be_disabled();
void _native_popup();
void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options);
TypedArray<Dictionary> _get_options() const;
void _update_option_controls();
void _option_changed_checkbox_toggled(bool p_pressed, const String &p_name);
void _option_changed_item_selected(int p_idx, const String &p_name);
DependencyRemoveDialog *dependency_remove_dialog = nullptr;
protected:
virtual void _update_theme_item_cache() override;
virtual void _item_menu_id_pressed(int p_option) override;
virtual bool _should_use_native_popup() const override;
virtual bool _should_hide_file(const String &p_file) const override;
virtual Color _get_folder_color(const String &p_path) const override;
virtual void _popup_base(const Rect2i &p_rect = Rect2i()) override;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); }
bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); }
void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); }
bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); }
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
virtual void set_visible(bool p_visible) override;
// Public for use with callable_mp.
void _file_submitted(const String &p_file);
void popup_file_dialog();
void clear_filters();
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_search_filter();
void set_search_filter(const String &p_search_filter);
String get_search_filter() const;
void set_enable_multiple_selection(bool p_enable);
Vector<String> get_selected_files() const;
String get_current_dir() const;
String get_current_file() const;
String get_current_path() const;
void set_current_dir(const String &p_dir);
void set_current_file(const String &p_file);
void set_current_path(const String &p_path);
String get_option_name(int p_option) const;
Vector<String> get_option_values(int p_option) const;
int get_option_default(int p_option) const;
void set_option_name(int p_option, const String &p_name);
void set_option_values(int p_option, const Vector<String> &p_values);
void set_option_default(int p_option, int p_index);
void add_option(const String &p_name, const Vector<String> &p_values, int p_index);
void set_option_count(int p_count);
int get_option_count() const;
Dictionary get_selected_options() const;
void set_display_mode(DisplayMode p_mode);
DisplayMode get_display_mode() const;
void set_file_mode(FileMode p_mode);
FileMode get_file_mode() const;
VBoxContainer *get_vbox();
LineEdit *get_line_edit() { return file; }
void set_access(Access p_access);
Access get_access() const;
static void set_default_show_hidden_files(bool p_show);
static void set_default_display_mode(DisplayMode p_mode);
void set_show_hidden_files(bool p_show);
void set_show_search_filter(bool p_show);
bool is_showing_hidden_files() const;
void invalidate();
void set_disable_overwrite_warning(bool p_disable);
bool is_overwrite_warning_disabled() const;
void set_previews_enabled(bool p_enabled);
bool are_previews_enabled();
#ifndef DISABLE_DEPRECATED
void add_side_menu(Control *p_menu, const String &p_title = "") { ERR_FAIL_MSG("add_side_menu() is kept for compatibility and does nothing. For similar functionality, you can show another dialog after file dialog."); }
void set_disable_overwrite_warning(bool p_disable) { set_customization_flag_enabled(CUSTOMIZATION_OVERWRITE_WARNING, !p_disable); }
bool is_overwrite_warning_disabled() const { return !is_customization_flag_enabled(CUSTOMIZATION_OVERWRITE_WARNING); }
#endif
EditorFileDialog();
~EditorFileDialog();
};
VARIANT_ENUM_CAST(EditorFileDialog::FileMode);
VARIANT_ENUM_CAST(EditorFileDialog::Access);
VARIANT_ENUM_CAST(EditorFileDialog::DisplayMode);

View file

@ -978,7 +978,6 @@ void ProjectDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
fdialog_project = memnew(EditorFileDialog);
fdialog_project->set_previews_enabled(false); // Crucial, otherwise the engine crashes.
fdialog_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
fdialog_project->connect("dir_selected", callable_mp(this, &ProjectDialog::_project_path_selected));
fdialog_project->connect("file_selected", callable_mp(this, &ProjectDialog::_project_path_selected));
@ -1188,7 +1187,6 @@ ProjectDialog::ProjectDialog() {
spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
default_files_container->add_child(spacer);
fdialog_install = memnew(EditorFileDialog);
fdialog_install->set_previews_enabled(false); //Crucial, otherwise the engine crashes.
fdialog_install->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
add_child(fdialog_install);

View file

@ -1366,11 +1366,11 @@ ProjectManager::ProjectManager() {
EditorScale::set_scale(EDITOR_GET("interface/editor/custom_display_scale"));
break;
}
EditorFileDialog::get_icon_func = &ProjectManager::_file_dialog_get_icon;
EditorFileDialog::get_thumbnail_func = &ProjectManager::_file_dialog_get_thumbnail;
FileDialog::set_get_icon_callback(callable_mp_static(ProjectManager::_file_dialog_get_icon));
FileDialog::set_get_thumbnail_callback(callable_mp_static(ProjectManager::_file_dialog_get_thumbnail));
EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
FileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
FileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
int swap_cancel_ok = EDITOR_GET("interface/editor/accept_dialog_cancel_ok_buttons");
if (swap_cancel_ok != 0) { // 0 is auto, set in register_scene based on DisplayServer.
@ -1735,7 +1735,6 @@ ProjectManager::ProjectManager() {
quick_settings_dialog->connect("restart_required", callable_mp(this, &ProjectManager::_restart_confirmed));
scan_dir = memnew(EditorFileDialog);
scan_dir->set_previews_enabled(false);
scan_dir->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
scan_dir->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
scan_dir->set_title(TTRC("Select a Folder to Scan")); // Must be after mode or it's overridden.

View file

@ -459,7 +459,7 @@ void ScriptCreateDialog::_browse_path(bool browse_parent, bool p_save) {
file_browse->set_title(TTR("Open Script"));
}
file_browse->set_disable_overwrite_warning(true);
file_browse->set_customization_flag_enabled(FileDialog::CUSTOMIZATION_OVERWRITE_WARNING, false);
file_browse->clear_filters();
List<String> extensions;

View file

@ -54,6 +54,7 @@
#include "main/main.h"
#include "modules/regex/regex.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/file_dialog.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
@ -1591,7 +1592,17 @@ void EditorSettings::save_project_metadata() {
project_metadata_dirty = false;
}
void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
void EditorSettings::set_favorites(const Vector<String> &p_favorites, bool p_update_file_dialog) {
if (p_update_file_dialog) {
FileDialog::set_favorite_list(p_favorites);
} else if (p_favorites == favorites) {
// If the list came from EditorFileDialog, it may be the same as before.
return;
}
set_favorites_bind(p_favorites);
}
void EditorSettings::set_favorites_bind(const Vector<String> &p_favorites) {
favorites = p_favorites;
String favorites_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
@ -1627,7 +1638,17 @@ HashMap<String, PackedStringArray> EditorSettings::get_favorite_properties() con
return favorite_properties;
}
void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs, bool p_update_file_dialog) {
if (p_update_file_dialog) {
FileDialog::set_recent_list(p_recent_dirs);
} else if (p_recent_dirs == recent_dirs) {
// If the list came from EditorFileDialog, it may be the same as before.
return;
}
set_recent_dirs_bind(p_recent_dirs);
}
void EditorSettings::set_recent_dirs_bind(const Vector<String> &p_recent_dirs) {
recent_dirs = p_recent_dirs;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
@ -1671,6 +1692,7 @@ void EditorSettings::load_favorites_and_recent_dirs() {
line = f->get_line().strip_edges();
}
}
FileDialog::set_favorite_list(favorites);
/// Inspector Favorites
@ -1701,6 +1723,7 @@ void EditorSettings::load_favorites_and_recent_dirs() {
line = f->get_line().strip_edges();
}
}
FileDialog::set_recent_list(recent_dirs);
}
HashMap<StringName, Color> EditorSettings::get_godot2_text_editor_theme() {
@ -2237,9 +2260,9 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
ClassDB::bind_method(D_METHOD("get_project_metadata", "section", "key", "default"), &EditorSettings::get_project_metadata, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("set_favorites", "dirs"), &EditorSettings::set_favorites);
ClassDB::bind_method(D_METHOD("set_favorites", "dirs"), &EditorSettings::set_favorites_bind);
ClassDB::bind_method(D_METHOD("get_favorites"), &EditorSettings::get_favorites);
ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs);
ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs_bind);
ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs);
ClassDB::bind_method(D_METHOD("set_builtin_action_override", "name", "actions_list"), &EditorSettings::set_builtin_action_override);

View file

@ -177,11 +177,13 @@ public:
Variant get_project_metadata(const String &p_section, const String &p_key, const Variant &p_default) const;
void save_project_metadata();
void set_favorites(const Vector<String> &p_favorites);
void set_favorites(const Vector<String> &p_favorites, bool p_update_file_dialog = true);
void set_favorites_bind(const Vector<String> &p_favorites);
Vector<String> get_favorites() const;
void set_favorite_properties(const HashMap<String, PackedStringArray> &p_favorite_properties);
HashMap<String, PackedStringArray> get_favorite_properties() const;
void set_recent_dirs(const Vector<String> &p_recent_dirs);
void set_recent_dirs(const Vector<String> &p_recent_dirs, bool p_update_file_dialog = true);
void set_recent_dirs_bind(const Vector<String> &p_recent_dirs);
Vector<String> get_recent_dirs() const;
void load_favorites_and_recent_dirs();

View file

@ -306,7 +306,7 @@ void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) {
handled = true;
}
if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) {
if (ED_IS_SHORTCUT("filesystem_dock/focus_path", p_event)) {
_focus_current_path_box();
handled = true;
}

View file

@ -31,6 +31,7 @@
#include "shader_create_dialog.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "editor/editor_node.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_validation_panel.h"
@ -261,7 +262,7 @@ void ShaderCreateDialog::_browse_path() {
file_browse->set_title(TTR("Open Shader / Choose Location"));
file_browse->set_ok_button_text(TTR("Open"));
file_browse->set_disable_overwrite_warning(true);
file_browse->set_customization_flag_enabled(FileDialog::CUSTOMIZATION_OVERWRITE_WARNING, false);
file_browse->clear_filters();
List<String> extensions = type_data.get(type_menu->get_selected()).extensions;

View file

@ -1050,6 +1050,8 @@ void ThemeClassic::populate_standard_styles(const Ref<EditorTheme> &p_theme, Edi
p_theme->set_color("folder_icon_color", "FileDialog", (p_config.dark_icon_and_font ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(p_config.accent_color, 0.7));
p_theme->set_color("file_disabled_color", "FileDialog", p_config.font_disabled_color);
p_theme->set_constant("thumbnail_size", "EditorFileDialog", p_config.thumb_size);
// PopupDialog.
p_theme->set_stylebox(SceneStringName(panel), "PopupDialog", p_config.popup_style);

View file

@ -1003,6 +1003,8 @@ void ThemeModern::populate_standard_styles(const Ref<EditorTheme> &p_theme, Edit
p_theme->set_color("folder_icon_color", "FileDialog", (p_config.dark_icon_and_font ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(p_config.accent_color, 0.7));
p_theme->set_color("file_disabled_color", "FileDialog", p_config.font_disabled_color);
p_theme->set_constant("thumbnail_size", "EditorFileDialog", p_config.thumb_size);
// PopupDialog.
p_theme->set_stylebox(SceneStringName(panel), "PopupDialog", p_config.dialog_style);

View file

@ -174,3 +174,54 @@ Validate extension JSON: Error: Field 'classes/GLTFState/methods/get_unique_name
Validate extension JSON: Error: Field 'classes/GLTFState/methods/get_use_named_skin_binds': is_const changed value in new API, from false to true.
GLTFState getters made const. Compatibility methods registered.
GH-111212
---------
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/add_filter
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/add_option
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/add_side_menu
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/clear_filename_filter
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/clear_filters
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_access
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_current_dir
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_current_file
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_current_path
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_display_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_file_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_filename_filter
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_filters
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_line_edit
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_option_count
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_option_default
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_option_name
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_option_values
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_selected_options
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/get_vbox
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/invalidate
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/is_showing_hidden_files
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/popup_file_dialog
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_access
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_current_dir
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_current_file
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_current_path
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_display_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_file_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_filename_filter
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_filters
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_option_count
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_option_default
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_option_name
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_option_values
Validate extension JSON: API was removed: classes/EditorFileDialog/methods/set_show_hidden_files
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/access
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/current_dir
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/current_file
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/current_path
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/display_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/file_mode
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/filters
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/option_count
Validate extension JSON: API was removed: classes/EditorFileDialog/properties/show_hidden_files
The errors are false-positives. The removed methods are now part of the new parent class.

View file

@ -31,6 +31,7 @@
#include "openxr_action_map_editor.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "editor/editor_node.h"
#include "editor/gui/editor_bottom_panel.h"
#include "editor/gui/editor_file_dialog.h"

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);

View file

@ -127,6 +127,7 @@ public:
enum DisplayMode {
DISPLAY_THUMBNAILS,
DISPLAY_LIST,
DISPLAY_MAX
};
enum ItemMenu {
@ -184,7 +185,6 @@ private:
FileMode mode = FILE_MODE_SAVE_FILE;
DisplayMode display_mode = DISPLAY_THUMBNAILS;
FileSortOption file_sort = FileSortOption::NAME;
Ref<DirAccess> dir_access;
Vector<String> filters;
Vector<String> processed_filters;
@ -204,7 +204,6 @@ private:
String root_prefix;
String full_dir;
Callable thumbnail_callback;
bool is_invalidating = false;
VBoxContainer *main_vbox = nullptr;
@ -299,7 +298,6 @@ private:
void update_filters();
void update_customization();
void _item_menu_id_pressed(int p_option);
void _empty_clicked(const Vector2 &p_pos, MouseButton p_button);
void _item_clicked(int p_item, const Vector2 &p_pos, MouseButton p_button);
void _popup_menu(const Vector2 &p_pos, int p_for_item);
@ -314,7 +312,6 @@ private:
void _select_drive(int p_idx);
void _dir_submitted(String p_dir);
void _file_submitted(const String &p_file);
void _action_pressed();
void _save_confirm_pressed();
void _cancel_pressed();
@ -352,7 +349,6 @@ private:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
bool _can_use_native_popup();
void _native_popup();
void _native_dialog_cb(bool p_ok, const Vector<String> &p_files, int p_filter);
void _native_dialog_cb_with_options(bool p_ok, const Vector<String> &p_files, int p_filter, const Dictionary &p_selected_options);
@ -368,7 +364,15 @@ private:
virtual void _post_popup() override;
protected:
virtual void _popup_base(const Rect2i &p_rect = Rect2i()) override;
Ref<DirAccess> dir_access;
bool _can_use_native_popup() const;
virtual void _item_menu_id_pressed(int p_option);
virtual bool _should_use_native_popup() const;
virtual bool _should_hide_file(const String &p_file) const { return false; }
virtual Color _get_folder_color(const String &p_path) const { return theme_cache.folder_icon_color; }
void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); }
@ -376,6 +380,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list); }
bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); }
bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); }
static void _bind_methods();
#ifndef DISABLE_DEPRECATED
@ -396,7 +401,6 @@ public:
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;
String get_current_dir() const;
@ -446,6 +450,7 @@ public:
VBoxContainer *get_vbox() { return main_vbox; }
LineEdit *get_line_edit() { return filename_edit; }
ItemList *get_file_item_list() { return file_list; }
void set_access(Access p_access);
Access get_access() const;