From 263a2bdec6c45dda0a9e0b73d9e6e7e17292c1ba Mon Sep 17 00:00:00 2001 From: kobewi Date: Thu, 9 Oct 2025 22:31:55 +0200 Subject: [PATCH] Rework FileDialog shortcuts --- core/input/input_map.cpp | 23 +++++++ core/input/shortcut.cpp | 11 ++++ core/input/shortcut.h | 2 + doc/classes/ProjectSettings.xml | 15 +++++ scene/gui/file_dialog.cpp | 102 ++++++++++++-------------------- scene/gui/file_dialog.h | 7 +++ 6 files changed, 97 insertions(+), 63 deletions(-) diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 8603e999b32..c25cac7d1eb 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -403,9 +403,12 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_graph_delete", TTRC("Delete Nodes") }, { "ui_graph_follow_left", TTRC("Follow Input Port Connection") }, { "ui_graph_follow_right", TTRC("Follow Output Port Connection") }, + { "ui_filedialog_delete", TTRC("Delete") }, { "ui_filedialog_up_one_level", TTRC("Go Up One Level") }, { "ui_filedialog_refresh", TTRC("Refresh") }, { "ui_filedialog_show_hidden", TTRC("Show Hidden") }, + { "ui_filedialog_find", TTRC("Find") }, + { "ui_filedialog_focus_path", TTRC("Focus Path") }, { "ui_swap_input_direction ", TTRC("Swap Input Direction") }, { "ui_unicode_start", TTRC("Start Unicode Character Input") }, { "ui_colorpicker_delete_preset", TTRC("ColorPicker: Delete Preset") }, @@ -804,6 +807,10 @@ const HashMap>> &InputMap::get_builtins() { default_builtin_cache.insert("ui_graph_follow_right.macos", inputs); // ///// UI File Dialog Shortcuts ///// + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE)); + default_builtin_cache.insert("ui_filedialog_delete", inputs); + inputs = List>(); inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE)); default_builtin_cache.insert("ui_filedialog_up_one_level", inputs); @@ -816,6 +823,22 @@ const HashMap>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(Key::H)); default_builtin_cache.insert("ui_filedialog_show_hidden", inputs); + inputs = List>(); + inputs.push_back(InputEventKey::create_reference(Key::F | KeyModifierMask::CMD_OR_CTRL)); + default_builtin_cache.insert("ui_filedialog_find", inputs); + + inputs = List>(); + // Ctrl + L (matches most Windows/Linux file managers' "focus on path bar" shortcut, + // plus macOS Safari's "focus on address bar" shortcut). + inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::CMD_OR_CTRL)); + default_builtin_cache.insert("ui_filedialog_focus_path", inputs); + + inputs = List>(); + // Cmd + Shift + G (matches Finder's "Go To" shortcut). + inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::CMD_OR_CTRL)); + inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::CMD_OR_CTRL)); + default_builtin_cache.insert("ui_filedialog_focus_path.macos", inputs); + inputs = List>(); inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL)); default_builtin_cache.insert("ui_swap_input_direction", inputs); diff --git a/core/input/shortcut.cpp b/core/input/shortcut.cpp index 2301e00179e..72646262377 100644 --- a/core/input/shortcut.cpp +++ b/core/input/shortcut.cpp @@ -85,6 +85,17 @@ String Shortcut::get_as_text() const { return "None"; } +Ref Shortcut::make_from_action(const StringName &p_action) { + Ref event; + event.instantiate(); + event->set_action(p_action); + + Ref shortcut; + shortcut.instantiate(); + shortcut->set_events({ event }); + return shortcut; +} + bool Shortcut::has_valid_event() const { // Tests if there is ANY input event which is valid. for (int i = 0; i < events.size(); i++) { diff --git a/core/input/shortcut.h b/core/input/shortcut.h index 5c0548276a0..80c80bcd5fa 100644 --- a/core/input/shortcut.h +++ b/core/input/shortcut.h @@ -52,5 +52,7 @@ public: String get_as_text() const; + static Ref make_from_action(const StringName &p_action); + static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2); }; diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 8c6d2fb3eed..69cc7f6c756 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1287,6 +1287,21 @@ Default [InputEventAction] to go to the end position of a [Control] (e.g. last item in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_END] on typical desktop UI systems. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + + Default [InputEventAction] to delete the selected file in a [FileDialog]. + [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + + + Default [InputEventAction] to open file filter in a [FileDialog]. + [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + + + Default [InputEventAction] to focus path edit field in a [FileDialog]. + [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + + + macOS specific override for the shortcut to focus path edit field in [FileDialog]. + Default [InputEventAction] to refresh the contents of the current directory of a [FileDialog]. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 2a4ea9a47a0..cef4321fcff 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -255,8 +255,6 @@ void FileDialog::_notification(int p_what) { _update_favorite_list(); _update_recent_list(); invalidate(); // Put it here to preview in the editor. - } else { - set_process_shortcut_input(false); } } break; @@ -292,65 +290,15 @@ void FileDialog::_notification(int p_what) { } void FileDialog::shortcut_input(const Ref &p_event) { - ERR_FAIL_COND(p_event.is_null()); + if (p_event.is_null() || p_event->is_released() || p_event->is_echo()) { + return; + } - Ref k = p_event; - if (k.is_valid() && has_focus()) { - if (k->is_pressed()) { - bool handled = true; - - switch (k->get_keycode()) { - case Key::H: { - if (k->is_command_or_control_pressed()) { - set_show_hidden_files(!show_hidden_files); - } else { - handled = false; - } - - } break; - case Key::F: { - if (k->is_command_or_control_pressed()) { - show_filename_filter_button->set_pressed(!show_filename_filter_button->is_pressed()); - } else { - handled = false; - } - - } break; - case Key::F5: { - invalidate(); - } break; - case Key::BACKSPACE: { - _dir_submitted(".."); - } break; -#ifdef MACOS_ENABLED - // Cmd + Shift + G (matches Finder's "Go To" shortcut). - case Key::G: { - if (k->is_command_or_control_pressed() && k->is_shift_pressed()) { - directory_edit->grab_focus(); - directory_edit->select_all(); - } else { - handled = false; - } - } break; -#endif - // Ctrl + L (matches most Windows/Linux file managers' "focus on path bar" shortcut, - // plus macOS Safari's "focus on address bar" shortcut). - case Key::L: { - if (k->is_command_or_control_pressed()) { - directory_edit->grab_focus(); - directory_edit->select_all(); - } else { - handled = false; - } - } break; - default: { - handled = false; - } - } - - if (handled) { - set_input_as_handled(); - } + for (const KeyValue> &action : action_shortcuts) { + if (action.value->matches_event(p_event)) { + _item_menu_id_pressed(action.key); + set_input_as_handled(); + break; } } } @@ -427,8 +375,6 @@ void FileDialog::_post_popup() { file_list->grab_focus(true); } - set_process_shortcut_input(true); - // For open dir mode, deselect all items on file dialog open. if (mode == FILE_MODE_OPEN_DIR) { deselect_all(); @@ -765,6 +711,23 @@ void FileDialog::_item_menu_id_pressed(int p_option) { } _push_history(); } break; + + case ITEM_MENU_GO_UP: { + _dir_submitted(".."); + } break; + + case ITEM_MENU_TOGGLE_HIDDEN: { + set_show_hidden_files(!show_hidden_files); + } break; + + case ITEM_MENU_FIND: { + show_filename_filter_button->set_pressed(!show_filename_filter_button->is_pressed()); + } break; + + case ITEM_MENU_FOCUS_PATH: { + directory_edit->grab_focus(); + directory_edit->select_all(); + } break; } } @@ -789,12 +752,14 @@ void FileDialog::_popup_menu(const Vector2 &p_pos, int p_for_item) { item_menu->add_item(ETR("Copy Path"), ITEM_MENU_COPY_PATH); if (customization_flags[CUSTOMIZATION_DELETE]) { item_menu->add_item(ETR("Delete"), ITEM_MENU_DELETE); + item_menu->set_item_shortcut(-1, action_shortcuts[ITEM_MENU_DELETE]); } } else { if (can_create_folders) { item_menu->add_item(ETR("New Folder..."), ITEM_MENU_NEW_FOLDER); } item_menu->add_item(ETR("Refresh"), ITEM_MENU_REFRESH); + item_menu->set_item_shortcut(-1, action_shortcuts[ITEM_MENU_REFRESH]); } #if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED) @@ -2259,12 +2224,20 @@ FileDialog::FileDialog() { set_hide_on_ok(false); 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; } + action_shortcuts[ITEM_MENU_DELETE] = Shortcut::make_from_action("ui_filedialog_delete"); + action_shortcuts[ITEM_MENU_GO_UP] = Shortcut::make_from_action("ui_filedialog_up_one_level"); + action_shortcuts[ITEM_MENU_REFRESH] = Shortcut::make_from_action("ui_filedialog_refresh"); + action_shortcuts[ITEM_MENU_TOGGLE_HIDDEN] = Shortcut::make_from_action("ui_filedialog_show_hidden"); + action_shortcuts[ITEM_MENU_FIND] = Shortcut::make_from_action("ui_filedialog_find"); + action_shortcuts[ITEM_MENU_FOCUS_PATH] = Shortcut::make_from_action("ui_filedialog_focus_path"); + show_hidden_files = default_show_hidden_files; display_mode = default_display_mode; dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); @@ -2290,6 +2263,7 @@ FileDialog::FileDialog() { dir_up = memnew(Button); dir_up->set_theme_type_variation(SceneStringName(FlatButton)); dir_up->set_tooltip_text(ETR("Go to parent folder.")); + dir_up->set_shortcut(action_shortcuts[ITEM_MENU_GO_UP]); top_toolbar->add_child(dir_up); dir_up->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::_go_up)); @@ -2319,6 +2293,7 @@ FileDialog::FileDialog() { refresh_button = memnew(Button); refresh_button->set_theme_type_variation(SceneStringName(FlatButton)); refresh_button->set_tooltip_text(ETR("Refresh files.")); + refresh_button->set_shortcut(action_shortcuts[ITEM_MENU_REFRESH]); top_toolbar->add_child(refresh_button); refresh_button->connect(SceneStringName(pressed), callable_mp(this, &FileDialog::update_file_list)); @@ -2414,6 +2389,7 @@ FileDialog::FileDialog() { show_hidden->set_toggle_mode(true); show_hidden->set_pressed(is_showing_hidden_files()); show_hidden->set_tooltip_text(ETR("Toggle the visibility of hidden files.")); + show_hidden->set_shortcut(action_shortcuts[ITEM_MENU_TOGGLE_HIDDEN]); lower_toolbar->add_child(show_hidden); show_hidden->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_hidden_files)); @@ -2449,8 +2425,8 @@ FileDialog::FileDialog() { show_filename_filter_button = memnew(Button); show_filename_filter_button->set_theme_type_variation(SceneStringName(FlatButton)); show_filename_filter_button->set_toggle_mode(true); - show_filename_filter_button->set_pressed(false); show_filename_filter_button->set_tooltip_text(ETR("Toggle the visibility of the filter for file names.")); + show_filename_filter_button->set_shortcut(action_shortcuts[ITEM_MENU_FIND]); lower_toolbar->add_child(show_filename_filter_button); show_filename_filter_button->connect(SceneStringName(toggled), callable_mp(this, &FileDialog::set_show_filename_filter)); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index dcf444189f8..b8832eb6aea 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -136,6 +136,11 @@ public: ITEM_MENU_NEW_FOLDER, ITEM_MENU_SHOW_IN_EXPLORER, ITEM_MENU_SHOW_BUNDLE_CONTENT, + // Not in the menu, only for shortcuts. + ITEM_MENU_GO_UP, + ITEM_MENU_TOGGLE_HIDDEN, + ITEM_MENU_FIND, + ITEM_MENU_FOCUS_PATH, }; enum Customization { @@ -170,6 +175,8 @@ private: bool can_create_folders = true; bool customization_flags[CUSTOMIZATION_MAX]; // Initialized to true in the constructor. + HashMap> action_shortcuts; + inline static LocalVector global_favorites; inline static LocalVector global_recents;