A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
2using System;
3using System.Collections.Generic;
4using System.IO;
5using System.Linq;
6using UnityEditor;
7using UnityEngine.InputSystem.Editor.Lists;
8using UnityEngine.InputSystem.Utilities;
9
10namespace UnityEngine.InputSystem.Editor
11{
12 internal delegate InputActionsEditorState Command(in InputActionsEditorState state);
13
14 internal static class Commands
15 {
16 public static Command SelectAction(string actionName)
17 {
18 return (in InputActionsEditorState state) => state.SelectAction(actionName);
19 }
20
21 public static Command SelectAction(int index)
22 {
23 return (in InputActionsEditorState state) => state.SelectAction(index);
24 }
25
26 public static Command SelectActionMap(string actionMapName)
27 {
28 return (in InputActionsEditorState state) => state.SelectActionMap(actionMapName);
29 }
30
31 public static Command AddActionMap()
32 {
33 return (in InputActionsEditorState state) =>
34 {
35 var newMap = InputActionSerializationHelpers.AddActionMap(state.serializedObject);
36 var actionProperty = InputActionSerializationHelpers.AddAction(newMap);
37 InputActionSerializationHelpers.AddBinding(actionProperty, newMap);
38 state.serializedObject.ApplyModifiedProperties();
39 state.m_Analytics?.RegisterActionMapEdit();
40 return state.SelectActionMap(newMap);
41 };
42 }
43
44 public static Command AddAction()
45 {
46 return (in InputActionsEditorState state) =>
47 {
48 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
49 if (actionMap == null)
50 {
51 Debug.LogError("Cannot add action without an action map selected");
52 return state;
53 }
54 var newAction = InputActionSerializationHelpers.AddAction(actionMap);
55 InputActionSerializationHelpers.AddBinding(newAction, actionMap);
56 state.serializedObject.ApplyModifiedProperties();
57 state.m_Analytics?.RegisterActionEdit();
58 return state.SelectAction(newAction);
59 };
60 }
61
62 public static Command AddBinding()
63 {
64 return (in InputActionsEditorState state) =>
65 {
66 var action = Selectors.GetSelectedAction(state)?.wrappedProperty;
67 var map = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
68 if (action == null || map == null)
69 {
70 Debug.LogError("Cannot add binding without an action and action map selected");
71 return state;
72 }
73 var binding = InputActionSerializationHelpers.AddBinding(action, map);
74 var bindingIndex = new SerializedInputBinding(binding).indexOfBinding;
75 state.serializedObject.ApplyModifiedProperties();
76 state.m_Analytics?.RegisterBindingEdit();
77 return state.With(selectedBindingIndex: bindingIndex, selectionType: SelectionType.Binding);
78 };
79 }
80
81 public static Command AddComposite(string compositeName)
82 {
83 return (in InputActionsEditorState state) =>
84 {
85 var action = Selectors.GetSelectedAction(state)?.wrappedProperty;
86 var map = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
87 var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(compositeName);
88 var composite = InputActionSerializationHelpers.AddCompositeBinding(action, map, compositeName, compositeType);
89 var index = new SerializedInputBinding(composite).indexOfBinding;
90 state.serializedObject.ApplyModifiedProperties();
91 state.m_Analytics?.RegisterBindingEdit();
92 return state.With(selectedBindingIndex: index, selectionType: SelectionType.Binding);
93 };
94 }
95
96 public static Command DeleteActionMap(int actionMapIndex)
97 {
98 return (in InputActionsEditorState state) =>
99 {
100 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
101 var actionMapID = InputActionSerializationHelpers.GetId(actionMap);
102 var isCut = state.IsActionMapCut(actionMapIndex);
103 InputActionSerializationHelpers.DeleteActionMap(state.serializedObject, actionMapID);
104 state.serializedObject.ApplyModifiedProperties();
105 state.m_Analytics?.RegisterActionMapEdit();
106 if (state.selectedActionMapIndex == actionMapIndex)
107 return isCut ? SelectPrevActionMap(state).ClearCutElements() : SelectPrevActionMap(state);
108 if (isCut)
109 return state.SelectActionMap(state.selectedActionMapIndex > actionMapIndex ? state.selectedActionMapIndex - 1 : state.selectedActionMapIndex).ClearCutElements();
110 return state.SelectActionMap(state.selectedActionMapIndex > actionMapIndex ? state.selectedActionMapIndex - 1 : state.selectedActionMapIndex);
111 };
112 }
113
114 public static Command CopyActionMapSelection()
115 {
116 return (in InputActionsEditorState state) =>
117 {
118 CopyPasteHelper.CopyActionMap(state);
119 return state.ClearCutElements();
120 };
121 }
122
123 public static Command CutActionMapSelection()
124 {
125 return (in InputActionsEditorState state) =>
126 {
127 CopyPasteHelper.CutActionMap(state);
128 return state.CutActionMaps();
129 };
130 }
131
132 public static Command CopyActionBindingSelection()
133 {
134 return (in InputActionsEditorState state) =>
135 {
136 CopyPasteHelper.Copy(state);
137 return state.ClearCutElements();
138 };
139 }
140
141 public static Command CutActionsOrBindings()
142 {
143 return (in InputActionsEditorState state) =>
144 {
145 CopyPasteHelper.Cut(state);
146 return state.CutActionOrBinding();
147 };
148 }
149
150 public static Command PasteActionMaps(IReadOnlyList<IPasteListener> pasteListeners)
151 {
152 return (in InputActionsEditorState state) =>
153 {
154 var newIndex = -99;
155 if (state.hasCutElements)
156 newIndex = CopyPasteHelper.DeleteCutElements(state);
157 else
158 {
159 foreach (var pasteListener in pasteListeners)
160 pasteListener.OnPaste(state);
161 }
162 var lastPastedElement = CopyPasteHelper.PasteActionMapsFromClipboard(state.With(selectedActionMapIndex: newIndex >= -1 ? newIndex : state.selectedActionMapIndex));
163 if (lastPastedElement != null)
164 {
165 state.serializedObject.ApplyModifiedProperties();
166 return state.With(selectedActionMapIndex: lastPastedElement.GetIndexOfArrayElement()).ClearCutElements();
167 }
168 return state.ClearCutElements();
169 };
170 }
171
172 public static Command DeleteCutElements()
173 {
174 return (in InputActionsEditorState state) =>
175 {
176 if (!state.hasCutElements)
177 return state;
178 CopyPasteHelper.DeleteCutElements(state);
179 state.serializedObject.ApplyModifiedProperties();
180 return state.ClearCutElements();
181 };
182 }
183
184 public static Command PasteActionIntoActionMap(int actionMapIndex)
185 {
186 return (in InputActionsEditorState state) =>
187 {
188 CopyPasteHelper.Copy(state);
189 var action = Selectors.GetSelectedAction(state);
190 var actionMap = Selectors.GetActionMapForAction(state, action?.id);
191 var isCut = action.HasValue && state.IsActionCut(actionMap.GetIndexOfArrayElement(),
192 action.Value.wrappedProperty.GetIndexOfArrayElement());
193 InputActionSerializationHelpers.DeleteActionAndBindings(actionMap, InputActionSerializationHelpers.GetId(action?.wrappedProperty));
194 var lastPastedElement = CopyPasteHelper.PasteActionsOrBindingsFromClipboard(state, true, actionMapIndex);
195 if (lastPastedElement != null)
196 state.serializedObject.ApplyModifiedProperties();
197 EditorHelpers.SetSystemCopyBufferContents(string.Empty);
198 if (isCut)
199 return state.ClearCutElements();
200 return state;
201 };
202 }
203
204 public static Command PasteActionFromActionMap(List<IPasteListener> pasteListeners)
205 {
206 return (in InputActionsEditorState state) =>
207 {
208 var newIndex = -1;
209 if (state.hasCutElements)
210 newIndex = CopyPasteHelper.DeleteCutElements(state);
211 else
212 {
213 foreach (var pasteListener in pasteListeners)
214 pasteListener.OnPaste(state);
215 }
216 var lastPastedElement = CopyPasteHelper.PasteActionsOrBindingsFromClipboard(state.With(selectedActionIndex: newIndex >= 0 ? newIndex : state.selectedActionIndex), true);
217 if (lastPastedElement != null)
218 {
219 state.serializedObject.ApplyModifiedProperties();
220 return state.With(selectedActionIndex: lastPastedElement.GetIndexOfArrayElement(), selectionType: SelectionType.Action).ClearCutElements();
221 }
222 return state.ClearCutElements();
223 };
224 }
225
226 public static Command PasteActionsOrBindings(List<IPasteListener> pasteListeners)
227 {
228 return (in InputActionsEditorState state) =>
229 {
230 var typeOfCopiedData = CopyPasteHelper.GetCopiedClipboardType();
231 SerializedInputAction? relatedAction = null;
232 if (state.selectionType == SelectionType.Binding)
233 relatedAction = Selectors.GetRelatedInputAction(state);
234
235 var newIndex = -1;
236 if (state.hasCutElements)
237 newIndex = CopyPasteHelper.DeleteCutElements(state);
238 else
239 {
240 foreach (var pasteListener in pasteListeners)
241 pasteListener.OnPaste(state);
242 }
243 SerializedProperty lastPastedElement = null;
244 if (state.selectionType == SelectionType.Action)
245 {
246 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
247 var actions = Selectors.GetActionCount(actionMap);
248 if (actions.HasValue && actions.Value > 0)
249 lastPastedElement = CopyPasteHelper.PasteActionsOrBindingsFromClipboard(
250 state.With(selectedActionIndex: newIndex >= 0 ? newIndex : state.selectedActionIndex),
251 typeOfCopiedData == typeof(InputBinding));
252 else
253 {
254 lastPastedElement =
255 CopyPasteHelper.PasteActionsOrBindingsFromClipboard(
256 state.With(selectedActionMapIndex: actionMap.GetIndexOfArrayElement()), addLast: true);
257 }
258 }
259 else if (state.selectionType == SelectionType.Binding)
260 {
261 if (relatedAction != null)
262 {
263 var bindings = Selectors.GetBindingsForAction(relatedAction.Value.name, state);
264 if (bindings.Count == 0) //add cutted binding into action instead if there are no bindings left for the action
265 lastPastedElement = CopyPasteHelper.PasteActionsOrBindingsFromClipboard(state.With(selectedActionIndex: relatedAction.Value.wrappedProperty.GetIndexOfArrayElement(), selectionType: SelectionType.Action));
266 else
267 lastPastedElement = CopyPasteHelper.PasteActionsOrBindingsFromClipboard(state.With(selectedBindingIndex: newIndex >= 0 ? newIndex : state.selectedBindingIndex));
268
269 lastPastedElement.FindPropertyRelative("m_Action").stringValue = relatedAction.Value.name;
270 }
271 }
272
273 if (lastPastedElement != null)
274 {
275 state.serializedObject.ApplyModifiedProperties();
276 if (typeOfCopiedData == typeof(InputAction))
277 return state.With(selectedActionIndex: lastPastedElement.GetIndexOfArrayElement()).ClearCutElements();
278 if (typeOfCopiedData == typeof(InputBinding))
279 return state.With(selectedBindingIndex: lastPastedElement.GetIndexOfArrayElement()).ClearCutElements();
280 }
281 return state.ClearCutElements();
282 };
283 }
284
285 public static Command DuplicateActionMap(int actionMapIndex)
286 {
287 return (in InputActionsEditorState state) =>
288 {
289 var actionMapArray = state.serializedObject.FindProperty(nameof(InputActionAsset.m_ActionMaps));
290 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
291 var name = actionMap?.FindPropertyRelative(nameof(InputAction.m_Name)).stringValue;
292 var newMap = CopyPasteHelper.DuplicateElement(actionMapArray, actionMap, name, actionMap.GetIndexOfArrayElement() + 1);
293 state.serializedObject.ApplyModifiedProperties();
294 state.m_Analytics?.RegisterActionMapEdit();
295 return state.SelectActionMap(newMap.FindPropertyRelative(nameof(InputAction.m_Name)).stringValue);
296 };
297 }
298
299 public static Command DuplicateAction()
300 {
301 return (in InputActionsEditorState state) =>
302 {
303 var action = Selectors.GetSelectedAction(state)?.wrappedProperty;
304 var actionMap = Selectors.GetActionMapAtIndex(state, state.selectedActionMapIndex)?.wrappedProperty;
305 var actionArray = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Actions));
306 CopyPasteHelper.DuplicateAction(actionArray, action, actionMap, state);
307 state.serializedObject.ApplyModifiedProperties();
308 state.m_Analytics?.RegisterActionEdit();
309 return state.SelectAction(state.selectedActionIndex + 1);
310 };
311 }
312
313 public static Command DuplicateBinding()
314 {
315 return (in InputActionsEditorState state) =>
316 {
317 var binding = Selectors.GetSelectedBinding(state)?.wrappedProperty;
318 var actionName = binding?.FindPropertyRelative("m_Action").stringValue;
319 var actionMap = Selectors.GetActionMapAtIndex(state, state.selectedActionMapIndex)?.wrappedProperty;
320 var bindingsArray = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Bindings));
321 var newIndex = CopyPasteHelper.DuplicateBinding(bindingsArray, binding, actionName, binding.GetIndexOfArrayElement() + 1);
322 state.serializedObject.ApplyModifiedProperties();
323 state.m_Analytics?.RegisterBindingEdit();
324 return state.SelectBinding(newIndex);
325 };
326 }
327
328 private static InputActionsEditorState SelectPrevActionMap(InputActionsEditorState state)
329 {
330 var count = Selectors.GetActionMapCount(state);
331 var index = 0;
332 if (count != null && count.Value > 0)
333 index = Math.Max(state.selectedActionMapIndex - 1, 0);
334 return state.SelectActionMap(index);
335 }
336
337 public static Command ReorderActionMap(int oldIndex, int newIndex)
338 {
339 return (in InputActionsEditorState state) =>
340 {
341 InputActionSerializationHelpers.MoveActionMap(state.serializedObject, oldIndex, newIndex);
342 state.serializedObject.ApplyModifiedProperties();
343 return state.SelectActionMap(newIndex);
344 };
345 }
346
347 public static Command MoveAction(int oldIndex, int newIndex)
348 {
349 return (in InputActionsEditorState state) =>
350 {
351 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
352 InputActionSerializationHelpers.MoveAction(actionMap, oldIndex, newIndex);
353 state.serializedObject.ApplyModifiedProperties();
354 return state.SelectAction(newIndex);
355 };
356 }
357
358 public static Command MoveBinding(int oldIndex, int actionIndex, int childIndex)
359 {
360 return (in InputActionsEditorState state) =>
361 {
362 var newBindingIndex = MoveBindingOrComposite(state, oldIndex, actionIndex, childIndex);
363 state.serializedObject.ApplyModifiedProperties();
364 return state.SelectBinding(newBindingIndex);
365 };
366 }
367
368 public static Command MoveComposite(int oldIndex, int actionIndex, int childIndex)
369 {
370 return (in InputActionsEditorState state) =>
371 {
372 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
373 var compositeBindings = CopyPasteHelper.GetBindingsForComposite(actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Bindings)), oldIndex);
374 //move the composite element
375 var newBindingIndex = MoveBindingOrComposite(state, oldIndex, actionIndex, childIndex);
376 var actionTo = Selectors.GetActionForIndex(actionMap, actionIndex).FindPropertyRelative(nameof(InputAction.m_Name)).stringValue;
377 var toIndex = newBindingIndex;
378 foreach (var compositePart in compositeBindings)
379 {
380 // the index of the composite part stays the same if composite was moved down as previous elements are shifted down (the index seems to update async so it's safer to use the oldIndex)
381 // if the composite was moved up, the index of the composite part is not changing so we are safe to use it
382 var from = oldIndex < newBindingIndex ? oldIndex : compositePart.GetIndexOfArrayElement();
383 // if added below the old position the array changes as composite parts are added on top (increase the index)
384 // if added above the oldIndex, the index does not change
385 var to = oldIndex < newBindingIndex ? newBindingIndex : ++toIndex;
386 InputActionSerializationHelpers.MoveBinding(actionMap, from, to);
387 Selectors.GetCompositeOrBindingInMap(actionMap, to).wrappedProperty.FindPropertyRelative("m_Action").stringValue = actionTo;
388 }
389 state.m_Analytics?.RegisterBindingEdit();
390 state.serializedObject.ApplyModifiedProperties();
391 return state.SelectBinding(newBindingIndex);
392 };
393 }
394
395 private static int MoveBindingOrComposite(InputActionsEditorState state, int oldIndex, int actionIndex, int childIndex)
396 {
397 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
398 var bindingsForAction = Selectors.GetBindingsForAction(state, actionMap, actionIndex);
399 var allBindings = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Bindings));
400 var actionTo = Selectors.GetActionForIndex(actionMap, actionIndex).FindPropertyRelative(nameof(InputAction.m_Name)).stringValue;
401 var actionFrom = Selectors.GetCompositeOrBindingInMap(actionMap, oldIndex).wrappedProperty.FindPropertyRelative("m_Action");
402 int newBindingIndex;
403 if (bindingsForAction.Count == 0) //if there are no bindings for an action retrieve the first binding index of a binding before (iterate previous actions)
404 newBindingIndex = Selectors.GetBindingIndexBeforeAction(allBindings, actionIndex, allBindings);
405 else
406 {
407 var toSkip = GetNumberOfCompositePartItemsToSkip(bindingsForAction, childIndex, oldIndex); //skip composite parts if there are - avoid moving into a composite
408 newBindingIndex = bindingsForAction[0].GetIndexOfArrayElement() + Math.Clamp(childIndex + toSkip, 0, bindingsForAction.Count);
409 newBindingIndex -= newBindingIndex > oldIndex && !actionTo.Equals(actionFrom.stringValue) ? 1 : 0; // reduce index by one in case the moved binding will be shifted underneath to another action
410 }
411
412 state.m_Analytics?.RegisterBindingEdit();
413 actionFrom.stringValue = actionTo;
414 InputActionSerializationHelpers.MoveBinding(actionMap, oldIndex, newBindingIndex);
415 return newBindingIndex;
416 }
417
418 private static int GetNumberOfCompositePartItemsToSkip(List<SerializedProperty> bindings, int childIndex, int oldIndex)
419 {
420 var toSkip = 0;
421 var normalBindings = 0;
422 foreach (var binding in bindings)
423 {
424 if (binding.GetIndexOfArrayElement() == oldIndex)
425 continue;
426 if (normalBindings > childIndex)
427 break;
428 if (binding.FindPropertyRelative(nameof(InputBinding.m_Flags)).intValue ==
429 (int)InputBinding.Flags.PartOfComposite)
430 toSkip++;
431 else
432 normalBindings++;
433 }
434 return toSkip;
435 }
436
437 public static Command MovePartOfComposite(int oldIndex, int newIndex, int compositeIndex)
438 {
439 return (in InputActionsEditorState state) =>
440 {
441 var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
442 var actionTo = actionMap?.FindPropertyRelative(nameof(InputActionMap.m_Bindings)).GetArrayElementAtIndex(compositeIndex).FindPropertyRelative("m_Action").stringValue;
443 InputActionSerializationHelpers.MoveBinding(actionMap, oldIndex, newIndex);
444 Selectors.GetCompositeOrBindingInMap(actionMap, newIndex).wrappedProperty.FindPropertyRelative("m_Action").stringValue = actionTo;
445 state.m_Analytics?.RegisterBindingEdit();
446 state.serializedObject.ApplyModifiedProperties();
447 return state.SelectBinding(newIndex);
448 };
449 }
450
451 public static Command DeleteAction(int actionMapIndex, string actionName)
452 {
453 return (in InputActionsEditorState state) =>
454 {
455 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
456 var action = Selectors.GetActionInMap(state, actionMapIndex, actionName).wrappedProperty;
457 var actionIndex = action.GetIndexOfArrayElement();
458 var actionID = InputActionSerializationHelpers.GetId(action);
459 var isCut = state.IsActionCut(actionMapIndex, actionIndex);
460 InputActionSerializationHelpers.DeleteActionAndBindings(actionMap, actionID);
461 state.serializedObject.ApplyModifiedProperties();
462 state.m_Analytics?.RegisterActionEdit();
463
464 if (isCut)
465 return state.With(selectedActionIndex: -1, selectionType: SelectionType.Action).ClearCutElements();
466 return state.With(selectedActionIndex: -1, selectionType: SelectionType.Action); // ActionsTreeView will dispatch a separate command to select the previous Action
467 };
468 }
469
470 public static Command DeleteBinding(int actionMapIndex, int bindingIndex)
471 {
472 return (in InputActionsEditorState state) =>
473 {
474 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
475 var binding = Selectors.GetCompositeOrBindingInMap(actionMap, bindingIndex).wrappedProperty;
476 var isCut = state.IsBindingCut(actionMapIndex, bindingIndex);
477 InputActionSerializationHelpers.DeleteBinding(binding, actionMap);
478 state.serializedObject.ApplyModifiedProperties();
479 state.m_Analytics?.RegisterBindingEdit();
480
481 if (isCut)
482 return state.With(selectedBindingIndex: -1, selectionType: SelectionType.Binding).ClearCutElements();
483 return state.With(selectedBindingIndex: -1, selectionType: SelectionType.Binding); // ActionsTreeView will dispatch a separate command to select the previous Binding
484 };
485 }
486
487 public static Command SelectBinding(int bindingIndex)
488 {
489 return (in InputActionsEditorState state) =>
490 state.With(selectedBindingIndex: bindingIndex, selectionType: SelectionType.Binding);
491 }
492
493 public static Command UpdatePathNameAndValues(NamedValue[] parameters, SerializedProperty pathProperty)
494 {
495 return (in InputActionsEditorState state) =>
496 {
497 var path = pathProperty.stringValue;
498 var nameAndParameters = NameAndParameters.Parse(path);
499 nameAndParameters.parameters = parameters;
500
501 pathProperty.stringValue = nameAndParameters.ToString();
502 state.serializedObject.ApplyModifiedProperties();
503 state.m_Analytics?.RegisterBindingEdit();
504 return state;
505 };
506 }
507
508 public static Command SetCompositeBindingType(SerializedInputBinding bindingProperty, IEnumerable<string> compositeTypes,
509 ParameterListView parameterListView, int selectedCompositeTypeIndex)
510 {
511 return (in InputActionsEditorState state) =>
512 {
513 var nameAndParameters = new NameAndParameters
514 {
515 name = compositeTypes.ElementAt(selectedCompositeTypeIndex),
516 parameters = parameterListView.GetParameters()
517 };
518 InputActionSerializationHelpers.ChangeCompositeBindingType(bindingProperty.wrappedProperty, nameAndParameters);
519 state.serializedObject.ApplyModifiedProperties();
520 state.m_Analytics?.RegisterBindingEdit(); // Questionable if action or binding edit?
521 return state;
522 };
523 }
524
525 public static Command SetCompositeBindingPartName(SerializedInputBinding bindingProperty, string partName)
526 {
527 return (in InputActionsEditorState state) =>
528 {
529 InputActionSerializationHelpers.SetBindingPartName(bindingProperty.wrappedProperty, partName);
530 state.serializedObject.ApplyModifiedProperties();
531 state.m_Analytics?.RegisterBindingEdit();
532 return state;
533 };
534 }
535
536 public static Command ChangeActionType(SerializedInputAction inputAction, InputActionType newValue)
537 {
538 return (in InputActionsEditorState state) =>
539 {
540 inputAction.wrappedProperty.FindPropertyRelative(nameof(InputAction.m_Type)).intValue = (int)newValue;
541 state.serializedObject.ApplyModifiedProperties();
542 state.m_Analytics?.RegisterActionEdit();
543 return state;
544 };
545 }
546
547 public static Command ChangeInitialStateCheck(SerializedInputAction inputAction, bool value)
548 {
549 return (in InputActionsEditorState state) =>
550 {
551 var property = inputAction.wrappedProperty.FindPropertyRelative(nameof(InputAction.m_Flags));
552 if (value)
553 property.intValue |= (int)InputAction.ActionFlags.WantsInitialStateCheck;
554 else
555 property.intValue &= ~(int)InputAction.ActionFlags.WantsInitialStateCheck;
556 state.serializedObject.ApplyModifiedProperties();
557 state.m_Analytics?.RegisterActionEdit();
558 return state;
559 };
560 }
561
562 public static Command ChangeActionControlType(SerializedInputAction inputAction, int controlTypeIndex)
563 {
564 return (in InputActionsEditorState state) =>
565 {
566 var controlTypes = Selectors.BuildControlTypeList(inputAction.type).ToList();
567
568 // ISX-1650: "Any" (in index 0) should not be put into an InputAction.expectedControlType. It's expected to be null in this case.
569 var controlType = (controlTypeIndex == 0) ? string.Empty : controlTypes[controlTypeIndex];
570 inputAction.wrappedProperty.FindPropertyRelative(nameof(InputAction.m_ExpectedControlType)).stringValue = controlType;
571 state.serializedObject.ApplyModifiedProperties();
572 state.m_Analytics?.RegisterActionEdit();
573 return state;
574 };
575 }
576
577 /// <summary>
578 /// Exists to integrate with some existing UI stuff, like InputControlPathEditor
579 /// </summary>
580 /// <returns></returns>
581 public static Command ApplyModifiedProperties()
582 {
583 return (in InputActionsEditorState state) =>
584 {
585 state.serializedObject.ApplyModifiedProperties();
586 return state;
587 };
588 }
589
590 public static Command SaveAsset(Action postSaveAction)
591 {
592 return (in InputActionsEditorState state) =>
593 {
594 // TODO This needs to callback to owning editor to save or have asset GUID
595 // TODO It makes more sense to call back to editor since editor owns target object?
596 //InputActionAssetManager.SaveAsset(state.serializedObject.targetObject as InputActionAsset);
597 postSaveAction?.Invoke();
598 state.m_Analytics?.RegisterExplicitSave();
599 return state;
600 };
601 }
602
603 public static Command ToggleAutoSave(bool newValue, Action postSaveAction)
604 {
605 return (in InputActionsEditorState state) =>
606 {
607 if (newValue != InputEditorUserSettings.autoSaveInputActionAssets)
608 {
609 // If it changed from disabled to enabled, perform an initial save.
610 if (newValue)
611 {
612 //InputActionAssetManager.SaveAsset(state.serializedObject.targetObject as InputActionAsset);
613 postSaveAction?.Invoke();
614 state.m_Analytics?.RegisterAutoSave();
615 }
616
617 InputEditorUserSettings.autoSaveInputActionAssets = newValue;
618 }
619
620 return state;
621 };
622 }
623
624 public static Command ChangeActionMapName(int index, string newName)
625 {
626 return (in InputActionsEditorState state) =>
627 {
628 var actionMap = Selectors.GetActionMapAtIndex(state, index)?.wrappedProperty;
629 InputActionSerializationHelpers.RenameActionMap(actionMap, newName);
630 state.serializedObject.ApplyModifiedProperties();
631 state.m_Analytics?.RegisterActionMapEdit();
632 return state;
633 };
634 }
635
636 public static Command ChangeActionName(int actionMapIndex, string oldName, string newName)
637 {
638 return (in InputActionsEditorState state) =>
639 {
640 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
641 var action = Selectors.GetActionInMap(state, actionMapIndex, oldName).wrappedProperty;
642 InputActionSerializationHelpers.RenameAction(action, actionMap, newName);
643 state.serializedObject.ApplyModifiedProperties();
644 state.m_Analytics?.RegisterActionEdit();
645 return state;
646 };
647 }
648
649 public static Command ChangeCompositeName(int actionMapIndex, int bindingIndex, string newName)
650 {
651 return (in InputActionsEditorState state) =>
652 {
653 var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
654 var binding = Selectors.GetCompositeOrBindingInMap(actionMap, bindingIndex).wrappedProperty;
655 InputActionSerializationHelpers.RenameComposite(binding, newName);
656 state.serializedObject.ApplyModifiedProperties();
657 state.m_Analytics?.RegisterBindingEdit();
658 return state;
659 };
660 }
661
662 // Removes all action maps and their content from the associated serialized InputActionAsset.
663 public static Command ClearActionMaps()
664 {
665 return (in InputActionsEditorState state) =>
666 {
667 state.m_Analytics?.RegisterReset();
668
669 InputActionSerializationHelpers.DeleteAllActionMaps(state.serializedObject);
670 state.serializedObject.ApplyModifiedProperties();
671 return state.ClearCutElements();
672 };
673 }
674
675 // Replaces all action maps of the associated serialized InputActionAsset with the action maps contained in
676 // the given source asset.
677 public static Command ReplaceActionMaps(string inputActionAssetJsonContent)
678 {
679 return (in InputActionsEditorState state) =>
680 {
681 // First delete all existing data
682 InputActionSerializationHelpers.DeleteAllActionMaps(state.serializedObject);
683 InputActionSerializationHelpers.DeleteAllControlSchemes(state.serializedObject);
684
685 // Create new data based on source
686 var temp = InputActionAsset.FromJson(inputActionAssetJsonContent);
687 using (var tmp = new SerializedObject(temp))
688 {
689 InputActionSerializationHelpers.AddControlSchemes(state.serializedObject, tmp);
690 InputActionSerializationHelpers.AddActionMaps(state.serializedObject, tmp);
691 }
692 state.serializedObject.ApplyModifiedProperties();
693 state.m_Analytics.RegisterActionMapEdit();
694
695 return state.ClearCutElements();
696 };
697 }
698 }
699}
700
701#endif