From cb6d7fd0596ff86f2361f7791493b6f1b30c6935 Mon Sep 17 00:00:00 2001 From: EricEzaM Date: Mon, 3 Oct 2022 00:50:05 +1000 Subject: [PATCH] Add searching by event for Editor Settings shortcuts and Project Settings input map. * Focus into the LineEdit, then perform input to search the list of events by the events assigned. * New specialised editor-only control for this: EventListenerLineEdit. Line edit is a good candidate for such a control because you can focus it, override it's input handling, and show the event all in one control. Update InputEventConfigurationDialog to use event listener line edit rather than the separate tabs. * Cleaner look - no need for tabs. * Simpler code. --- editor/action_map_editor.cpp | 289 ++++++++++++------- editor/action_map_editor.h | 61 +++- editor/editor_settings_dialog.cpp | 71 +++-- editor/editor_settings_dialog.h | 6 +- editor/plugins/input_event_editor_plugin.cpp | 8 +- scene/gui/line_edit.h | 3 +- 6 files changed, 283 insertions(+), 155 deletions(-) diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index b6348c5952c..4d48dd5ac57 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -35,6 +35,106 @@ #include "editor/editor_scale.h" #include "scene/gui/separator.h" +bool EventListenerLineEdit::_is_event_allowed(const Ref &p_event) const { + const Ref mb = p_event; + const Ref k = p_event; + const Ref jb = p_event; + const Ref jm = p_event; + + return (mb.is_valid() && (allowed_input_types & INPUT_MOUSE_BUTTON)) || + (k.is_valid() && (allowed_input_types & INPUT_KEY)) || + (jb.is_valid() && (allowed_input_types & INPUT_JOY_BUTTON)) || + (jm.is_valid() && (allowed_input_types & INPUT_JOY_MOTION)); +} + +void EventListenerLineEdit::gui_input(const Ref &p_event) { + const Ref mm = p_event; + if (mm.is_valid()) { + LineEdit::gui_input(p_event); + return; + } + + // Allow mouse button click on the clear button without being treated as an event. + const Ref b = p_event; + if (b.is_valid() && _is_over_clear_button(b->get_position())) { + LineEdit::gui_input(p_event); + return; + } + + // First event will be an event which is used to focus this control - i.e. a mouse click, or a tab press. + // Ignore the first one so that clicking into the LineEdit does not override the current event. + // Ignore is reset to true when the control is unfocused. + if (ignore) { + ignore = false; + return; + } + + accept_event(); + if (!p_event->is_pressed() || p_event->is_echo() || p_event->is_match(event) || !_is_event_allowed(p_event)) { + return; + } + + event = p_event; + set_text(event->as_text()); + emit_signal("event_changed", event); +} + +void EventListenerLineEdit::_on_text_changed(const String &p_text) { + if (p_text.is_empty()) { + clear_event(); + } +} + +void EventListenerLineEdit::_on_focus() { + set_placeholder(TTR("Listening for input...")); +} + +void EventListenerLineEdit::_on_unfocus() { + ignore = true; + set_placeholder(TTR("Filter by event...")); +} + +Ref EventListenerLineEdit::get_event() const { + return event; +} + +void EventListenerLineEdit::clear_event() { + if (event.is_valid()) { + event = Ref(); + set_text(""); + emit_signal("event_changed", event); + } +} + +void EventListenerLineEdit::set_allowed_input_types(int input_types) { + allowed_input_types = input_types; +} + +int EventListenerLineEdit::get_allowed_input_types() const { + return allowed_input_types; +} + +void EventListenerLineEdit::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + connect("text_changed", callable_mp(this, &EventListenerLineEdit::_on_text_changed)); + connect("focus_entered", callable_mp(this, &EventListenerLineEdit::_on_focus)); + connect("focus_exited", callable_mp(this, &EventListenerLineEdit::_on_unfocus)); + set_right_icon(get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons"))); + set_clear_button_enabled(true); + } break; + } +} + +void EventListenerLineEdit::_bind_methods() { + ADD_SIGNAL(MethodInfo("event_changed", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); +} + +EventListenerLineEdit::EventListenerLineEdit() { + set_caret_blink_enabled(false); + set_placeholder(TTR("Filter by event...")); +} + ///////////////////////////////////////// // Maps to 2*axis if value is neg, or 2*axis+1 if value is pos. @@ -98,6 +198,13 @@ void InputEventConfigurationDialog::_set_event(const Ref &p_event, b if (p_event.is_valid()) { event = p_event; + // If the event is changed to something which is not the same as the listener, + // clear out the event from the listener text box to avoid confusion. + const Ref listener_event = event_listener->get_event(); + if (listener_event.is_valid() && !listener_event->is_match(p_event)) { + event_listener->clear_event(); + } + // Update Label event_as_text->set_text(get_event_text(event, true)); @@ -175,31 +282,8 @@ void InputEventConfigurationDialog::_set_event(const Ref &p_event, b } else { // Event is not valid, reset dialog event = p_event; - Vector strings; - - // Reset message, promp for input according to which input types are allowed. - String text = TTR("Perform an Input (%s)."); - - if (allowed_input_types & INPUT_KEY) { - strings.append(TTR("Key")); - } - - if (allowed_input_types & INPUT_JOY_BUTTON) { - strings.append(TTR("Joypad Button")); - } - if (allowed_input_types & INPUT_JOY_MOTION) { - strings.append(TTR("Joypad Axis")); - } - if (allowed_input_types & INPUT_MOUSE_BUTTON) { - strings.append(TTR("Mouse Button in area below")); - } - if (strings.size() == 0) { - text = TTR("Input Event dialog has been misconfigured: No input types are allowed."); - event_as_text->set_text(text); - } else { - String insert_text = String(", ").join(strings); - event_as_text->set_text(vformat(text, insert_text)); - } + event_listener->clear_event(); + event_as_text->set_text(TTR("No Event Configured")); additional_options_container->hide(); input_list_tree->deselect_all(); @@ -207,54 +291,19 @@ void InputEventConfigurationDialog::_set_event(const Ref &p_event, b } } -void InputEventConfigurationDialog::_tab_selected(int p_tab) { - Callable signal_method = callable_mp(this, &InputEventConfigurationDialog::_listen_window_input); - if (p_tab == 0) { - // Start Listening. - if (!is_connected("window_input", signal_method)) { - connect("window_input", signal_method); - } - } else { - // Stop Listening. - if (is_connected("window_input", signal_method)) { - disconnect("window_input", signal_method); - } - input_list_tree->call_deferred(SNAME("ensure_cursor_is_visible")); - if (input_list_tree->get_selected() == nullptr) { - // If nothing selected, scroll to top. - input_list_tree->scroll_to_item(input_list_tree->get_root()); - } - } -} - -void InputEventConfigurationDialog::_listen_window_input(const Ref &p_event) { - // Ignore if echo or not pressed - if (p_event->is_echo() || !p_event->is_pressed()) { +void InputEventConfigurationDialog::_on_listen_input_changed(const Ref &p_event) { + // Ignore if invalid, echo or not pressed + if (p_event.is_null() || p_event->is_echo() || !p_event->is_pressed()) { return; } - // Ignore mouse motion - Ref mm = p_event; - if (mm.is_valid()) { - return; - } - - // Ignore mouse button if not in the detection rect - Ref mb = p_event; - if (mb.is_valid()) { - Rect2 r = mouse_detection_rect->get_rect(); - if (!r.has_point(mouse_detection_rect->get_local_mouse_position() + r.get_position())) { - return; - } - } - // Create an editable reference Ref received_event = p_event; - // Check what the type is and if it is allowed. Ref k = received_event; Ref joyb = received_event; Ref joym = received_event; + Ref mb = received_event; int type = 0; if (k.is_valid()) { @@ -301,7 +350,14 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref & received_event->set_device(_get_current_device()); _set_event(received_event); - set_input_as_handled(); +} + +void InputEventConfigurationDialog::_on_listen_focus_changed() { + if (event_listener->has_focus()) { + set_close_on_escape(false); + } else { + set_close_on_escape(true); + } } void InputEventConfigurationDialog::_search_term_updated(const String &) { @@ -478,10 +534,10 @@ void InputEventConfigurationDialog::_input_list_item_selected() { return; } - InputEventConfigurationDialog::InputType input_type = (InputEventConfigurationDialog::InputType)(int)selected->get_parent()->get_meta("__type"); + InputType input_type = (InputType)(int)selected->get_parent()->get_meta("__type"); switch (input_type) { - case InputEventConfigurationDialog::INPUT_KEY: { + case INPUT_KEY: { Key keycode = (Key)(int)selected->get_meta("__keycode"); Ref k; k.instantiate(); @@ -506,7 +562,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { _set_event(k, false); } break; - case InputEventConfigurationDialog::INPUT_MOUSE_BUTTON: { + case INPUT_MOUSE_BUTTON: { MouseButton idx = (MouseButton)(int)selected->get_meta("__index"); Ref mb; mb.instantiate(); @@ -526,7 +582,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { _set_event(mb, false); } break; - case InputEventConfigurationDialog::INPUT_JOY_BUTTON: { + case INPUT_JOY_BUTTON: { JoyButton idx = (JoyButton)(int)selected->get_meta("__index"); Ref jb = InputEventJoypadButton::create_reference(idx); @@ -535,7 +591,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { _set_event(jb, false); } break; - case InputEventConfigurationDialog::INPUT_JOY_MOTION: { + case INPUT_JOY_MOTION: { JoyAxis axis = (JoyAxis)(int)selected->get_meta("__axis"); int value = selected->get_meta("__value"); @@ -611,10 +667,6 @@ void InputEventConfigurationDialog::popup_and_configure(const Ref &p physical_key_checkbox->set_pressed(true); autoremap_command_or_control_checkbox->set_pressed(false); - _set_current_device(0); - - // Switch to "Listen" tab - tab_container->set_current_tab(0); // Select "All Devices" by default. device_id_option->select(0); @@ -632,7 +684,7 @@ void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) { } InputEventConfigurationDialog::InputEventConfigurationDialog() { - allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION | INPUT_MOUSE_BUTTON; + allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION; set_title(TTR("Event Configuration")); set_min_size(Size2i(550 * EDSCALE, 0)); // Min width @@ -640,31 +692,28 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { VBoxContainer *main_vbox = memnew(VBoxContainer); add_child(main_vbox); - tab_container = memnew(TabContainer); - tab_container->set_use_hidden_tabs_for_min_size(true); - tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tab_container->set_theme_type_variation("TabContainerOdd"); - tab_container->connect("tab_selected", callable_mp(this, &InputEventConfigurationDialog::_tab_selected)); - main_vbox->add_child(tab_container); - - // Listen to input tab - VBoxContainer *vb = memnew(VBoxContainer); - vb->set_name(TTR("Listen for Input")); event_as_text = memnew(Label); + event_as_text->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); event_as_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - vb->add_child(event_as_text); - // Mouse button detection rect (Mouse button event outside this rect will be ignored) - mouse_detection_rect = memnew(Panel); - mouse_detection_rect->set_v_size_flags(Control::SIZE_EXPAND_FILL); - vb->add_child(mouse_detection_rect); - tab_container->add_child(vb); + event_as_text->add_theme_font_override("font", get_theme_font(SNAME("bold"), SNAME("EditorFonts"))); + event_as_text->add_theme_font_size_override("font_size", 18 * EDSCALE); + main_vbox->add_child(event_as_text); + + event_listener = memnew(EventListenerLineEdit); + event_listener->set_h_size_flags(Control::SIZE_EXPAND_FILL); + event_listener->set_stretch_ratio(0.75); + event_listener->connect("event_changed", callable_mp(this, &InputEventConfigurationDialog::_on_listen_input_changed)); + event_listener->connect("focus_entered", callable_mp(this, &InputEventConfigurationDialog::_on_listen_focus_changed)); + event_listener->connect("focus_exited", callable_mp(this, &InputEventConfigurationDialog::_on_listen_focus_changed)); + main_vbox->add_child(event_listener); + + main_vbox->add_child(memnew(HSeparator)); // List of all input options to manually select from. - VBoxContainer *manual_vbox = memnew(VBoxContainer); manual_vbox->set_name(TTR("Manual Selection")); manual_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tab_container->add_child(manual_vbox); + main_vbox->add_child(manual_vbox); input_list_search = memnew(LineEdit); input_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -747,9 +796,6 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { additional_options_container->add_child(physical_key_checkbox); main_vbox->add_child(additional_options_container); - - // Default to first tab - tab_container->set_current_tab(0); } ///////////////////////////////////////// @@ -944,6 +990,12 @@ void ActionMapEditor::_search_term_updated(const String &) { update_action_list(); } +void ActionMapEditor::_search_by_event(const Ref &p_event) { + if (p_event.is_null() || (p_event->is_pressed() && !p_event->is_echo())) { + update_action_list(); + } +} + Variant ActionMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { TreeItem *selected = action_tree->get_selected(); if (!selected) { @@ -1084,6 +1136,22 @@ InputEventConfigurationDialog *ActionMapEditor::get_configuration_dialog() { return event_config_dialog; } +bool ActionMapEditor::_should_display_action(const String &p_name, const Array &p_events) const { + const Ref search_ev = action_list_search_by_event->get_event(); + bool event_match = true; + if (search_ev.is_valid()) { + event_match = false; + for (int i = 0; i < p_events.size(); ++i) { + const Ref ev = p_events[i]; + if (ev.is_valid() && ev->is_match(search_ev, true)) { + event_match = true; + } + } + } + + return event_match && action_list_search->get_text().is_subsequence_ofn(p_name); +} + void ActionMapEditor::update_action_list(const Vector &p_action_infos) { if (!p_action_infos.is_empty()) { actions_cache = p_action_infos; @@ -1101,8 +1169,8 @@ void ActionMapEditor::update_action_list(const Vector &p_action_info uneditable_count++; } - String search_term = action_list_search->get_text(); - if (!search_term.is_empty() && action_info.name.findn(search_term) == -1) { + const Array events = action_info.action["events"]; + if (!_should_display_action(action_info.name, events)) { continue; } @@ -1110,7 +1178,6 @@ void ActionMapEditor::update_action_list(const Vector &p_action_info continue; } - const Array events = action_info.action["events"]; const Variant deadzone = action_info.action["deadzone"]; // Update Tree... @@ -1206,16 +1273,22 @@ ActionMapEditor::ActionMapEditor() { action_list_search = memnew(LineEdit); action_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL); - action_list_search->set_placeholder(TTR("Filter Actions")); + action_list_search->set_placeholder(TTR("Filter by name...")); action_list_search->set_clear_button_enabled(true); action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated)); top_hbox->add_child(action_list_search); - show_builtin_actions_checkbutton = memnew(CheckButton); - show_builtin_actions_checkbutton->set_pressed(false); - show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions")); - show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions)); - top_hbox->add_child(show_builtin_actions_checkbutton); + action_list_search_by_event = memnew(EventListenerLineEdit); + action_list_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL); + action_list_search_by_event->set_stretch_ratio(0.75); + action_list_search_by_event->connect("event_changed", callable_mp(this, &ActionMapEditor::_search_by_event)); + top_hbox->add_child(action_list_search_by_event); + + Button *clear_all_search = memnew(Button); + clear_all_search->set_text(TTR("Clear All")); + clear_all_search->connect("pressed", callable_mp(action_list_search_by_event, &EventListenerLineEdit::clear_event)); + clear_all_search->connect("pressed", callable_mp(action_list_search, &LineEdit::clear)); + top_hbox->add_child(clear_all_search); // Adding Action line edit + button add_hbox = memnew(HBoxContainer); @@ -1236,6 +1309,12 @@ ActionMapEditor::ActionMapEditor() { // Disable the button and set its tooltip. _add_edit_text_changed(add_edit->get_text()); + show_builtin_actions_checkbutton = memnew(CheckButton); + show_builtin_actions_checkbutton->set_pressed(false); + show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions")); + show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions)); + add_hbox->add_child(show_builtin_actions_checkbutton); + main_vbox->add_child(add_hbox); // Action Editor Tree diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h index 36d21fe2584..f576a2b5652 100644 --- a/editor/action_map_editor.h +++ b/editor/action_map_editor.h @@ -40,19 +40,48 @@ #include "scene/gui/tab_container.h" #include "scene/gui/tree.h" +enum InputType { + INPUT_KEY = 1, + INPUT_MOUSE_BUTTON = 2, + INPUT_JOY_BUTTON = 4, + INPUT_JOY_MOTION = 8 +}; + +class EventListenerLineEdit : public LineEdit { + GDCLASS(EventListenerLineEdit, LineEdit) + + int allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION; + bool ignore = true; + bool share_keycodes = false; + Ref event; + + bool _is_event_allowed(const Ref &p_event) const; + + void gui_input(const Ref &p_event) override; + void _on_text_changed(const String &p_text); + + void _on_focus(); + void _on_unfocus(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + Ref get_event() const; + void clear_event(); + + void set_allowed_input_types(int input_types); + int get_allowed_input_types() const; + +public: + EventListenerLineEdit(); +}; + // Confirmation Dialog used when configuring an input event. // Separate from ActionMapEditor for code cleanliness and separation of responsibilities. class InputEventConfigurationDialog : public ConfirmationDialog { - GDCLASS(InputEventConfigurationDialog, ConfirmationDialog); - -public: - enum InputType { - INPUT_KEY = 1, - INPUT_MOUSE_BUTTON = 2, - INPUT_JOY_BUTTON = 4, - INPUT_JOY_MOTION = 8 - }; - + GDCLASS(InputEventConfigurationDialog, ConfirmationDialog) private: struct IconCache { Ref keyboard; @@ -63,11 +92,9 @@ private: Ref event = Ref(); - TabContainer *tab_container = nullptr; - // Listening for input + EventListenerLineEdit *event_listener = nullptr; Label *event_as_text = nullptr; - Panel *mouse_detection_rect = nullptr; // List of All Key/Mouse/Joypad input options. int allowed_input_types; @@ -104,9 +131,8 @@ private: CheckBox *physical_key_checkbox = nullptr; void _set_event(const Ref &p_event, bool p_update_input_list_selection = true); - - void _tab_selected(int p_tab); - void _listen_window_input(const Ref &p_event); + void _on_listen_input_changed(const Ref &p_event); + void _on_listen_focus_changed(); void _search_term_updated(const String &p_term); void _update_input_list(); @@ -174,6 +200,7 @@ private: bool show_builtin_actions = false; CheckButton *show_builtin_actions_checkbutton = nullptr; LineEdit *action_list_search = nullptr; + EventListenerLineEdit *action_list_search_by_event = nullptr; HBoxContainer *add_hbox = nullptr; LineEdit *add_edit = nullptr; @@ -191,6 +218,8 @@ private: void _tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button); void _tree_item_activated(); void _search_term_updated(const String &p_search_term); + void _search_by_event(const Ref &p_event); + bool _should_display_action(const String &p_name, const Array &p_events) const; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 2c09543d928..b5147bb4ebd 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -106,11 +106,16 @@ void EditorSettingsDialog::popup_edit_settings() { _focus_current_search_box(); } -void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) { - shortcut_filter = p_filter; +void EditorSettingsDialog::_filter_shortcuts(const String &) { _update_shortcuts(); } +void EditorSettingsDialog::_filter_shortcuts_by_event(const Ref &p_event) { + if (p_event.is_null() || (p_event->is_pressed() && !p_event->is_echo())) { + _update_shortcuts(); + } +} + void EditorSettingsDialog::_undo_redo_callback(void *p_self, const String &p_name) { EditorNode::get_log()->add_message(p_name, EditorLog::MSG_TYPE_EDITOR); } @@ -326,6 +331,22 @@ void EditorSettingsDialog::_create_shortcut_treeitem(TreeItem *p_parent, const S } } +bool EditorSettingsDialog::_should_display_shortcut(const String &p_name, const Array &p_events) const { + const Ref search_ev = shortcut_search_by_event->get_event(); + bool event_match = true; + if (search_ev.is_valid()) { + event_match = false; + for (int i = 0; i < p_events.size(); ++i) { + const Ref ev = p_events[i]; + if (ev.is_valid() && ev->is_match(search_ev, true)) { + event_match = true; + } + } + } + + return event_match && shortcut_search_box->get_text().is_subsequence_ofn(p_name); +} + void EditorSettingsDialog::_update_shortcuts() { // Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated. HashMap collapsed; @@ -379,32 +400,17 @@ void EditorSettingsDialog::_update_shortcuts() { const String &action_name = E.key; const InputMap::Action &action = E.value; - Array events; // Need to get the list of events into an array so it can be set as metadata on the item. - Vector event_strings; - // Skip non-builtin actions. if (!InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().has(action_name)) { continue; } const List> &all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name)->value; - List> key_default_events; - // Remove all non-key events from the defaults. Only check keys, since we are in the editor. - for (const List>::Element *I = all_default_events.front(); I; I = I->next()) { - Ref k = I->get(); - if (k.is_valid()) { - key_default_events.push_back(k); - } - } - - // Join the text of the events with a delimiter so they can all be displayed in one cell. - String events_display_string = event_strings.is_empty() ? "None" : String("; ").join(event_strings); - - if (!shortcut_filter.is_subsequence_ofn(action_name) && (events_display_string == "None" || !shortcut_filter.is_subsequence_ofn(events_display_string))) { + Array action_events = _event_list_to_array_helper(action.inputs); + if (!_should_display_shortcut(action_name, action_events)) { continue; } - Array action_events = _event_list_to_array_helper(action.inputs); Array default_events = _event_list_to_array_helper(all_default_events); bool same_as_defaults = Shortcut::is_event_array_equal(default_events, action_events); bool collapse = !collapsed.has(action_name) || (collapsed.has(action_name) && collapsed[action_name]); @@ -459,8 +465,7 @@ void EditorSettingsDialog::_update_shortcuts() { String section_name = E.get_slice("/", 0); TreeItem *section = sections[section_name]; - // Shortcut Item - if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) { + if (!_should_display_shortcut(sc->get_name(), sc->get_events())) { continue; } @@ -749,12 +754,29 @@ EditorSettingsDialog::EditorSettingsDialog() { tabs->add_child(tab_shortcuts); tab_shortcuts->set_name(TTR("Shortcuts")); + HBoxContainer *top_hbox = memnew(HBoxContainer); + top_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tab_shortcuts->add_child(top_hbox); + shortcut_search_box = memnew(LineEdit); - shortcut_search_box->set_placeholder(TTR("Filter Shortcuts")); + shortcut_search_box->set_placeholder(TTR("Filter by name...")); shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - tab_shortcuts->add_child(shortcut_search_box); + top_hbox->add_child(shortcut_search_box); shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts)); + shortcut_search_by_event = memnew(EventListenerLineEdit); + shortcut_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL); + shortcut_search_by_event->set_stretch_ratio(0.75); + shortcut_search_by_event->set_allowed_input_types(INPUT_KEY); + shortcut_search_by_event->connect("event_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts_by_event)); + top_hbox->add_child(shortcut_search_by_event); + + Button *clear_all_search = memnew(Button); + clear_all_search->set_text(TTR("Clear All")); + clear_all_search->connect("pressed", callable_mp(shortcut_search_box, &LineEdit::clear)); + clear_all_search->connect("pressed", callable_mp(shortcut_search_by_event, &EventListenerLineEdit::clear_event)); + top_hbox->add_child(clear_all_search); + shortcuts = memnew(Tree); shortcuts->set_v_size_flags(Control::SIZE_EXPAND_FILL); shortcuts->set_columns(2); @@ -771,8 +793,7 @@ EditorSettingsDialog::EditorSettingsDialog() { // Adding event dialog shortcut_editor = memnew(InputEventConfigurationDialog); shortcut_editor->connect("confirmed", callable_mp(this, &EditorSettingsDialog::_event_config_confirmed)); - shortcut_editor->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY); - shortcut_editor->set_close_on_escape(false); + shortcut_editor->set_allowed_input_types(INPUT_KEY); add_child(shortcut_editor); set_hide_on_ok(true); diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h index 87ed6a77eb6..05424a64ed9 100644 --- a/editor/editor_settings_dialog.h +++ b/editor/editor_settings_dialog.h @@ -53,6 +53,7 @@ class EditorSettingsDialog : public AcceptDialog { LineEdit *search_box = nullptr; LineEdit *shortcut_search_box = nullptr; + EventListenerLineEdit *shortcut_search_by_event = nullptr; SectionedInspector *inspector = nullptr; // Shortcuts @@ -64,7 +65,6 @@ class EditorSettingsDialog : public AcceptDialog { }; Tree *shortcuts = nullptr; - String shortcut_filter; InputEventConfigurationDialog *shortcut_editor = nullptr; @@ -103,13 +103,13 @@ class EditorSettingsDialog : public AcceptDialog { void _focus_current_search_box(); void _filter_shortcuts(const String &p_filter); + void _filter_shortcuts_by_event(const Ref &p_event); + bool _should_display_shortcut(const String &p_name, const Array &p_events) const; void _update_shortcuts(); void _shortcut_button_pressed(Object *p_item, int p_column, int p_idx, MouseButton p_button = MouseButton::LEFT); void _shortcut_cell_double_clicked(); - void _builtin_action_popup_index_pressed(int p_index); - static void _undo_redo_callback(void *p_self, const String &p_name); Label *restart_label = nullptr; diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp index 153eab32d23..e28c1a47775 100644 --- a/editor/plugins/input_event_editor_plugin.cpp +++ b/editor/plugins/input_event_editor_plugin.cpp @@ -63,13 +63,13 @@ void InputEventConfigContainer::set_event(const Ref &p_event) { Ref jm = p_event; if (k.is_valid()) { - config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY); + config_dialog->set_allowed_input_types(INPUT_KEY); } else if (m.is_valid()) { - config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_MOUSE_BUTTON); + config_dialog->set_allowed_input_types(INPUT_MOUSE_BUTTON); } else if (jb.is_valid()) { - config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_BUTTON); + config_dialog->set_allowed_input_types(INPUT_JOY_BUTTON); } else if (jm.is_valid()) { - config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_MOTION); + config_dialog->set_allowed_input_types(INPUT_JOY_MOTION); } input_event = p_event; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index a4d5205f816..861c7f273b7 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -199,8 +199,6 @@ private: float base_scale = 1.0; } theme_cache; - bool _is_over_clear_button(const Point2 &p_pos) const; - void _clear_undo_stack(); void _clear_redo(); void _create_undo_state(); @@ -240,6 +238,7 @@ private: void _ensure_menu(); protected: + bool _is_over_clear_button(const Point2 &p_pos) const; virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods();