Skip to content

Commit d602742

Browse files
committed
Merge pull request #102889 from ryevdokimov/add-editorsettings-shortcuts
Add ability to add new EditorSettings shortcuts
2 parents 1932a5c + 8806036 commit d602742

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
@@ -70,6 +70,33 @@
7070
[/codeblocks]
7171
</description>
7272
</method>
73+
<method name="add_shortcut">
74+
<return type="void" />
75+
<param index="0" name="path" type="String" />
76+
<param index="1" name="shortcut" type="Shortcut" />
77+
<description>
78+
Adds a [param shortcut] whose path is specified by [param path].
79+
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:
80+
- [code]"name"[/code] (no slash): Creates a category named [code]name[/code] with the shortcut displayed as [code]name[/code].
81+
- [code]"category/name"[/code] (single slash): Displays as [code]name[/code] in the [code]category[/code] section.
82+
- [code]"category/name/extra"[/code] (multiple slashes): Extra path components are ignored, so this behaves the same as [code]"category/name"[/code].
83+
[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.
84+
[codeblock]
85+
# Add a custom shortcut for a plugin action.
86+
var my_shortcut = Shortcut.new()
87+
var input_event = InputEventKey.new()
88+
input_event.keycode = KEY_F5
89+
input_event.ctrl_pressed = true
90+
my_shortcut.events.append(input_event)
91+
92+
# This will appear under the "My Plugin" category as "Reload Data".
93+
EditorInterface.get_editor_settings().add_shortcut("my_plugin/reload_data", my_shortcut)
94+
95+
# This will appear under the "Test Action" category as "Test Action".
96+
EditorInterface.get_editor_settings().add_shortcut("test_action", my_shortcut)
97+
[/codeblock]
98+
</description>
99+
</method>
73100
<method name="check_changed_settings_in_group" qualifiers="const">
74101
<return type="bool" />
75102
<param index="0" name="setting_prefix" type="String" />
@@ -118,20 +145,55 @@
118145
Returns the value of the setting specified by [param name]. This is equivalent to using [method Object.get] on the EditorSettings instance.
119146
</description>
120147
</method>
148+
<method name="get_shortcut" qualifiers="const">
149+
<return type="Shortcut" />
150+
<param index="0" name="path" type="String" />
151+
<description>
152+
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].
153+
</description>
154+
</method>
155+
<method name="get_shortcut_list">
156+
<return type="PackedStringArray" />
157+
<description>
158+
Returns the list of stored shortcut paths.
159+
</description>
160+
</method>
121161
<method name="has_setting" qualifiers="const">
122162
<return type="bool" />
123163
<param index="0" name="name" type="String" />
124164
<description>
125165
Returns [code]true[/code] if the setting specified by [param name] exists, [code]false[/code] otherwise.
126166
</description>
127167
</method>
168+
<method name="has_shortcut" qualifiers="const">
169+
<return type="bool" />
170+
<param index="0" name="path" type="String" />
171+
<description>
172+
Returns [code]true[/code] if the shortcut specified by [param path] exists, [code]false[/code] otherwise.
173+
</description>
174+
</method>
175+
<method name="is_shortcut" qualifiers="const">
176+
<return type="bool" />
177+
<param index="0" name="path" type="String" />
178+
<param index="1" name="event" type="InputEvent" />
179+
<description>
180+
Returns [code]true[/code] if the shortcut specified by [param path] matches the event specified by [param event], [code]false[/code] otherwise.
181+
</description>
182+
</method>
128183
<method name="mark_setting_changed">
129184
<return type="void" />
130185
<param index="0" name="setting" type="String" />
131186
<description>
132187
Marks the passed editor setting as being changed, see [method get_changed_settings]. Only settings which exist (see [method has_setting]) will be accepted.
133188
</description>
134189
</method>
190+
<method name="remove_shortcut">
191+
<return type="void" />
192+
<param index="0" name="path" type="String" />
193+
<description>
194+
Removes the shortcut specified by [param path].
195+
</description>
196+
</method>
135197
<method name="set_builtin_action_override">
136198
<return type="void" />
137199
<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
@@ -1898,24 +1898,54 @@ String EditorSettings::get_language() const {
18981898

18991899
// Shortcuts
19001900

1901-
void EditorSettings::_add_shortcut_default(const String &p_name, const Ref<Shortcut> &p_shortcut) {
1902-
shortcuts[p_name] = p_shortcut;
1901+
void EditorSettings::_add_shortcut_default(const String &p_path, const Ref<Shortcut> &p_shortcut) {
1902+
shortcuts[p_path] = p_shortcut;
1903+
}
1904+
1905+
void EditorSettings::add_shortcut(const String &p_path, const Ref<Shortcut> &p_shortcut) {
1906+
Array use_events = p_shortcut->get_events();
1907+
if (shortcuts.has(p_path)) {
1908+
Ref<Shortcut> existing = shortcuts.get(p_path);
1909+
if (!existing->has_meta("original")) {
1910+
// Loaded from editor settings, but plugin not loaded yet.
1911+
// Keep the events from editor settings but still override the shortcut in the shortcuts map
1912+
use_events = existing->get_events();
1913+
} else if (!Shortcut::is_event_array_equal(existing->get_events(), existing->get_meta("original"))) {
1914+
// Shortcut exists and is customized - don't override with default.
1915+
return;
1916+
}
1917+
}
1918+
1919+
p_shortcut->set_meta("original", p_shortcut->get_events());
1920+
p_shortcut->set_events(use_events);
1921+
if (p_shortcut->get_name().is_empty()) {
1922+
String shortcut_name = p_path.get_slicec('/', 1);
1923+
if (shortcut_name.is_empty()) {
1924+
shortcut_name = p_path;
1925+
}
1926+
p_shortcut->set_name(shortcut_name);
1927+
}
1928+
shortcuts[p_path] = p_shortcut;
1929+
shortcuts[p_path]->set_meta("customized", true);
19031930
}
19041931

1905-
void EditorSettings::add_shortcut(const String &p_name, const Ref<Shortcut> &p_shortcut) {
1906-
shortcuts[p_name] = p_shortcut;
1907-
shortcuts[p_name]->set_meta("customized", true);
1932+
void EditorSettings::remove_shortcut(const String &p_path) {
1933+
shortcuts.erase(p_path);
19081934
}
19091935

1910-
bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const {
1911-
HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_name);
1912-
ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + ".");
1936+
bool EditorSettings::is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const {
1937+
HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_path);
1938+
ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_path + ".");
19131939

19141940
return E->value->matches_event(p_event);
19151941
}
19161942

1917-
Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const {
1918-
HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_name);
1943+
bool EditorSettings::has_shortcut(const String &p_path) const {
1944+
return get_shortcut(p_path).is_valid();
1945+
}
1946+
1947+
Ref<Shortcut> EditorSettings::get_shortcut(const String &p_path) const {
1948+
HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_path);
19191949
if (SC) {
19201950
return SC->value;
19211951
}
@@ -1924,32 +1954,42 @@ Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const {
19241954
// Use the first item in the action list for the shortcut event, since a shortcut can only have 1 linked event.
19251955

19261956
Ref<Shortcut> sc;
1927-
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_override = builtin_action_overrides.find(p_name);
1957+
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_override = builtin_action_overrides.find(p_path);
19281958
if (builtin_override) {
19291959
sc.instantiate();
19301960
sc->set_events_list(&builtin_override->value);
1931-
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
1961+
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));
19321962
}
19331963

19341964
// If there was no override, check the default builtins to see if it has an InputEvent for the provided name.
19351965
if (sc.is_null()) {
1936-
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);
1966+
HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_path);
19371967
if (builtin_default) {
19381968
sc.instantiate();
19391969
sc->set_events_list(&builtin_default->value);
1940-
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name));
1970+
sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));
19411971
}
19421972
}
19431973

19441974
if (sc.is_valid()) {
19451975
// Add the shortcut to the list.
1946-
shortcuts[p_name] = sc;
1976+
shortcuts[p_path] = sc;
19471977
return sc;
19481978
}
19491979

19501980
return Ref<Shortcut>();
19511981
}
19521982

1983+
Vector<String> EditorSettings::_get_shortcut_list() {
1984+
List<String> shortcut_list;
1985+
get_shortcut_list(&shortcut_list);
1986+
Vector<String> ret;
1987+
for (const String &shortcut : shortcut_list) {
1988+
ret.push_back(shortcut);
1989+
}
1990+
return ret;
1991+
}
1992+
19531993
void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {
19541994
for (const KeyValue<String, Ref<Shortcut>> &E : shortcuts) {
19551995
r_shortcuts->push_back(E.key);
@@ -2202,6 +2242,13 @@ void EditorSettings::_bind_methods() {
22022242

22032243
ClassDB::bind_method(D_METHOD("set_builtin_action_override", "name", "actions_list"), &EditorSettings::set_builtin_action_override);
22042244

2245+
ClassDB::bind_method(D_METHOD("add_shortcut", "path", "shortcut"), &EditorSettings::add_shortcut);
2246+
ClassDB::bind_method(D_METHOD("remove_shortcut", "path"), &EditorSettings::remove_shortcut);
2247+
ClassDB::bind_method(D_METHOD("is_shortcut", "path", "event"), &EditorSettings::is_shortcut);
2248+
ClassDB::bind_method(D_METHOD("has_shortcut", "path"), &EditorSettings::has_shortcut);
2249+
ClassDB::bind_method(D_METHOD("get_shortcut", "path"), &EditorSettings::get_shortcut);
2250+
ClassDB::bind_method(D_METHOD("get_shortcut_list"), &EditorSettings::_get_shortcut_list);
2251+
22052252
ClassDB::bind_method(D_METHOD("check_changed_settings_in_group", "setting_prefix"), &EditorSettings::check_changed_settings_in_group);
22062253
ClassDB::bind_method(D_METHOD("get_changed_settings"), &EditorSettings::get_changed_settings);
22072254
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
@@ -127,6 +127,9 @@ class EditorSettings : public Resource {
127127
void _remove_deprecated_settings();
128128
#endif
129129

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

@@ -191,10 +194,12 @@ class EditorSettings : public Resource {
191194
static float get_auto_display_scale();
192195
String get_language() const;
193196

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

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

0 commit comments

Comments
 (0)