Skip to content

Commit 4889a2b

Browse files
authored
NEW: delete & rename actions, maps and bindings (ISX-1373, ISX-1039) (#1681)
* Fix: focus & focusOut events for inputFields * Change: only rename actions & composites * Fix: fixed NullReference if TreeViewItem out of screen * Fix: rename wrong action or actionMap * added edit on return and improved with use itemsChosen event * fixed renaming with F2 * rename composites properly * fixed rename canceled on click away * avoid NullReferenceError at MapListView if item out of screen * fixed renaming actionMap -> excluding own name * fixed action maps not renamed bug + removed redundant line * add context menu with rename functionality * added: functionality to delete bindings * added: functionality for deleting actions * added: deleting action maps * fixed errors on delete bindings * fixed errors for deleting actions * fixed action not focused after adding a new one * fixed delete actionMaps & unsubscribe handlers correctly * shortcut selector method * fixed selection not updated in ActionsTreeView * some refactoring * added delete with DEL key functionality * formatting fix * formatting * fixed small no binding name issue * refactor for PR * re-adding some dependencies * pragma fix for example script * Revert "pragma fix for example script" This reverts commit 3c99e45.
1 parent c55cdd9 commit 4889a2b

13 files changed

Lines changed: 584 additions & 131 deletions

Packages/com.unity.inputsystem/InputSystem/Editor/Internal/InputActionSerializationHelpers.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,18 @@ public static void ChangeBinding(SerializedProperty bindingProperty, string path
335335
}
336336
}
337337

338-
public static void DeleteBinding(SerializedProperty bindingArrayProperty, Guid id)
338+
public static void DeleteBinding(SerializedProperty binding, SerializedProperty actionMap)
339+
{
340+
var bindingsProperty = actionMap.FindPropertyRelative("m_Bindings");
341+
DeleteBinding(binding, bindingsProperty, binding.GetIndexOfArrayElement());
342+
}
343+
344+
private static void DeleteBinding(SerializedProperty bindingProperty, SerializedProperty bindingArrayProperty, int bindingIndex)
339345
{
340-
// If it's a composite, delete all its parts first.
341-
var bindingIndex = GetIndex(bindingArrayProperty, id);
342-
var bindingProperty = bindingArrayProperty.GetArrayElementAtIndex(bindingIndex);
343346
var bindingFlags = (InputBinding.Flags)bindingProperty.FindPropertyRelative("m_Flags").intValue;
344-
if ((bindingFlags & InputBinding.Flags.Composite) != 0)
347+
var isComposite = (bindingFlags & InputBinding.Flags.Composite) != 0;
348+
// If it's a composite, delete all its parts first.
349+
if (isComposite)
345350
{
346351
for (var partIndex = bindingIndex + 1; partIndex < bindingArrayProperty.arraySize;)
347352
{
@@ -356,6 +361,13 @@ public static void DeleteBinding(SerializedProperty bindingArrayProperty, Guid i
356361
bindingArrayProperty.DeleteArrayElementAtIndex(bindingIndex);
357362
}
358363

364+
public static void DeleteBinding(SerializedProperty bindingArrayProperty, Guid id)
365+
{
366+
var bindingIndex = GetIndex(bindingArrayProperty, id);
367+
var bindingProperty = bindingArrayProperty.GetArrayElementAtIndex(bindingIndex);
368+
DeleteBinding(bindingProperty, bindingArrayProperty, bindingIndex);
369+
}
370+
359371
public static void AssignUniqueIDs(SerializedProperty element)
360372
{
361373
// Assign new ID to map.
@@ -439,7 +451,7 @@ public static void RenameActionMap(SerializedProperty actionMapProperty, string
439451
// Make sure name is unique in InputActionAsset.
440452
var assetObject = actionMapProperty.serializedObject;
441453
var mapsArrayProperty = assetObject.FindProperty("m_ActionMaps");
442-
var uniqueName = FindUniqueName(mapsArrayProperty, newName);
454+
var uniqueName = FindUniqueName(mapsArrayProperty, newName, actionMapProperty.GetIndexOfArrayElement());
443455

444456
// Assign to map.
445457
var nameProperty = actionMapProperty.FindPropertyRelative("m_Name");

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Commands/Commands.cs

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_UI_TK_ASSET_EDITOR
2+
using System;
23
using System.Collections.Generic;
34
using System.Linq;
45
using UnityEditor;
@@ -37,7 +38,12 @@ public static Command AddAction()
3738
{
3839
return (in InputActionsEditorState state) =>
3940
{
40-
var actionMap = Selectors.GetSelectedActionMap(state).wrappedProperty;
41+
var actionMap = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
42+
if (actionMap == null)
43+
{
44+
Debug.LogError("Cannot add action without an action map selected");
45+
return state;
46+
}
4147
var newAction = InputActionSerializationHelpers.AddAction(actionMap);
4248
InputActionSerializationHelpers.AddBinding(newAction, actionMap);
4349
state.serializedObject.ApplyModifiedProperties();
@@ -49,15 +55,91 @@ public static Command AddBinding()
4955
{
5056
return (in InputActionsEditorState state) =>
5157
{
52-
var action = Selectors.GetSelectedAction(state).wrappedProperty;
53-
var map = Selectors.GetSelectedActionMap(state).wrappedProperty;
58+
var action = Selectors.GetSelectedAction(state)?.wrappedProperty;
59+
var map = Selectors.GetSelectedActionMap(state)?.wrappedProperty;
60+
if (action == null || map == null)
61+
{
62+
Debug.LogError("Cannot add binding without an action and action map selected");
63+
return state;
64+
}
5465
var binding = InputActionSerializationHelpers.AddBinding(action, map);
5566
var bindingIndex = new SerializedInputBinding(binding).indexOfBinding;
5667
state.serializedObject.ApplyModifiedProperties();
5768
return state.With(selectedBindingIndex: bindingIndex, selectionType: SelectionType.Binding);
5869
};
5970
}
6071

72+
public static Command DeleteActionMap(int actionMapIndex)
73+
{
74+
return (in InputActionsEditorState state) =>
75+
{
76+
var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
77+
var actionMapID = InputActionSerializationHelpers.GetId(actionMap);
78+
InputActionSerializationHelpers.DeleteActionMap(state.serializedObject, actionMapID);
79+
state.serializedObject.ApplyModifiedProperties();
80+
if (state.selectedActionMapIndex == actionMapIndex)
81+
return SelectPrevActionMap(state);
82+
return state.SelectActionMap(state.selectedActionMapIndex > actionMapIndex ? state.selectedActionMapIndex - 1 : state.selectedActionMapIndex);
83+
};
84+
}
85+
86+
private static InputActionsEditorState SelectPrevActionMap(InputActionsEditorState state)
87+
{
88+
var count = Selectors.GetActionMapCount(state.serializedObject);
89+
int index = -1;
90+
if (count != null && count.Value > 0)
91+
index = Math.Max(state.selectedActionMapIndex - 1, 0);
92+
return state.SelectActionMap(index);
93+
}
94+
95+
public static Command DeleteAction(int actionMapIndex, string actionName)
96+
{
97+
return (in InputActionsEditorState state) =>
98+
{
99+
var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
100+
var action = Selectors.GetActionInMap(state, actionMapIndex, actionName).wrappedProperty;
101+
var actionIndex = action.GetIndexOfArrayElement();
102+
var actionID = InputActionSerializationHelpers.GetId(action);
103+
InputActionSerializationHelpers.DeleteActionAndBindings(actionMap, actionID);
104+
state.serializedObject.ApplyModifiedProperties();
105+
if (state.selectedActionIndex >= actionIndex)
106+
return SelectPrevAction(state, actionMap);
107+
return state.SelectAction(state.selectedActionIndex);
108+
};
109+
}
110+
111+
private static InputActionsEditorState SelectPrevAction(InputActionsEditorState state, SerializedProperty actionMap)
112+
{
113+
var count = Selectors.GetActionCount(actionMap);
114+
int index = -1;
115+
if (count != null && count.Value > 0)
116+
index = Math.Max(state.selectedActionIndex - 1, 0);
117+
return state.SelectAction(index);
118+
}
119+
120+
public static Command DeleteBinding(int actionMapIndex, int bindingIndex)
121+
{
122+
return (in InputActionsEditorState state) =>
123+
{
124+
var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
125+
var binding = Selectors.GetCompositeOrBindingInMap(actionMap, bindingIndex).wrappedProperty;
126+
InputActionSerializationHelpers.DeleteBinding(binding, actionMap);
127+
state.serializedObject.ApplyModifiedProperties();
128+
if (state.selectedBindingIndex >= bindingIndex)
129+
return SelectPrevBinding(state, actionMap);
130+
return state.SelectBinding(state.selectedBindingIndex);
131+
};
132+
}
133+
134+
private static InputActionsEditorState SelectPrevBinding(InputActionsEditorState state, SerializedProperty actionMap)
135+
{
136+
var count = Selectors.GetBindingCount(actionMap);
137+
var index = -1;
138+
if (count != null && count.Value > 0)
139+
index = Math.Max(state.selectedBindingIndex - 1, 0);
140+
return state.SelectBinding(index);
141+
}
142+
61143
public static Command ExpandCompositeBinding(SerializedInputBinding binding)
62144
{
63145
return (in InputActionsEditorState state) => state.ExpandCompositeBinding(binding);
@@ -188,16 +270,40 @@ public static Command ToggleAutoSave(bool newValue)
188270
};
189271
}
190272

191-
public static Command ChangeActionMapName(string newName)
273+
public static Command ChangeActionMapName(int index, string newName)
192274
{
193275
return (in InputActionsEditorState state) =>
194276
{
195-
var actionMap = Selectors.GetSelectedActionMap(state).wrappedProperty;
277+
var actionMap = Selectors.GetActionMapAtIndex(state, index)?.wrappedProperty;
196278
InputActionSerializationHelpers.RenameActionMap(actionMap, newName);
197279
state.serializedObject.ApplyModifiedProperties();
198280
return state;
199281
};
200282
}
283+
284+
public static Command ChangeActionName(int actionMapIndex, string oldName, string newName)
285+
{
286+
return (in InputActionsEditorState state) =>
287+
{
288+
var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
289+
var action = Selectors.GetActionInMap(state, actionMapIndex, oldName).wrappedProperty;
290+
InputActionSerializationHelpers.RenameAction(action, actionMap, newName);
291+
state.serializedObject.ApplyModifiedProperties();
292+
return state;
293+
};
294+
}
295+
296+
public static Command ChangeCompositeName(int actionMapIndex, int bindingIndex, string newName)
297+
{
298+
return (in InputActionsEditorState state) =>
299+
{
300+
var actionMap = Selectors.GetActionMapAtIndex(state, actionMapIndex)?.wrappedProperty;
301+
var binding = Selectors.GetCompositeOrBindingInMap(actionMap, bindingIndex).wrappedProperty;
302+
InputActionSerializationHelpers.RenameComposite(binding, newName);
303+
state.serializedObject.ApplyModifiedProperties();
304+
return state;
305+
};
306+
}
201307
}
202308
}
203309

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/InputActionsEditorState.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,9 @@ public InputActionsEditorState SelectAction(SerializedProperty state)
158158
return With(selectedActionIndex: index, selectionType: SelectionType.Action);
159159
}
160160

161-
public InputActionsEditorState SelectActionMap(SerializedProperty state)
161+
public InputActionsEditorState SelectActionMap(SerializedProperty actionMap)
162162
{
163-
var index = state.GetIndexOfArrayElement();
163+
var index = actionMap.GetIndexOfArrayElement();
164164
return With(selectedBindingIndex: 0, selectedActionMapIndex: index, selectedActionIndex: 0);
165165
}
166166

@@ -169,14 +169,34 @@ public InputActionsEditorState SelectActionMap(string actionMapName)
169169
var actionMap = GetActionMapByName(actionMapName);
170170
return With(selectedBindingIndex: 0,
171171
selectedActionMapIndex: actionMap.GetIndexOfArrayElement(),
172-
selectedActionIndex: 0);
172+
selectedActionIndex: 0, selectionType: SelectionType.Action);
173173
}
174174

175175
public InputActionsEditorState SelectBinding(int index)
176176
{
177+
//if no binding selected (due to no bindings in list) set selection type to action
178+
if (index == -1)
179+
return With(selectedBindingIndex: index, selectionType: SelectionType.Action);
177180
return With(selectedBindingIndex: index);
178181
}
179182

183+
public InputActionsEditorState SelectAction(int index)
184+
{
185+
//if no action selected (no actions available) set selection type to none
186+
if (index == -1)
187+
return With(selectedActionIndex: index, selectionType: SelectionType.None);
188+
return With(selectedActionIndex: index);
189+
}
190+
191+
public InputActionsEditorState SelectActionMap(int index)
192+
{
193+
if (index == -1)
194+
return With(selectedActionMapIndex: index, selectionType: SelectionType.None);
195+
return With(selectedBindingIndex: 0,
196+
selectedActionMapIndex: index,
197+
selectedActionIndex: 0, selectionType: SelectionType.Action);
198+
}
199+
180200
public ReadOnlyCollection<int> GetOrCreateExpandedState()
181201
{
182202
return new ReadOnlyCollection<int>(GetOrCreateExpandedStateInternal().ToList());
@@ -226,6 +246,7 @@ private SerializedProperty GetSelectedActionMap()
226246

227247
internal enum SelectionType
228248
{
249+
None,
229250
Action,
230251
Binding
231252
}

Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/ActionMapsView.cs

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,30 @@ public ActionMapsView(VisualElement root, StateContainer stateContainer)
2424
{
2525
var treeViewItem = (InputActionsTreeViewItem)element;
2626
treeViewItem.label.text = (string)m_ListView.itemsSource[i];
27-
treeViewItem.EditTextFinished += ChangeActionMapName;
27+
treeViewItem.EditTextFinishedCallback = newName => ChangeActionMapName(i, newName);
28+
treeViewItem.EditTextFinished += treeViewItem.EditTextFinishedCallback;
29+
treeViewItem.DeleteCallback = _ => DeleteActionMap(i);
30+
treeViewItem.OnDeleteItem += treeViewItem.DeleteCallback;
31+
32+
ContextMenu.GetContextMenuForActionMapItem(treeViewItem, m_ListView);
2833
};
2934
m_ListView.makeItem = () => new InputActionsTreeViewItem();
3035
m_ListView.unbindItem = (element, i) =>
3136
{
32-
((InputActionsTreeViewItem)element).EditTextFinished -= ChangeActionMapName;
37+
var treeViewElement = (InputActionsTreeViewItem)element;
38+
treeViewElement.Reset();
39+
treeViewElement.OnDeleteItem -= treeViewElement.DeleteCallback;
40+
treeViewElement.EditTextFinished -= treeViewElement.EditTextFinishedCallback;
41+
};
42+
43+
m_ListView.itemsChosen += objects =>
44+
{
45+
var item = m_ListView.GetRootElementForIndex(m_ListView.selectedIndex).Q<InputActionsTreeViewItem>();
46+
item.FocusOnRenameTextField();
3347
};
3448

49+
m_ListView.RegisterCallback<KeyDownEvent>(OnKeyDownEvent);
50+
3551
CreateSelector(s => new ViewStateCollection<string>(Selectors.GetActionMapNames(s)),
3652
(actionMapNames, state) => new ViewState(Selectors.GetSelectedActionMap(state), actionMapNames));
3753

@@ -43,19 +59,38 @@ public ActionMapsView(VisualElement root, StateContainer stateContainer)
4359
public override void RedrawUI(ViewState viewState)
4460
{
4561
m_ListView.itemsSource = viewState.actionMapNames?.ToList() ?? new List<string>();
46-
var indexOf = viewState.actionMapNames.IndexOf(viewState.selectedActionMap.name);
47-
m_ListView.SetSelection(indexOf);
62+
if (viewState.selectedActionMap.HasValue)
63+
{
64+
var indexOf = viewState.actionMapNames.IndexOf(viewState.selectedActionMap.Value.name);
65+
m_ListView.SetSelection(indexOf);
66+
}
4867
m_ListView.Rebuild();
68+
RenameNewActionMaps();
4969
}
5070

5171
public override void DestroyView()
5272
{
5373
addActionMapButton.clicked -= AddActionMap;
5474
}
5575

56-
private void ChangeActionMapName(string newName)
76+
private void RenameNewActionMaps()
77+
{
78+
if (!m_EnterRenamingMode)
79+
return;
80+
m_ListView.ScrollToItem(m_ListView.selectedIndex);
81+
var element = m_ListView.GetRootElementForIndex(m_ListView.selectedIndex);
82+
((InputActionsTreeViewItem)element).FocusOnRenameTextField();
83+
m_EnterRenamingMode = false;
84+
}
85+
86+
private void DeleteActionMap(int index)
87+
{
88+
Dispatch(Commands.DeleteActionMap(index));
89+
}
90+
91+
private void ChangeActionMapName(int index, string newName)
5792
{
58-
Dispatch(Commands.ChangeActionMapName(newName));
93+
Dispatch(Commands.ChangeActionMapName(index, newName));
5994
}
6095

6196
private void SelectActionMap()
@@ -66,17 +101,39 @@ private void SelectActionMap()
66101
private void AddActionMap()
67102
{
68103
Dispatch(Commands.AddActionMap());
104+
m_EnterRenamingMode = true;
105+
}
106+
107+
private void OnKeyDownEvent(KeyDownEvent e)
108+
{
109+
if (e.keyCode == KeyCode.F2)
110+
OnKeyDownEventForRename();
111+
else if (e.keyCode == KeyCode.Delete)
112+
OnKeyDownEventForDelete();
113+
}
114+
115+
private void OnKeyDownEventForRename()
116+
{
117+
var item = (InputActionsTreeViewItem)m_ListView.GetRootElementForIndex(m_ListView.selectedIndex);
118+
item.FocusOnRenameTextField();
119+
}
120+
121+
private void OnKeyDownEventForDelete()
122+
{
123+
var item = (InputActionsTreeViewItem)m_ListView.GetRootElementForIndex(m_ListView.selectedIndex);
124+
item.DeleteItem();
69125
}
70126

127+
private bool m_EnterRenamingMode;
71128
private readonly VisualElement m_Root;
72129
private ListView m_ListView;
73130

74131
internal class ViewState
75132
{
76-
public SerializedInputActionMap selectedActionMap;
133+
public SerializedInputActionMap? selectedActionMap;
77134
public IEnumerable<string> actionMapNames;
78135

79-
public ViewState(SerializedInputActionMap selectedActionMap, IEnumerable<string> actionMapNames)
136+
public ViewState(SerializedInputActionMap? selectedActionMap, IEnumerable<string> actionMapNames)
80137
{
81138
this.selectedActionMap = selectedActionMap;
82139
this.actionMapNames = actionMapNames;

0 commit comments

Comments
 (0)