A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS 2using System; 3using System.ComponentModel; 4using System.Linq; 5using System.Reflection; 6using UnityEditor; 7using UnityEngine.InputSystem.Layouts; 8using UnityEngine.InputSystem.Utilities; 9using UnityEngine.UIElements; 10 11namespace UnityEngine.InputSystem.Editor 12{ 13 internal static class ContextMenu 14 { 15 private static readonly string copy_String = "Copy"; 16 private static readonly string cut_String = "Cut"; 17 private static readonly string paste_String = "Paste"; 18 19 private static readonly string rename_String = "Rename"; 20 private static readonly string duplicate_String = "Duplicate"; 21 private static readonly string delete_String = "Delete"; 22 23 private static readonly string add_Action_Map_String = "Add Action Map"; 24 private static readonly string add_Action_String = "Add Action"; 25 private static readonly string add_Binding_String = "Add Binding"; 26 27 #region ActionMaps 28 public static void GetContextMenuForActionMapItem(ActionMapsView mapView, InputActionMapsTreeViewItem treeViewItem, int index) 29 { 30 treeViewItem.OnContextualMenuPopulateEvent = (menuEvent => 31 { 32 // TODO: AddAction should enable m_RenameOnActionAdded 33 menuEvent.menu.AppendAction(add_Action_String, _ => mapView.Dispatch(Commands.AddAction())); 34 menuEvent.menu.AppendSeparator(); 35 menuEvent.menu.AppendAction(rename_String, _ => mapView.RenameActionMap(index)); 36 menuEvent.menu.AppendAction(duplicate_String, _ => mapView.DuplicateActionMap(index)); 37 menuEvent.menu.AppendAction(delete_String, _ => mapView.DeleteActionMap(index)); 38 menuEvent.menu.AppendSeparator(); 39 menuEvent.menu.AppendAction(copy_String, _ => mapView.CopyItems()); 40 menuEvent.menu.AppendAction(cut_String, _ => mapView.CutItems()); 41 42 var copiedAction = CopyPasteHelper.GetCopiedClipboardType() == typeof(InputAction); 43 if (CopyPasteHelper.HasPastableClipboardData(typeof(InputActionMap))) 44 menuEvent.menu.AppendAction(paste_String, _ => mapView.PasteItems(copiedAction)); 45 }); 46 } 47 48 // Add "Add Action Map" option to empty space under the ListView. Matches with old IMGUI style (ISX-1519). 49 // Include Paste here as well, since it makes sense for adding ActionMaps. 50 public static void GetContextMenuForActionMapsEmptySpace(ActionMapsView mapView, VisualElement element, bool onlyShowIfListIsEmpty = false) 51 { 52 _ = new ContextualMenuManipulator(menuEvent => 53 { 54 if (!onlyShowIfListIsEmpty || mapView.GetMapCount() == 0) 55 { 56 var copiedAction = CopyPasteHelper.GetCopiedClipboardType() == typeof(InputAction); 57 if (CopyPasteHelper.HasPastableClipboardData(typeof(InputActionMap))) 58 menuEvent.menu.AppendAction(paste_String, _ => mapView.PasteItems(copiedAction)); 59 60 menuEvent.menu.AppendSeparator(); 61 menuEvent.menu.AppendAction(add_Action_Map_String, _ => mapView.AddActionMap()); 62 } 63 }) { target = element }; 64 } 65 66 #endregion 67 68 #region Actions 69 // Add the "Paste" option to all elements in the Action area. 70 public static void GetContextMenuForActionListView(ActionsTreeView actionsTreeView, TreeView treeView, VisualElement target) 71 { 72 _ = new ContextualMenuManipulator(menuEvent => 73 { 74 var item = treeView.GetItemDataForIndex<ActionOrBindingData>(treeView.selectedIndex); 75 var hasPastableData = CopyPasteHelper.HasPastableClipboardData(item.isAction ? typeof(InputAction) : typeof(InputBinding)); 76 if (hasPastableData) 77 menuEvent.menu.AppendAction(paste_String, _ => actionsTreeView.PasteItems()); 78 }) { target = target }; 79 } 80 81 // Add "Add Action" option to empty space under the TreeView. Matches with old IMGUI style (ISX-1519). 82 // Include Paste here as well, since it makes sense for Actions; thus users would expect it for Bindings too. 83 public static void GetContextMenuForActionsEmptySpace(ActionsTreeView actionsTreeView, TreeView treeView, VisualElement target, bool onlyShowIfTreeIsEmpty = false) 84 { 85 _ = new ContextualMenuManipulator(menuEvent => 86 { 87 if (actionsTreeView.GetMapCount() > 0 && (!onlyShowIfTreeIsEmpty || treeView.GetTreeCount() == 0)) 88 { 89 var item = treeView.GetItemDataForIndex<ActionOrBindingData>(treeView.selectedIndex); 90 if (CopyPasteHelper.HasPastableClipboardData(item.isAction ? typeof(InputAction) : typeof(InputBinding))) 91 menuEvent.menu.AppendAction(paste_String, _ => actionsTreeView.PasteItems()); 92 93 menuEvent.menu.AppendSeparator(); 94 menuEvent.menu.AppendAction(add_Action_String, _ => actionsTreeView.AddAction()); 95 } 96 }) { target = target }; 97 } 98 99 public static void GetContextMenuForActionItem(ActionsTreeView treeView, InputActionsTreeViewItem treeViewItem, string controlLayout, int index) 100 { 101 _ = new ContextualMenuManipulator(menuEvent => 102 { 103 menuEvent.menu.AppendAction(add_Binding_String, _ => treeView.AddBinding(index)); 104 AppendCompositeMenuItems(treeView, controlLayout, index, (name, action) => menuEvent.menu.AppendAction(name, _ => action.Invoke())); 105 menuEvent.menu.AppendSeparator(); 106 AppendRenameAction(menuEvent, treeView, index); 107 AppendDuplicateDeleteCutAndCopyActionsSection(menuEvent, treeView, index); 108 }) { target = treeViewItem }; 109 } 110 111 public static Action GetContextMenuForActionAddItem(ActionsTreeView treeView, string controlLayout, int index) 112 { 113 return () => 114 { 115 GenericMenu menu = new GenericMenu(); 116 menu.AddItem(new GUIContent(add_Binding_String), false, () => treeView.AddBinding(index)); 117 AppendCompositeMenuItems(treeView, controlLayout, index, (name, action) => menu.AddItem(new GUIContent(name), false, action.Invoke)); 118 menu.ShowAsContext(); 119 }; 120 } 121 122 private static void AppendCompositeMenuItems(ActionsTreeView treeView, string expectedControlLayout, int index, Action<string, Action> addToMenuAction) 123 { 124 foreach (var compositeName in InputBindingComposite.s_Composites.internedNames.Where(x => 125 !InputBindingComposite.s_Composites.aliases.Contains(x)).OrderBy(x => x)) 126 { 127 // Skip composites we should hide 128 var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(compositeName); 129 var designTimeVisible = compositeType.GetCustomAttribute<DesignTimeVisibleAttribute>(); 130 if (designTimeVisible != null && !designTimeVisible.Visible) 131 continue; 132 133 // Skip composites that don't match the expected control layout 134 // NOTE: "Any" is a special case and expected to be null 135 if (!string.IsNullOrEmpty(expectedControlLayout)) 136 { 137 var valueType = InputBindingComposite.GetValueType(compositeName); 138 if (valueType != null && 139 !InputControlLayout.s_Layouts.ValueTypeIsAssignableFrom( 140 new InternedString(expectedControlLayout), valueType)) 141 continue; 142 } 143 144 var displayName = compositeType.GetCustomAttribute<DisplayNameAttribute>(); 145 var niceName = displayName != null ? displayName.DisplayName.Replace('/', '\\') : ObjectNames.NicifyVariableName(compositeName) + " Composite"; 146 addToMenuAction.Invoke($"Add {niceName}", () => treeView.AddComposite(index, compositeName)); 147 } 148 } 149 150 public static void GetContextMenuForCompositeItem(ActionsTreeView treeView, InputActionsTreeViewItem treeViewItem, int index) 151 { 152 _ = new ContextualMenuManipulator(menuEvent => 153 { 154 AppendRenameAction(menuEvent, treeView, index); 155 AppendDuplicateDeleteCutAndCopyActionsSection(menuEvent, treeView, index); 156 }) { target = treeViewItem }; 157 } 158 159 public static void GetContextMenuForBindingItem(ActionsTreeView treeView, InputActionsTreeViewItem treeViewItem, int index) 160 { 161 _ = new ContextualMenuManipulator(menuEvent => 162 { 163 AppendDuplicateDeleteCutAndCopyActionsSection(menuEvent, treeView, index); 164 }) { target = treeViewItem }; 165 } 166 167 private static void AppendRenameAction(ContextualMenuPopulateEvent menuEvent, ActionsTreeView treeView, int index) 168 { 169 menuEvent.menu.AppendAction(rename_String, _ => treeView.RenameActionItem(index)); 170 } 171 172 // These actions are always either all present, or all missing, so we can group their Append calls here. 173 private static void AppendDuplicateDeleteCutAndCopyActionsSection(ContextualMenuPopulateEvent menuEvent, ActionsTreeView actionsTreeView, int index) 174 { 175 menuEvent.menu.AppendAction(duplicate_String, _ => actionsTreeView.DuplicateItem(index)); 176 menuEvent.menu.AppendAction(delete_String, _ => actionsTreeView.DeleteItem(index)); 177 menuEvent.menu.AppendSeparator(); 178 menuEvent.menu.AppendAction(copy_String, _ => actionsTreeView.CopyItems()); 179 menuEvent.menu.AppendAction(cut_String, _ => actionsTreeView.CutItems()); 180 } 181 182 #endregion 183 } 184} 185#endif