A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS 2using CmdEvents = UnityEngine.InputSystem.Editor.InputActionsEditorConstants.CommandEvents; 3using System.Collections.Generic; 4using System.Linq; 5using UnityEngine.UIElements; 6 7namespace UnityEngine.InputSystem.Editor 8{ 9 /// <summary> 10 /// A list view to display the action maps of the currently opened input actions asset. 11 /// </summary> 12 internal class ActionMapsView : ViewBase<ActionMapsView.ViewState> 13 { 14 public ActionMapsView(VisualElement root, StateContainer stateContainer) 15 : base(root, stateContainer) 16 { 17 m_ListView = root.Q<ListView>("action-maps-list-view"); 18 m_ListView.selectionType = UIElements.SelectionType.Single; 19 m_ListView.reorderable = true; 20 m_ListViewSelectionChangeFilter = new CollectionViewSelectionChangeFilter(m_ListView); 21 m_ListViewSelectionChangeFilter.selectedIndicesChanged += (selectedIndices) => 22 { 23 Dispatch(Commands.SelectActionMap(((ActionMapData)m_ListView.selectedItem).mapName)); 24 }; 25 26 m_ListView.bindItem = (element, i) => 27 { 28 var treeViewItem = (InputActionMapsTreeViewItem)element; 29 var mapData = (ActionMapData)m_ListView.itemsSource[i]; 30 treeViewItem.label.text = mapData.mapName; 31 treeViewItem.EditTextFinishedCallback = newName => ChangeActionMapName(i, newName); 32 treeViewItem.EditTextFinished += treeViewItem.EditTextFinishedCallback; 33 treeViewItem.userData = i; 34 element.SetEnabled(!mapData.isDisabled); 35 36 ContextMenu.GetContextMenuForActionMapItem(this, treeViewItem, i); 37 }; 38 m_ListView.makeItem = () => new InputActionMapsTreeViewItem(); 39 m_ListView.unbindItem = (element, i) => 40 { 41 var treeViewElement = (InputActionMapsTreeViewItem)element; 42 treeViewElement.Reset(); 43 treeViewElement.EditTextFinished -= treeViewElement.EditTextFinishedCallback; 44 }; 45 46 m_ListView.itemsChosen += objects => 47 { 48 var item = m_ListView.GetRootElementForIndex(m_ListView.selectedIndex).Q<InputActionMapsTreeViewItem>(); 49 item.FocusOnRenameTextField(); 50 }; 51 52 m_ListView.RegisterCallback<ExecuteCommandEvent>(OnExecuteCommand); 53 m_ListView.RegisterCallback<ValidateCommandEvent>(OnValidateCommand); 54 m_ListView.RegisterCallback<PointerDownEvent>(OnPointerDown, TrickleDown.TrickleDown); 55 56 // ISXB-748 - Scrolling the view causes a visual glitch with the rename TextField. As a work-around we 57 // need to cancel the rename operation in this scenario. 58 m_ListView.RegisterCallback<WheelEvent>(e => InputActionMapsTreeViewItem.CancelRename(), TrickleDown.TrickleDown); 59 60 var treeView = root.Q<TreeView>("actions-tree-view"); 61 m_ListView.AddManipulator(new DropManipulator(OnDroppedHandler, treeView)); 62 m_ListView.itemIndexChanged += OnReorder; 63 64 CreateSelector(Selectors.GetActionMapNames, Selectors.GetSelectedActionMap, (actionMapNames, actionMap, state) => new ViewState(actionMap, actionMapNames, state.GetDisabledActionMaps(actionMapNames.ToList()))); 65 66 m_AddActionMapButton = root.Q<Button>("add-new-action-map-button"); 67 m_AddActionMapButton.clicked += AddActionMap; 68 69 ContextMenu.GetContextMenuForActionMapsEmptySpace(this, root.Q<VisualElement>("rclick-area-to-add-new-action-map")); 70 // Only bring up this context menu for the List when it's empty, so we can treat it like right-clicking the empty space: 71 ContextMenu.GetContextMenuForActionMapsEmptySpace(this, m_ListView, onlyShowIfListIsEmpty: true); 72 } 73 74 void OnDroppedHandler(int mapIndex) 75 { 76 Dispatch(Commands.PasteActionIntoActionMap(mapIndex)); 77 } 78 79 void OnReorder(int oldIndex, int newIndex) 80 { 81 Dispatch(Commands.ReorderActionMap(oldIndex, newIndex)); 82 } 83 84 public override void RedrawUI(ViewState viewState) 85 { 86 m_ListView.itemsSource = viewState.actionMapData?.ToList() ?? new List<ActionMapData>(); 87 if (viewState.selectedActionMap.HasValue) 88 { 89 var actionMapData = viewState.actionMapData?.Find(map => map.mapName.Equals(viewState.selectedActionMap.Value.name)); 90 if (actionMapData.HasValue) 91 m_ListView.SetSelection(viewState.actionMapData.IndexOf(actionMapData.Value)); 92 } 93 m_ListView.RefreshItems(); 94 RenameNewActionMaps(); 95 } 96 97 public override void DestroyView() 98 { 99 m_AddActionMapButton.clicked -= AddActionMap; 100 } 101 102 private void RenameNewActionMaps() 103 { 104 if (!m_EnterRenamingMode) 105 return; 106 m_ListView.ScrollToItem(m_ListView.selectedIndex); 107 var element = m_ListView.GetRootElementForIndex(m_ListView.selectedIndex); 108 if (element == null) 109 return; 110 ((InputActionMapsTreeViewItem)element).FocusOnRenameTextField(); 111 } 112 113 internal void RenameActionMap(int index) 114 { 115 m_ListView.ScrollToItem(index); 116 var element = m_ListView.GetRootElementForIndex(index); 117 if (element == null) 118 return; 119 ((InputActionMapsTreeViewItem)element).FocusOnRenameTextField(); 120 } 121 122 internal void DeleteActionMap(int index) 123 { 124 Dispatch(Commands.DeleteActionMap(index)); 125 } 126 127 internal void DuplicateActionMap(int index) 128 { 129 Dispatch(Commands.DuplicateActionMap(index)); 130 } 131 132 internal void CopyItems() 133 { 134 Dispatch(Commands.CopyActionMapSelection()); 135 } 136 137 internal void CutItems() 138 { 139 Dispatch(Commands.CutActionMapSelection()); 140 } 141 142 internal void PasteItems(bool copiedAction) 143 { 144 Dispatch(copiedAction ? Commands.PasteActionFromActionMap(InputActionsEditorView.s_OnPasteCutElements) : Commands.PasteActionMaps(InputActionsEditorView.s_OnPasteCutElements)); 145 } 146 147 private void ChangeActionMapName(int index, string newName) 148 { 149 m_EnterRenamingMode = false; 150 Dispatch(Commands.ChangeActionMapName(index, newName)); 151 } 152 153 internal void AddActionMap() 154 { 155 Dispatch(Commands.AddActionMap()); 156 m_EnterRenamingMode = true; 157 } 158 159 internal int GetMapCount() 160 { 161 return m_ListView.itemsSource.Count; 162 } 163 164 private void OnExecuteCommand(ExecuteCommandEvent evt) 165 { 166 var selectedItem = m_ListView.GetRootElementForIndex(m_ListView.selectedIndex); 167 if (selectedItem == null) 168 return; 169 170 if (allowUICommandExecution) 171 { 172 switch (evt.commandName) 173 { 174 case CmdEvents.Rename: 175 ((InputActionMapsTreeViewItem)selectedItem).FocusOnRenameTextField(); 176 break; 177 case CmdEvents.Delete: 178 case CmdEvents.SoftDelete: 179 DeleteActionMap(m_ListView.selectedIndex); 180 break; 181 case CmdEvents.Duplicate: 182 DuplicateActionMap(m_ListView.selectedIndex); 183 break; 184 case CmdEvents.Copy: 185 CopyItems(); 186 break; 187 case CmdEvents.Cut: 188 CutItems(); 189 break; 190 case CmdEvents.Paste: 191 var isActionCopied = CopyPasteHelper.GetCopiedClipboardType() == typeof(InputAction); 192 if (CopyPasteHelper.HasPastableClipboardData(typeof(InputActionMap))) 193 PasteItems(isActionCopied); 194 break; 195 default: 196 return; // Skip StopPropagation if we didn't execute anything 197 } 198 199 // Prevent any UI commands from executing until after UI has been updated 200 allowUICommandExecution = false; 201 } 202 evt.StopPropagation(); 203 } 204 205 private void OnValidateCommand(ValidateCommandEvent evt) 206 { 207 // Mark commands as supported for Execute by stopping propagation of the event 208 switch (evt.commandName) 209 { 210 case CmdEvents.Rename: 211 case CmdEvents.Delete: 212 case CmdEvents.SoftDelete: 213 case CmdEvents.Duplicate: 214 case CmdEvents.Copy: 215 case CmdEvents.Cut: 216 case CmdEvents.Paste: 217 evt.StopPropagation(); 218 break; 219 } 220 } 221 222 private void OnPointerDown(PointerDownEvent evt) 223 { 224 // Allow right clicks to select an item before we bring up the matching context menu. 225 if (evt.button == (int)MouseButton.RightMouse && evt.clickCount == 1) 226 { 227 var actionMap = (evt.target as VisualElement).GetFirstAncestorOfType<InputActionMapsTreeViewItem>(); 228 if (actionMap != null) 229 m_ListView.SetSelection(actionMap.parent.IndexOf(actionMap)); 230 } 231 } 232 233 private readonly CollectionViewSelectionChangeFilter m_ListViewSelectionChangeFilter; 234 private bool m_EnterRenamingMode; 235 private readonly ListView m_ListView; 236 private readonly Button m_AddActionMapButton; 237 238 internal struct ActionMapData 239 { 240 internal string mapName; 241 internal bool isDisabled; 242 243 public ActionMapData(string mapName, bool isDisabled) 244 { 245 this.mapName = mapName; 246 this.isDisabled = isDisabled; 247 } 248 } 249 250 internal class ViewState 251 { 252 public SerializedInputActionMap? selectedActionMap; 253 public List<ActionMapData> actionMapData; 254 255 public ViewState(SerializedInputActionMap? selectedActionMap, IEnumerable<string> actionMapNames, IEnumerable<string> disabledActionMapNames) 256 { 257 this.selectedActionMap = selectedActionMap; 258 actionMapData = new List<ActionMapData>(); 259 foreach (var name in actionMapNames) 260 { 261 actionMapData.Add(new ActionMapData(name, disabledActionMapNames.Contains(name))); 262 } 263 } 264 } 265 } 266} 267 268#endif