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