Skip to content

Commit

Permalink
Allow shortcuts to have any number of bindings. Updated UI as required.
Browse files Browse the repository at this point in the history
  • Loading branch information
EricEzaM committed Oct 1, 2021
1 parent 4baddc1 commit ad30b0a
Show file tree
Hide file tree
Showing 9 changed files with 477 additions and 272 deletions.
84 changes: 70 additions & 14 deletions core/input/shortcut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,26 @@
#include "shortcut.h"
#include "core/os/keyboard.h"

void Shortcut::set_event(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(Object::cast_to<InputEventShortcut>(*p_event), "Cannot set a shortcut event to an instance of InputEventShortcut.");
event = p_event;
void Shortcut::set_events(const Array &p_events) {
for (int i = 0; i < p_events.size(); i++) {
Ref<InputEventShortcut> ies = p_events[i];
ERR_FAIL_COND_MSG(ies.is_valid(), "Cannot set a shortcut event to an instance of InputEventShortcut.");
}

events = p_events;
emit_changed();
}

Ref<InputEvent> Shortcut::get_event() const {
return event;
void Shortcut::set_events_list(const List<Ref<InputEvent>> *p_events) {
events.clear();

for (const Ref<InputEvent> &ie : *p_events) {
events.push_back(ie);
}
}

Array Shortcut::get_events() const {
return events;
}

bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
Expand All @@ -48,29 +60,73 @@ bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
return true;
}
}
return event.is_valid() && event->is_match(p_event, true);

for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
bool valid = ie.is_valid() && ie->is_match(p_event);

// Stop on first valid event - don't need to check further.
if (valid) {
return true;
}
}

return false;
}

String Shortcut::get_as_text() const {
if (event.is_valid()) {
return event->as_text();
} else {
return "None";
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
// Return first shortcut which is valid
if (ie.is_valid()) {
return ie->as_text();
}
}

return "None";
}

bool Shortcut::has_valid_event() const {
return event.is_valid();
// Tests if there is ANY input event which is valid.
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ie = events[i];
if (ie.is_valid()) {
return true;
}
}

return false;
}

void Shortcut::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_event", "event"), &Shortcut::set_event);
ClassDB::bind_method(D_METHOD("get_event"), &Shortcut::get_event);
ClassDB::bind_method(D_METHOD("set_events", "events"), &Shortcut::set_events);
ClassDB::bind_method(D_METHOD("get_events"), &Shortcut::get_events);

ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event);

ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), "set_event", "get_event");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "events", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")), "set_events", "get_events");
}

bool Shortcut::is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2) {
if (p_event_array1.size() != p_event_array2.size()) {
return false;
}

bool is_same = true;
for (int i = 0; i < p_event_array1.size(); i++) {
Ref<InputEvent> ie_1 = p_event_array1[i];
Ref<InputEvent> ie_2 = p_event_array2[i];

is_same = ie_1->is_match(ie_2);

// Break on the first that doesn't match - don't need to check further.
if (!is_same) {
break;
}
}

return is_same;
}
12 changes: 8 additions & 4 deletions core/input/shortcut.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,22 @@
class Shortcut : public Resource {
GDCLASS(Shortcut, Resource);

Ref<InputEvent> event;
Array events;

protected:
static void _bind_methods();

public:
void set_event(const Ref<InputEvent> &p_shortcut);
Ref<InputEvent> get_event() const;
void set_events(const Array &p_events);
Array get_events() const;

void set_events_list(const List<Ref<InputEvent>> *p_events);

bool matches_event(const Ref<InputEvent> &p_event) const;
bool has_valid_event() const;

String get_as_text() const;
};

static bool is_event_array_equal(const Array &p_event_array1, const Array &p_event_array2);
};
#endif // SHORTCUT_H
6 changes: 3 additions & 3 deletions doc/classes/Control.xml
Original file line number Diff line number Diff line change
Expand Up @@ -742,10 +742,10 @@
</method>
<method name="set_drag_forwarding">
<return type="void" />
<argument index="0" name="target" type="Control" />
<argument index="0" name="target" type="Node" />
<description>
Forwards the handling of this control's drag and drop to [code]target[/code] control.
Forwarding can be implemented in the target control similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
Forwards the handling of this control's drag and drop to [code]target[/code] node.
Forwarding can be implemented in the target node similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
1. The function name must be suffixed with [b]_fw[/b]
2. The function must take an extra argument that is the control doing the forwarding
[codeblocks]
Expand Down
14 changes: 7 additions & 7 deletions doc/classes/Shortcut.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,36 @@
A shortcut for binding input.
</brief_description>
<description>
A shortcut for binding input.
Shortcuts are commonly used for interacting with a [Control] element from an [InputEvent] (also known as hotkeys).
One shortcut can contain multiple [InputEvent]'s, allowing the possibility of triggering one action with multiple different inputs.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_as_text" qualifiers="const">
<return type="String" />
<description>
Returns the shortcut's [InputEvent] as a [String].
Returns the shortcut's first valid [InputEvent] as a [String].
</description>
</method>
<method name="has_valid_event" qualifiers="const">
<return type="bool" />
<description>
Returns whether the shortcut has a valid [member event] assigned to it.
Returns whether [member events] contains an [InputEvent] which is valid.
</description>
</method>
<method name="matches_event" qualifiers="const">
<return type="bool" />
<argument index="0" name="event" type="InputEvent" />
<description>
Returns whether the shortcut's [member event] matches [code]event[/code].
Returns whether any [InputEvent] in [member events] equals [code]event[/code].
</description>
</method>
</methods>
<members>
<member name="event" type="InputEvent" setter="set_event" getter="get_event">
The shortcut's [InputEvent].
Generally the [InputEvent] is a keyboard key, though it can be any [InputEvent], including an [InputEventAction].
<member name="events" type="Array" setter="set_events" getter="get_events" default="[]">
The shortcut's [InputEvent] array.
Generally the [InputEvent] used is an [InputEventKey], though it can be any [InputEvent], including an [InputEventAction].
</member>
</members>
</class>
Loading

0 comments on commit ad30b0a

Please sign in to comment.