A game about forced loneliness, made by TACStudios
1#if UNITY_EDITOR && UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS 2using System; 3using System.Linq; 4using UnityEditor; 5using UnityEngine.UIElements; 6 7namespace UnityEngine.InputSystem.Editor 8{ 9 internal class PropertiesView : ViewBase<PropertiesView.ViewState> 10 { 11 private ActionPropertiesView m_ActionPropertyView; 12 private BindingPropertiesView m_BindingPropertyView; 13 private NameAndParametersListView m_InteractionsListView; 14 private NameAndParametersListView m_ProcessorsListView; 15 16 private Foldout interactionsFoldout => rootElement.Q<Foldout>("interactions-foldout"); 17 private Foldout processorsFoldout => rootElement.Q<Foldout>("processors-foldout"); 18 19 private TextElement addInteractionButton; 20 private TextElement addProcessorButton; 21 22 public PropertiesView(VisualElement root, StateContainer stateContainer) 23 : base(root, stateContainer) 24 { 25 CreateSelector( 26 Selectors.GetSelectedAction, 27 Selectors.GetSelectedBinding, 28 state => state.selectionType, 29 (inputAction, inputBinding, selectionType, s) => new ViewState() 30 { 31 selectionType = selectionType, 32 serializedInputAction = inputAction, 33 inputBinding = inputBinding, 34 relatedInputAction = Selectors.GetRelatedInputAction(s) 35 }); 36 37 var interactionsToggle = interactionsFoldout.Q<Toggle>(); 38 interactionsToggle.AddToClassList("properties-foldout-toggle"); 39 if (addInteractionButton == null) 40 { 41 addInteractionButton = CreateAddButton(interactionsToggle, "add-new-interaction-button"); 42 new ContextualMenuManipulator(_ => {}){target = addInteractionButton, activators = {new ManipulatorActivationFilter(){button = MouseButton.LeftMouse}}}; 43 } 44 var processorToggle = processorsFoldout.Q<Toggle>(); 45 processorToggle.AddToClassList("properties-foldout-toggle"); 46 if (addProcessorButton == null) 47 { 48 addProcessorButton = CreateAddButton(processorToggle, "add-new-processor-button"); 49 new ContextualMenuManipulator(_ => {}){target = addProcessorButton, activators = {new ManipulatorActivationFilter(){button = MouseButton.LeftMouse}}}; 50 } 51 } 52 53 private TextElement CreateAddButton(Toggle toggle, string name) 54 { 55 var addButton = new Button(); 56 addButton.text = "+"; 57 addButton.name = name; 58 addButton.focusable = false; 59 #if UNITY_EDITOR_OSX 60 addButton.clickable.activators.Clear(); 61 #endif 62 addButton.AddToClassList("add-interaction-processor-button"); 63 toggle.Add(addButton); 64 return addButton; 65 } 66 67 private void CreateContextMenuProcessor(string expectedControlType) 68 { 69 var processors = InputProcessor.s_Processors; 70 Type expectedValueType = string.IsNullOrEmpty(expectedControlType) ? null : EditorInputControlLayoutCache.GetValueType(expectedControlType); 71 addProcessorButton.RegisterCallback<ContextualMenuPopulateEvent>(evt => 72 { 73 evt.menu.ClearItems(); 74 foreach (var name in processors.internedNames.Where(x => !processors.ShouldHideInUI(x)).OrderBy(x => x.ToString())) 75 { 76 // Skip if not compatible with value type. 77 if (!IsValidProcessorForControl(expectedValueType, name)) 78 continue; 79 var niceName = ObjectNames.NicifyVariableName(name); 80 evt.menu.AppendAction(niceName, _ => m_ProcessorsListView.OnAddElement(name.ToString())); 81 } 82 }); 83 } 84 85 private bool IsValidProcessorForControl(Type expectedValueType, string name) 86 { 87 if (expectedValueType == null) return true; 88 var type = InputProcessor.s_Processors.LookupTypeRegistration(name); 89 var valueType = InputProcessor.GetValueTypeFromType(type); 90 if (valueType != null && !expectedValueType.IsAssignableFrom(valueType)) 91 return false; 92 return true; 93 } 94 95 private void CreateContextMenuInteraction(string expectedControlType) 96 { 97 var interactions = InputInteraction.s_Interactions; 98 Type expectedValueType = string.IsNullOrEmpty(expectedControlType) ? null : EditorInputControlLayoutCache.GetValueType(expectedControlType); 99 addInteractionButton.RegisterCallback<ContextualMenuPopulateEvent>(evt => 100 { 101 evt.menu.ClearItems(); 102 foreach (var name in interactions.internedNames.Where(x => !interactions.ShouldHideInUI(x)).OrderBy(x => x.ToString())) 103 { 104 // Skip if not compatible with value type. 105 if (!IsValidInteractionForControl(expectedValueType, name)) 106 continue; 107 var niceName = ObjectNames.NicifyVariableName(name); 108 evt.menu.AppendAction(niceName, _ => m_InteractionsListView.OnAddElement(name.ToString())); 109 } 110 }); 111 } 112 113 private bool IsValidInteractionForControl(Type expectedValueType, string name) 114 { 115 if (expectedValueType == null) return true; 116 var type = InputInteraction.s_Interactions.LookupTypeRegistration(name); 117 var valueType = InputInteraction.GetValueType(type); 118 if (valueType != null && !expectedValueType.IsAssignableFrom(valueType)) 119 return false; 120 return true; 121 } 122 123 public override void RedrawUI(ViewState viewState) 124 { 125 DestroyChildView(m_ActionPropertyView); 126 DestroyChildView(m_BindingPropertyView); 127 DestroyChildView(m_InteractionsListView); 128 DestroyChildView(m_ProcessorsListView); 129 130 var propertiesContainer = rootElement.Q<VisualElement>("properties-container"); 131 132 var foldout = propertiesContainer.Q<Foldout>("properties-foldout"); 133 foldout.Clear(); 134 135 var visualElement = new VisualElement(); 136 foldout.Add(visualElement); 137 foldout.Q<Toggle>().AddToClassList("properties-foldout-toggle"); 138 139 var inputAction = viewState.serializedInputAction; 140 var inputActionOrBinding = inputAction?.wrappedProperty; 141 142 switch (viewState.selectionType) 143 { 144 case SelectionType.Action: 145 rootElement.Q<Label>("properties-header-label").text = "Action Properties"; 146 m_ActionPropertyView = CreateChildView(new ActionPropertiesView(visualElement, foldout, stateContainer)); 147 break; 148 149 case SelectionType.Binding: 150 rootElement.Q<Label>("properties-header-label").text = "Binding Properties"; 151 m_BindingPropertyView = CreateChildView(new BindingPropertiesView(visualElement, foldout, stateContainer)); 152 inputAction = viewState.relatedInputAction; 153 inputActionOrBinding = viewState.inputBinding?.wrappedProperty; 154 break; 155 } 156 157 CreateContextMenuProcessor(inputAction?.expectedControlType); 158 CreateContextMenuInteraction(inputAction?.expectedControlType); 159 160 var isPartOfComposite = viewState.selectionType == SelectionType.Binding && 161 viewState.inputBinding?.isPartOfComposite == true; 162 //don't show for Bindings in Composites 163 if (!isPartOfComposite) 164 { 165 interactionsFoldout.style.display = DisplayStyle.Flex; 166 m_InteractionsListView = CreateChildView(new NameAndParametersListView( 167 interactionsFoldout, 168 stateContainer, 169 inputActionOrBinding?.FindPropertyRelative(nameof(InputAction.m_Interactions)), 170 state => Selectors.GetInteractionsAsParameterListViews(state, inputAction))); 171 } 172 else 173 interactionsFoldout.style.display = DisplayStyle.None; 174 175 176 m_ProcessorsListView = CreateChildView(new NameAndParametersListView( 177 processorsFoldout, 178 stateContainer, 179 inputActionOrBinding?.FindPropertyRelative(nameof(InputAction.m_Processors)), 180 state => Selectors.GetProcessorsAsParameterListViews(state, inputAction))); 181 } 182 183 internal class ViewState 184 { 185 public SerializedInputAction? relatedInputAction; 186 public SerializedInputBinding? inputBinding; 187 public SerializedInputAction? serializedInputAction; 188 public SelectionType selectionType; 189 } 190 } 191} 192 193#endif