Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/openxr/editor/openxr_action_map_editor.cpp
21085 views
1
/**************************************************************************/
2
/* openxr_action_map_editor.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "openxr_action_map_editor.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/io/dir_access.h"
35
#include "core/io/resource_loader.h"
36
#include "core/io/resource_saver.h"
37
#include "editor/editor_node.h"
38
#include "editor/gui/editor_file_dialog.h"
39
#include "editor/settings/editor_command_palette.h"
40
#include "editor/settings/editor_settings.h"
41
#include "editor/themes/editor_scale.h"
42
43
HashMap<String, String> OpenXRActionMapEditor::interaction_profile_editors;
44
HashMap<String, String> OpenXRActionMapEditor::binding_modifier_editors;
45
46
void OpenXRActionMapEditor::_bind_methods() {
47
ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
48
ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
49
50
ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
51
ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
52
53
ClassDB::bind_method(D_METHOD("_do_add_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_add_action_set_editor);
54
ClassDB::bind_method(D_METHOD("_do_remove_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_remove_action_set_editor);
55
ClassDB::bind_method(D_METHOD("_do_add_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_add_interaction_profile_editor);
56
ClassDB::bind_method(D_METHOD("_do_remove_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_remove_interaction_profile_editor);
57
58
ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_interaction_profile_editor", "interaction_profile_path", "editor_class"), &OpenXRActionMapEditor::register_interaction_profile_editor);
59
ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_binding_modifier_editor", "binding_modifier_class", "editor_class"), &OpenXRActionMapEditor::register_binding_modifier_editor);
60
}
61
62
void OpenXRActionMapEditor::_notification(int p_what) {
63
switch (p_what) {
64
case NOTIFICATION_THEME_CHANGED: {
65
const String theme_style = EDITOR_GET("interface/theme/style");
66
tabs->set_theme_type_variation(theme_style == "Classic" ? "TabContainerOdd" : "TabContainerInner");
67
68
for (int i = 0; i < tabs->get_child_count(); i++) {
69
Control *tab = Object::cast_to<Control>(tabs->get_child(i));
70
if (tab) {
71
tab->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
72
}
73
}
74
} break;
75
76
case NOTIFICATION_READY: {
77
_create_action_sets();
78
_create_interaction_profiles();
79
} break;
80
}
81
}
82
83
OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(const Ref<OpenXRActionSet> &p_action_set) {
84
ERR_FAIL_COND_V(p_action_set.is_null(), nullptr);
85
86
OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set));
87
action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set));
88
action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed));
89
90
actionsets_vb->add_child(action_set_editor);
91
92
return action_set_editor;
93
}
94
95
void OpenXRActionMapEditor::_create_action_sets() {
96
if (action_map.is_valid()) {
97
Array action_sets = action_map->get_action_sets();
98
for (int i = 0; i < action_sets.size(); i++) {
99
Ref<OpenXRActionSet> action_set = action_sets[i];
100
_add_action_set_editor(action_set);
101
}
102
}
103
}
104
105
OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(const Ref<OpenXRInteractionProfile> &p_interaction_profile) {
106
ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr);
107
108
String profile_path = p_interaction_profile->get_interaction_profile_path();
109
110
// need to instance the correct editor for our profile
111
OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
112
if (interaction_profile_editors.has(profile_path)) {
113
Object *new_editor = ClassDB::instantiate(interaction_profile_editors[profile_path]);
114
if (new_editor) {
115
new_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(new_editor);
116
if (!new_profile_editor) {
117
WARN_PRINT("Interaction profile editor type mismatch for " + profile_path);
118
memfree(new_editor);
119
}
120
}
121
}
122
if (!new_profile_editor) {
123
// instance generic editor
124
new_profile_editor = memnew(OpenXRInteractionProfileEditor);
125
}
126
127
// now add it in..
128
ERR_FAIL_NULL_V(new_profile_editor, nullptr);
129
new_profile_editor->setup(action_map, p_interaction_profile);
130
tabs->add_child(new_profile_editor);
131
new_profile_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
132
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
133
134
if (!new_profile_editor->tooltip.is_empty()) {
135
tabs->set_tab_tooltip(tabs->get_tab_count() - 1, new_profile_editor->tooltip);
136
}
137
138
return new_profile_editor;
139
}
140
141
void OpenXRActionMapEditor::_create_interaction_profiles() {
142
if (action_map.is_valid()) {
143
Array new_interaction_profiles = action_map->get_interaction_profiles();
144
for (int i = 0; i < new_interaction_profiles.size(); i++) {
145
Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i];
146
_add_interaction_profile_editor(interaction_profile);
147
}
148
}
149
}
150
151
OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(const String &p_name) {
152
ERR_FAIL_COND_V(action_map.is_null(), nullptr);
153
Ref<OpenXRActionSet> new_action_set;
154
155
// add our new action set
156
new_action_set.instantiate();
157
new_action_set->set_name(p_name);
158
new_action_set->set_localized_name(p_name);
159
action_map->add_action_set(new_action_set);
160
action_map->set_edited(true);
161
162
// update our editor right away
163
OpenXRActionSetEditor *action_set_editor = _add_action_set_editor(new_action_set);
164
165
undo_redo->create_action(TTR("Add action set"));
166
undo_redo->add_do_method(this, "_do_add_action_set_editor", action_set_editor);
167
undo_redo->add_undo_method(this, "_do_remove_action_set_editor", action_set_editor);
168
undo_redo->commit_action(false);
169
170
return action_set_editor;
171
}
172
173
void OpenXRActionMapEditor::_remove_action_set(const String &p_name) {
174
ERR_FAIL_COND(action_map.is_null());
175
Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name);
176
ERR_FAIL_COND(action_set.is_null());
177
178
for (int i = 0; i < actionsets_vb->get_child_count(); i++) {
179
OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(actionsets_vb->get_child(i));
180
if (action_set_editor && action_set_editor->get_action_set() == action_set) {
181
_on_remove_action_set(action_set_editor);
182
}
183
}
184
}
185
186
void OpenXRActionMapEditor::_on_add_action_set() {
187
ERR_FAIL_COND(action_map.is_null());
188
String new_name = "New";
189
int count = 0;
190
191
while (action_map->find_action_set(new_name).is_valid()) {
192
new_name = "New_" + itos(count++);
193
}
194
195
OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name);
196
197
// Make sure our action set is the current tab
198
tabs->set_current_tab(0);
199
200
callable_mp(this, &OpenXRActionMapEditor::_set_focus_on_action_set).call_deferred(new_action_set_editor);
201
}
202
203
void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) {
204
// Scroll down to our new entry
205
actionsets_scroll->ensure_control_visible(p_action_set_editor);
206
207
// Set focus on this entry
208
p_action_set_editor->set_focus_on_entry();
209
}
210
211
void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
212
ERR_FAIL_COND(action_map.is_null());
213
214
OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor);
215
ERR_FAIL_NULL(action_set_editor);
216
ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb);
217
Ref<OpenXRActionSet> action_set = action_set_editor->get_action_set();
218
ERR_FAIL_COND(action_set.is_null());
219
220
// Remove all actions first.
221
action_set_editor->remove_all_actions();
222
223
// Make sure we update our interaction profiles.
224
for (int i = 0; i < tabs->get_tab_count(); i++) {
225
// First tab won't be an interaction profile editor, but being thorough..
226
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i));
227
if (interaction_profile_editor) {
228
interaction_profile_editor->remove_all_for_action_set(action_set);
229
}
230
}
231
232
// And now we can remove our action set.
233
undo_redo->create_action(TTR("Remove action set"));
234
undo_redo->add_do_method(this, "_do_remove_action_set_editor", action_set_editor);
235
undo_redo->add_undo_method(this, "_do_add_action_set_editor", action_set_editor);
236
undo_redo->commit_action(true);
237
238
action_map->set_edited(true);
239
}
240
241
void OpenXRActionMapEditor::_on_action_removed(const Ref<OpenXRAction> &p_action) {
242
for (int i = 0; i < tabs->get_tab_count(); i++) {
243
// First tab won't be an interaction profile editor, but being thorough..
244
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i));
245
if (interaction_profile_editor) {
246
interaction_profile_editor->remove_all_for_action(p_action);
247
}
248
}
249
}
250
251
void OpenXRActionMapEditor::_on_add_interaction_profile() {
252
ERR_FAIL_COND(action_map.is_null());
253
254
PackedStringArray already_selected;
255
256
for (int i = 0; i < action_map->get_interaction_profile_count(); i++) {
257
already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path());
258
}
259
260
select_interaction_profile_dialog->open(already_selected);
261
}
262
263
void OpenXRActionMapEditor::_on_interaction_profile_selected(const String &p_path) {
264
ERR_FAIL_COND(action_map.is_null());
265
266
Ref<OpenXRInteractionProfile> new_profile;
267
new_profile.instantiate();
268
new_profile->set_interaction_profile_path(p_path);
269
action_map->add_interaction_profile(new_profile);
270
action_map->set_edited(true);
271
272
OpenXRInteractionProfileEditorBase *interaction_profile_editor = _add_interaction_profile_editor(new_profile);
273
274
undo_redo->create_action(TTR("Add interaction profile"));
275
undo_redo->add_do_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
276
undo_redo->add_undo_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
277
undo_redo->commit_action(false);
278
279
tabs->set_current_tab(tabs->get_tab_count() - 1);
280
}
281
282
void OpenXRActionMapEditor::_load_action_map(const String &p_path, bool p_create_new_if_missing) {
283
Error err = OK;
284
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
285
if (da->file_exists(p_path)) {
286
action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
287
if (err != OK) {
288
EditorNode::get_singleton()->show_warning(vformat(TTR("Error loading %s: %s."), edited_path, TTR(error_names[err])));
289
290
edited_path = "";
291
header_label->set_text("");
292
return;
293
}
294
} else if (p_create_new_if_missing) {
295
action_map.instantiate();
296
action_map->create_default_action_sets();
297
298
// Save it immediately
299
err = ResourceSaver::save(action_map, p_path);
300
if (err != OK) {
301
// Show warning but continue.
302
EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), p_path, TTR(error_names[err])));
303
}
304
}
305
306
edited_path = p_path;
307
header_label->set_text(TTR("OpenXR Action map:") + " " + edited_path.get_file());
308
}
309
310
void OpenXRActionMapEditor::_on_save_action_map() {
311
Error err = ResourceSaver::save(action_map, edited_path);
312
if (err != OK) {
313
EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file %s: %s"), edited_path, TTR(error_names[err])));
314
return;
315
}
316
317
// TODO should clear undo/redo history
318
319
// out with the old
320
_clear_action_map();
321
322
_create_action_sets();
323
_create_interaction_profiles();
324
}
325
326
void OpenXRActionMapEditor::_on_reset_to_default_layout() {
327
// TODO should clear undo/redo history
328
329
// out with the old
330
_clear_action_map();
331
332
// create a new one
333
action_map.unref();
334
action_map.instantiate();
335
action_map->create_default_action_sets();
336
action_map->set_edited(true);
337
338
_create_action_sets();
339
_create_interaction_profiles();
340
}
341
342
void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
343
}
344
345
void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
346
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(p_tab));
347
ERR_FAIL_NULL(interaction_profile_editor);
348
349
undo_redo->create_action(TTR("Remove interaction profile"));
350
undo_redo->add_do_method(this, "_do_remove_interaction_profile_editor", interaction_profile_editor);
351
undo_redo->add_undo_method(this, "_do_add_interaction_profile_editor", interaction_profile_editor);
352
undo_redo->commit_action(true);
353
354
action_map->set_edited(true);
355
}
356
357
void OpenXRActionMapEditor::_do_add_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
358
Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
359
ERR_FAIL_COND(action_set.is_null());
360
361
action_map->add_action_set(action_set);
362
actionsets_vb->add_child(p_action_set_editor);
363
}
364
365
void OpenXRActionMapEditor::_do_remove_action_set_editor(OpenXRActionSetEditor *p_action_set_editor) {
366
Ref<OpenXRActionSet> action_set = p_action_set_editor->get_action_set();
367
ERR_FAIL_COND(action_set.is_null());
368
369
actionsets_vb->remove_child(p_action_set_editor);
370
action_map->remove_action_set(action_set);
371
}
372
373
void OpenXRActionMapEditor::_do_add_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
374
Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
375
ERR_FAIL_COND(interaction_profile.is_null());
376
377
action_map->add_interaction_profile(interaction_profile);
378
tabs->add_child(p_interaction_profile_editor);
379
tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
380
381
tabs->set_current_tab(tabs->get_tab_count() - 1);
382
}
383
384
void OpenXRActionMapEditor::_do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor) {
385
Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profile_editor->get_interaction_profile();
386
ERR_FAIL_COND(interaction_profile.is_null());
387
388
tabs->remove_child(p_interaction_profile_editor);
389
action_map->remove_interaction_profile(interaction_profile);
390
}
391
392
void OpenXRActionMapEditor::open_action_map(const String &p_path) {
393
make_visible();
394
395
// out with the old...
396
_clear_action_map();
397
398
// now load in our new action map
399
_load_action_map(p_path);
400
401
_create_action_sets();
402
_create_interaction_profiles();
403
}
404
405
void OpenXRActionMapEditor::_clear_action_map() {
406
while (actionsets_vb->get_child_count() > 0) {
407
Node *child = actionsets_vb->get_child(0);
408
actionsets_vb->remove_child(child);
409
child->queue_free();
410
}
411
412
for (int i = tabs->get_tab_count() - 1; i >= 0; --i) {
413
// First tab won't be an interaction profile editor, but being thorough..
414
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to<OpenXRInteractionProfileEditorBase>(tabs->get_tab_control(i));
415
if (interaction_profile_editor) {
416
tabs->remove_child(interaction_profile_editor);
417
interaction_profile_editor->queue_free();
418
}
419
}
420
}
421
422
void OpenXRActionMapEditor::register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class) {
423
interaction_profile_editors[p_for_path] = p_editor_class;
424
}
425
426
void OpenXRActionMapEditor::register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class) {
427
binding_modifier_editors[p_binding_modifier_class] = p_editor_class;
428
}
429
430
String OpenXRActionMapEditor::get_binding_modifier_editor_class(const String &p_binding_modifier_class) {
431
if (binding_modifier_editors.has(p_binding_modifier_class)) {
432
return binding_modifier_editors[p_binding_modifier_class];
433
}
434
435
return OpenXRBindingModifierEditor::get_class_static();
436
}
437
438
OpenXRActionMapEditor::OpenXRActionMapEditor() {
439
set_name(TTRC("OpenXR Action Map"));
440
set_icon_name("OpenXRActionMap");
441
set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_openxr_action_map_bottom_panel", TTRC("Toggle OpenXR Action Map Dock")));
442
set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);
443
set_available_layouts(EditorDock::DOCK_LAYOUT_HORIZONTAL | EditorDock::DOCK_LAYOUT_FLOATING);
444
set_custom_minimum_size(Size2(0.0, 300.0 * EDSCALE));
445
446
undo_redo = EditorUndoRedoManager::get_singleton();
447
448
VBoxContainer *main_vb = memnew(VBoxContainer);
449
add_child(main_vb);
450
451
top_hb = memnew(HBoxContainer);
452
main_vb->add_child(top_hb);
453
454
header_label = memnew(Label);
455
header_label->set_text(String(TTR("Action Map")));
456
header_label->set_clip_text(true);
457
header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
458
top_hb->add_child(header_label);
459
460
add_action_set = memnew(Button);
461
add_action_set->set_text(TTR("Add Action Set"));
462
add_action_set->set_tooltip_text(TTR("Add an action set."));
463
add_action_set->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set));
464
top_hb->add_child(add_action_set);
465
466
add_interaction_profile = memnew(Button);
467
add_interaction_profile->set_text(TTR("Add profile"));
468
add_interaction_profile->set_tooltip_text(TTR("Add an interaction profile."));
469
add_interaction_profile->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile));
470
top_hb->add_child(add_interaction_profile);
471
472
VSeparator *vseparator = memnew(VSeparator);
473
top_hb->add_child(vseparator);
474
475
save_as = memnew(Button);
476
save_as->set_text(TTR("Save"));
477
save_as->set_tooltip_text(TTR("Save this OpenXR action map."));
478
save_as->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map));
479
top_hb->add_child(save_as);
480
481
_default = memnew(Button);
482
_default->set_text(TTR("Reset to Default"));
483
_default->set_tooltip_text(TTR("Reset to default OpenXR action map."));
484
_default->connect(SceneStringName(pressed), callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout));
485
top_hb->add_child(_default);
486
487
tabs = memnew(TabContainer);
488
tabs->set_h_size_flags(SIZE_EXPAND_FILL);
489
tabs->set_v_size_flags(SIZE_EXPAND_FILL);
490
tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed));
491
tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed));
492
main_vb->add_child(tabs);
493
494
actionsets_scroll = memnew(ScrollContainer);
495
actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL);
496
actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
497
actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
498
tabs->add_child(actionsets_scroll);
499
actionsets_scroll->set_name(TTR("Action Sets"));
500
501
actionsets_vb = memnew(VBoxContainer);
502
actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL);
503
actionsets_scroll->add_child(actionsets_vb);
504
505
select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog);
506
select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
507
add_child(select_interaction_profile_dialog);
508
509
// Our Action map editor is only shown if openxr is enabled in project settings
510
// So load our action map and if it doesn't exist, create it right away.
511
_load_action_map(ResourceUID::ensure_path(GLOBAL_GET("xr/openxr/default_action_map")), true);
512
}
513
514