Skip to content

Commit 8806036

Browse files
Add ability to add new EditorSettings shortcuts
Co-Authored-By: Igor Kordiukiewicz <[email protected]>
1 parent 4d1f26e commit 8806036

File tree

3 files changed

+133
-19
lines changed

3 files changed

+133
-19
lines changed

doc/classes/EditorSettings.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,33 @@
6969
[/codeblocks]
7070
</description>
7171
</method>
72+
<method name="add_shortcut">
73+
<return type="void" />
74+
<param index="0" name="path" type="String" />
75+
<param index="1" name="shortcut" type="Shortcut" />
76+
<description>
77+
Adds a [param shortcut] whose path is specified by [param path].
78+
The [param path] determines how the shortcut is organized and displayed in the editor's shortcut settings. The path format affects the display as follows:
79+
- [code]"name"[/code] (no slash): Creates a category named [code]name[/code] with the shortcut displayed as [code]name[/code].
80+
- [code]"category/name"[/code] (single slash): Displays as [code]name[/code] in the [code]category[/code] section.
81+
- [code]"category/name/extra"[/code] (multiple slashes): Extra path components are ignored, so this behaves the same as [code]"category/name"[/code].
82+
[b]Note:[/b] Shortcuts are only saved to the editor settings if they differ from their original/default state. This means empty shortcuts that were originally empty will not persist between editor sessions and must be re-added. If a shortcut with the same [param path] already exists, this method will update it with the new [param shortcut] instead of creating a duplicate.
83+
[codeblock]
84+
# Add a custom shortcut for a plugin action.
85+
var my_shortcut = Shortcut.new()
86+
var input_event = InputEventKey.new()
87+
input_event.keycode = KEY_F5
88+
input_event.ctrl_pressed = true
89+
my_shortcut.events.append(input_event)
90+
91+
# This will appear under the "My Plugin" category as "Reload Data".
92+
EditorInterface.get_editor_settings().add_shortcut("my_plugin/reload_data", my_shortcut)
93+
94+
# This will appear under the "Test Action" category as "Test Action".
95+
EditorInterface.get_editor_settings().add_shortcut("test_action", my_shortcut)
96+
[/codeblock]
97+
</description>
98+
</method>
7299
<method name="check_changed_settings_in_group" qualifiers="const">
73100
<return type="bool" />
74101
<param index="0" name="setting_prefix" type="String" />
@@ -117,20 +144,55 @@
117144
Returns the value of the setting specified by [param name]. This is equivalent to using [method Object.get] on the EditorSettings instance.
118145
</description>
119146
</method>
147+
<method name="get_shortcut" qualifiers="const">
148+
<return type="Shortcut" />
149+
<param index="0" name="path" type="String" />
150+
<description>
151+
Returns the shortcut specified by [param path]. Tries to find a built-in action if no shortcut with the provided path is found in the shortcut list. If found, adds it to the list and returns it, otherwise returns [code]null[/code].
152+
</description>
153+
</method>
154+
<method name="get_shortcut_list">
155+
<return type="PackedStringArray" />
156+
<description>
157+
Returns the list of stored shortcut paths.
158+
</description>
159+
</method>
120160
<method name="has_setting" qualifiers="const">
121161
<return type="bool" />
122162
<param index="0" name="name" type="String" />
123163
<description>
124164
Returns [code]true[/code] if the setting specified by [param name] exists, [code]false[/code] otherwise.
125165
</description>
126166
</method>
167+
<method name="has_shortcut" qualifiers="const">
168+
<return type="bool" />
169+
<param index="0" name="path" type="String" />
170+
<description>
171+
Returns [code]true[/code] if the shortcut specified by [param path] exists, [code]false[/code] otherwise.
172+
</description>
173+
</method>
174+
<method name="is_shortcut" qualifiers="const">
175+
<return type="bool" />
176+
<param index="0" name="path" type="String" />
177+
<param index="1" name="event" type="InputEvent" />
178+
<description>
179+
Returns [code]true[/code] if the shortcut specified by [param path] matches the event specified by [param event], [code]false[/code] otherwise.
180+
</description>
181+
</method>
127182
<method name="mark_setting_changed">
128183
<return type="void" />
129184
<param index="0" name="setting" type="String" />
130185
<description>
131186
Marks the passed editor setting as being changed, see [method get_changed_settings]. Only settings which exist (see [method has_setting]) will be accepted.
132187
</description>
133188
</method>
189+
<method name="remove_shortcut">
190+
<return type="void" />
191+
<param index="0" name="path" type="String" />
192+
<description>
193+
Removes the shortcut specified by [param path].
194+
</description>
195+
</method>
134196
<method name="set_builtin_action_override">
135197
<return type="void" />
136198
<param index="0" name="name" type="String" />

editor/settings/editor_settings.cpp

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,24 +1937,54 @@ float EditorSettings::get_auto_display_scale() {
19371937

19381938
// Shortcuts
19391939

1940-
void EditorSettings::_add_shortcut_default(const String &p_name, const Ref<Shortcut> &p_shortcut) {
1941-
shortcuts[p_name] = p_shortcut;
1940+
void EditorSettings::_add_shortcut_default(const String &p_path, const Ref<Shortcut> &p_shortcut) {
1941+
shortcuts[p_path] = p_shortcut;
1942+
}
1943+
1944+
void EditorSettings::add_shortcut(const String &p_path, const Ref<Shortcut> &p_shortcut) {
1945+
Array use_events = p_shortcut->get_events();
1946+
if (shortcuts.has(p_path)) {
1947+
Ref<Shortcut> existing = shortcuts.get(p_path);
1948+
if (!existing->has_meta("original")) {
1949+
// Loaded from editor settings, but plugin not loaded yet.
1950+
// Keep the events from editor settings but still override the shortcut in the shortcuts map
1951+
use_events = existing->get_events();
1952+
} else if (!Shortcut::is_event_array_equal(existing->get_events(), existing->get_meta("original"))) {
1953+
// Shortcut exists and is customized - don't override with default.
1954+
return;
1955+
}
1956+
}
1957+
1958+
p_shortcut->set_meta("original", p_shortcut->get_events());
1959+
p_shortcut->set_events(use_events);
1960+
if (p_shortcut->get_name().is_empty()) {
1961+
String shortcut_name = p_path.get_slicec('/', 1);
1962+
if (shortcut_name.is_empty()) {
1963+
shortcut_name = p_path;
1964+
}
1965+
p_shortcut->set_name(shortcut_name);
1966+
}
1967+
shortcuts[p_path] = p_shortcut;
1968+
shortcuts[p_path]->set_meta("customized", true);
19421969
}
19431970

1944-
void EditorSettings::add_shortcut(const String &p_name, const Ref<Shortcut> &p_shortcut) {
1945-
shortcuts[p_name] = p_shortcut;
1946-
shortcuts[p_name]->set_meta("customized", true);
1971+
void EditorSettings::remove_shortcut(const String &p_path) {
1972+
shortcuts.erase(p_path);
19471973
}
19481974

1949-
bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const {
1950-
HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_name);
1951-
ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + ".");
1975+
bool EditorSettings::is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const {
1976+
HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_path);
1977+
ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_path + ".");
19521978

19531979
return E->value->matches_event(p_event);
19541980
}
19551981

1956-
Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const {
1957-
HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_name);
1982+
bool EditorSettings::has_shortcut(const String &p_path) const {
1983+
return get_shortcut(p_path).is_valid();
1984+
}
1985+
1986+
Ref<Shortcut> EditorSettings::get_shortcut(const String &p_path) const {
1987+
HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_path);
19581988
if (SC) {
19591989
return SC->value;
19601990
}
@@ -1963,32 +1993,42 @@ Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const {
19631993
// Use the first item in the action list for the shortcut event, since a shortcut can only have 1 linked event.
19641994

19651995
Ref<Shortcut> sc;
1966-
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_override = builtin_action_overrides.find(p_name);
1996+
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_override = builtin_action_overrides.find(p_path);
19671997
if (builtin_override) {
19681998
sc.instantiate();
19691999
sc->set_events_list(&builtin_override->value);
1970-
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
2000+
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));
19712001
}
19722002

19732003
// If there was no override, check the default builtins to see if it has an InputEvent for the provided name.
19742004
if (sc.is_null()) {
1975-
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);
2005+
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_path);
19762006
if (builtin_default) {
19772007
sc.instantiate();
19782008
sc->set_events_list(&builtin_default->value);
1979-
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
2009+
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));
19802010
}
19812011
}
19822012

19832013
if (sc.is_valid()) {
19842014
// Add the shortcut to the list.
1985-
shortcuts[p_name] = sc;
2015+
shortcuts[p_path] = sc;
19862016
return sc;
19872017
}
19882018

19892019
return Ref<Shortcut>();
19902020
}
19912021

2022+
Vector<String> EditorSettings::_get_shortcut_list() {
2023+
List<String> shortcut_list;
2024+
get_shortcut_list(&shortcut_list);
2025+
Vector<String> ret;
2026+
for (const String &shortcut : shortcut_list) {
2027+
ret.push_back(shortcut);
2028+
}
2029+
return ret;
2030+
}
2031+
19922032
void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {
19932033
for (const KeyValue<String, Ref<Shortcut>> &E : shortcuts) {
19942034
r_shortcuts->push_back(E.key);
@@ -2241,6 +2281,13 @@ void EditorSettings::_bind_methods() {
22412281

22422282
ClassDB::bind_method(D_METHOD("set_builtin_action_override", "name", "actions_list"), &EditorSettings::set_builtin_action_override);
22432283

2284+
ClassDB::bind_method(D_METHOD("add_shortcut", "path", "shortcut"), &EditorSettings::add_shortcut);
2285+
ClassDB::bind_method(D_METHOD("remove_shortcut", "path"), &EditorSettings::remove_shortcut);
2286+
ClassDB::bind_method(D_METHOD("is_shortcut", "path", "event"), &EditorSettings::is_shortcut);
2287+
ClassDB::bind_method(D_METHOD("has_shortcut", "path"), &EditorSettings::has_shortcut);
2288+
ClassDB::bind_method(D_METHOD("get_shortcut", "path"), &EditorSettings::get_shortcut);
2289+
ClassDB::bind_method(D_METHOD("get_shortcut_list"), &EditorSettings::_get_shortcut_list);
2290+
22442291
ClassDB::bind_method(D_METHOD("check_changed_settings_in_group", "setting_prefix"), &EditorSettings::check_changed_settings_in_group);
22452292
ClassDB::bind_method(D_METHOD("get_changed_settings"), &EditorSettings::get_changed_settings);
22462293
ClassDB::bind_method(D_METHOD("mark_setting_changed", "setting"), &EditorSettings::mark_setting_changed);

editor/settings/editor_settings.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class EditorSettings : public Resource {
128128
void _remove_deprecated_settings();
129129
#endif
130130

131+
// Bind helpers.
132+
Vector<String> _get_shortcut_list();
133+
131134
protected:
132135
static void _bind_methods();
133136

@@ -193,10 +196,12 @@ class EditorSettings : public Resource {
193196
String get_editor_layouts_config() const;
194197
static float get_auto_display_scale();
195198

196-
void _add_shortcut_default(const String &p_name, const Ref<Shortcut> &p_shortcut);
197-
void add_shortcut(const String &p_name, const Ref<Shortcut> &p_shortcut);
198-
bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const;
199-
Ref<Shortcut> get_shortcut(const String &p_name) const;
199+
void _add_shortcut_default(const String &p_path, const Ref<Shortcut> &p_shortcut);
200+
void add_shortcut(const String &p_path, const Ref<Shortcut> &p_shortcut);
201+
void remove_shortcut(const String &p_path);
202+
bool is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const;
203+
bool has_shortcut(const String &p_path) const;
204+
Ref<Shortcut> get_shortcut(const String &p_path) const;
200205
void get_shortcut_list(List<String> *r_shortcuts);
201206

202207
void set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events);

0 commit comments

Comments
 (0)