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.
This commit is contained in:
EricEzaM 2022-10-03 00:50:05 +10:00
parent e69b7083d4
commit cb6d7fd059
6 changed files with 283 additions and 155 deletions

View file

@ -35,6 +35,106 @@
#include "editor/editor_scale.h"
#include "scene/gui/separator.h"
bool EventListenerLineEdit::_is_event_allowed(const Ref<InputEvent> &p_event) const {
const Ref<InputEventMouseButton> mb = p_event;
const Ref<InputEventKey> k = p_event;
const Ref<InputEventJoypadButton> jb = p_event;
const Ref<InputEventJoypadMotion> 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<InputEvent> &p_event) {
const Ref<InputEventMouseMotion> 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<InputEventMouseButton> 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<InputEvent> EventListenerLineEdit::get_event() const {
return event;
}
void EventListenerLineEdit::clear_event() {
if (event.is_valid()) {
event = Ref<InputEvent>();
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<InputEvent> &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<InputEvent> 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<InputEvent> &p_event, b
} else {
// Event is not valid, reset dialog
event = p_event;
Vector<String> 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<InputEvent> &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<InputEvent> &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<InputEvent> &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<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
return;
}
// Ignore mouse button if not in the detection rect
Ref<InputEventMouseButton> 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<InputEvent> received_event = p_event;
// Check what the type is and if it is allowed.
Ref<InputEventKey> k = received_event;
Ref<InputEventJoypadButton> joyb = received_event;
Ref<InputEventJoypadMotion> joym = received_event;
Ref<InputEventMouseButton> mb = received_event;
int type = 0;
if (k.is_valid()) {
@ -301,7 +350,14 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &
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<InputEventKey> 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<InputEventMouseButton> 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<InputEventJoypadButton> 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<InputEvent> &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<InputEvent> &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<InputEvent> 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<InputEvent> 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<ActionInfo> &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<ActionInfo> &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<ActionInfo> &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

View file

@ -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<InputEvent> event;
bool _is_event_allowed(const Ref<InputEvent> &p_event) const;
void gui_input(const Ref<InputEvent> &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<InputEvent> 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<Texture2D> keyboard;
@ -63,11 +92,9 @@ private:
Ref<InputEvent> event = Ref<InputEvent>();
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<InputEvent> &p_event, bool p_update_input_list_selection = true);
void _tab_selected(int p_tab);
void _listen_window_input(const Ref<InputEvent> &p_event);
void _on_listen_input_changed(const Ref<InputEvent> &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<InputEvent> &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;

View file

@ -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<InputEvent> &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<InputEvent> 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<InputEvent> 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<String, bool> 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<String> event_strings;
// Skip non-builtin actions.
if (!InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().has(action_name)) {
continue;
}
const List<Ref<InputEvent>> &all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name)->value;
List<Ref<InputEventKey>> key_default_events;
// Remove all non-key events from the defaults. Only check keys, since we are in the editor.
for (const List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
Ref<InputEventKey> 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);

View file

@ -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<InputEvent> &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;

View file

@ -63,13 +63,13 @@ void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) {
Ref<InputEventJoypadMotion> 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;

View file

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