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