Merge pull request #111460 from KoBeWi/dialoging_shortcut_files

Rework FileDialog shortcuts
This commit is contained in:
Thaddeus Crews
2025-10-13 12:29:57 -05:00
6 changed files with 97 additions and 63 deletions

View File

@@ -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<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_graph_follow_right.macos", inputs);
// ///// UI File Dialog Shortcuts /////
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::KEY_DELETE));
default_builtin_cache.insert("ui_filedialog_delete", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::BACKSPACE));
default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
@@ -816,6 +823,22 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::H));
default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::F | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_filedialog_find", inputs);
inputs = List<Ref<InputEvent>>();
// 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<Ref<InputEvent>>();
// 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<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::QUOTELEFT | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_swap_input_direction", inputs);

View File

@@ -85,6 +85,17 @@ String Shortcut::get_as_text() const {
return "None";
}
Ref<Shortcut> Shortcut::make_from_action(const StringName &p_action) {
Ref<InputEventAction> event;
event.instantiate();
event->set_action(p_action);
Ref<Shortcut> 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++) {

View File

@@ -52,5 +52,7 @@ public:
String get_as_text() const;
static Ref<Shortcut> make_from_action(const StringName &p_action);
static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2);
};

View File

@@ -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.
</member>
<member name="input/ui_filedialog_delete" type="Dictionary" setter="" getter="">
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.
</member>
<member name="input/ui_filedialog_find" type="Dictionary" setter="" getter="">
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.
</member>
<member name="input/ui_filedialog_focus_path" type="Dictionary" setter="" getter="">
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.
</member>
<member name="input/ui_filedialog_focus_path.macos" type="Dictionary" setter="" getter="">
macOS specific override for the shortcut to focus path edit field in [FileDialog].
</member>
<member name="input/ui_filedialog_refresh" type="Dictionary" setter="" getter="">
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.

View File

@@ -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<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (p_event.is_null() || p_event->is_released() || p_event->is_echo()) {
return;
}
Ref<InputEventKey> 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<ItemMenu, Ref<Shortcut>> &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));

View File

@@ -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<ItemMenu, Ref<Shortcut>> action_shortcuts;
inline static LocalVector<String> global_favorites;
inline static LocalVector<String> global_recents;