public InputBindingPropertiesView( SerializedProperty bindingProperty, Action <FourCC> onChange = null, InputControlPickerState controlPickerState = null, string expectedControlLayout = null, ReadOnlyArray <InputControlScheme> controlSchemes = new ReadOnlyArray <InputControlScheme>(), IEnumerable <string> controlPathsToMatch = null) : base(InputActionSerializationHelpers.IsCompositeBinding(bindingProperty) ? "Composite" : "Binding", bindingProperty, onChange, expectedControlLayout) { m_BindingProperty = bindingProperty; m_GroupsProperty = bindingProperty.FindPropertyRelative("m_Groups"); m_PathProperty = bindingProperty.FindPropertyRelative("m_Path"); m_BindingGroups = m_GroupsProperty.stringValue.Split(InputBinding.kSeparator).ToList(); m_ExpectedControlLayout = expectedControlLayout; m_ControlSchemes = controlSchemes; var flags = (InputBinding.Flags)bindingProperty.FindPropertyRelative("m_Flags").intValue; m_IsPartOfComposite = (flags & InputBinding.Flags.PartOfComposite) != 0; m_IsComposite = (flags & InputBinding.Flags.Composite) != 0; // Set up control picker for m_Path. Not needed if the binding is a composite. if (!m_IsComposite) { m_ControlPickerState = controlPickerState ?? new InputControlPickerState(); m_ControlPathEditor = new InputControlPathEditor(m_PathProperty, m_ControlPickerState, OnPathChanged); m_ControlPathEditor.SetExpectedControlLayout(m_ExpectedControlLayout); if (controlPathsToMatch != null) { m_ControlPathEditor.SetControlPathsToMatch(controlPathsToMatch); } } }
private void OnItemDoubleClicked(ActionTreeItemBase item) { // Double-clicking on binding or action item opens property popup. PropertiesViewBase propertyView = null; if (item is BindingTreeItem) { if (m_ControlPickerState == null) { m_ControlPickerState = new InputControlPickerState(); } propertyView = new InputBindingPropertiesView(item.property, controlPickerState: m_ControlPickerState, expectedControlLayout: item.expectedControlLayout, onChange: change => m_TreeView.Reload()); } else if (item is ActionTreeItem) { propertyView = new InputActionPropertiesView(item.property, onChange: change => m_TreeView.Reload()); } if (propertyView != null) { var rect = new Rect(GUIUtility.GUIToScreenPoint(Event.current.mousePosition), Vector2.zero); PropertiesViewPopup.Show(rect, propertyView); } }
/// <summary> /// /// </summary> /// <param name="pathProperty"><see cref="string"/> type property that will receive the picked input control path.</param> /// <param name="pickerState">Persistent editing state of the </param> /// <param name="onModified"></param> /// <exception cref="ArgumentNullException"></exception> public InputControlPathEditor(SerializedProperty pathProperty, InputControlPickerState pickerState, Action onModified) { if (pathProperty == null) { throw new ArgumentNullException(nameof(pathProperty)); } this.pathProperty = pathProperty; this.onModified = onModified; m_PickerState = pickerState ?? new InputControlPickerState(); }
public InputControlPickerPopup(SerializedProperty pathProperty, InputControlPickerState pickerState, Action onModified, Action <Rect, SerializedProperty, Action> drawInteractivePickButton) { if (pathProperty == null) { throw new ArgumentNullException("pathProperty"); } m_PathProperty = pathProperty; m_DrawInteractivePickButton = drawInteractivePickButton; m_OnModified = onModified; m_PickerState = pickerState; }
public InputControlPickerDropdown( InputControlPickerState state, Action <string> onPickCallback, InputControlPicker.Mode mode = InputControlPicker.Mode.PickControl) : base(state.advancedDropdownState) { m_Gui = new InputControlPickerGUI(this); minimumSize = new Vector2(275, 300); maximumSize = new Vector2(0, 300); m_OnPickCallback = onPickCallback; m_Mode = mode; }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (m_PickerState == null) { m_PickerState = new InputControlPickerState(); } if (m_Editor == null) { m_Editor = new InputControlPathEditor(property, m_PickerState, () => property.serializedObject.ApplyModifiedProperties()); m_Editor.SetExpectedControlLayoutFromAttribute(); } EditorGUI.BeginProperty(position, label, property); m_Editor.OnGUI(position); EditorGUI.EndProperty(); }
public InputBindingPropertiesView(SerializedProperty bindingProperty, Action <FourCC> onChange, InputControlPickerState controlPickerState, InputActionWindowToolbar toolbar, bool isCompositeBinding = false, string expectedControlLayout = null) : base(isCompositeBinding ? "Composite" : "Binding", bindingProperty, onChange, expectedControlLayout) { m_ControlPickerState = controlPickerState; m_BindingProperty = bindingProperty; m_GroupsProperty = bindingProperty.FindPropertyRelative("m_Groups"); m_PathProperty = bindingProperty.FindPropertyRelative("m_Path"); m_Toolbar = toolbar; if (m_Toolbar != null) { m_ControlSchemes = toolbar.controlSchemes; } m_BindingGroups = m_GroupsProperty.stringValue.Split(InputBinding.kSeparator).ToList(); m_ExpectedControlLayout = expectedControlLayout; m_IsComposite = isCompositeBinding; }
public InputBindingPropertiesView(SerializedProperty bindingProperty, Action <Change> onChange, InputControlPickerState controlPickerState, InputActionWindowToolbar toolbar, string expectedControlLayout = null) { m_ControlPickerState = controlPickerState; m_BindingProperty = bindingProperty; m_OnChange = onChange; m_InteractionsProperty = bindingProperty.FindPropertyRelative("m_Interactions"); m_ProcessorsProperty = bindingProperty.FindPropertyRelative("m_Processors"); m_GroupsProperty = bindingProperty.FindPropertyRelative("m_Groups"); m_PathProperty = bindingProperty.FindPropertyRelative("m_Path"); m_InteractionsList = new InteractionsReorderableReorderableList(m_InteractionsProperty, OnInteractionsModified); m_ProcessorsList = new ProcessorsReorderableReorderableList(m_ProcessorsProperty, OnProcessorsModified); m_Toolbar = toolbar; if (m_Toolbar != null) { m_ControlSchemes = toolbar.controlSchemes; } m_BindingGroups = m_GroupsProperty.stringValue.Split(InputBinding.kSeparator).ToList(); m_ExpectedControlLayout = expectedControlLayout; }
private void InitializeTrees() { m_ActionMapsTree = ActionMapsTree.CreateFromSerializedObject(ApplyAndReload, m_ActionAssetManager.serializedObject, ref m_ActionMapsTreeState); m_ActionMapsTree.OnSelectionChanged = OnActionMapSelection; m_ActionMapsTree.OnContextClick = m_ContextMenu.OnActionMapContextClick; m_ActionsTree = ActionsTree.CreateFromSerializedObject(ApplyAndReload, ref m_ActionsTreeState); m_ActionsTree.OnSelectionChanged = OnActionSelection; m_ActionsTree.OnContextClick = m_ContextMenu.OnActionsContextClick; m_ActionsTree.OnRowGUI = OnActionRowGUI; m_InputActionWindowToolbar.OnSearchChanged = m_ActionsTree.SetNameFilter; m_InputActionWindowToolbar.OnSchemeChanged = a => { if (a == null) { m_ActionsTree.SetSchemeBindingGroupFilter(null); return; } var group = m_ActionAssetManager.m_AssetObjectForEditing.GetControlScheme(a).bindingGroup; m_ActionsTree.SetSchemeBindingGroupFilter(group); }; m_InputActionWindowToolbar.OnDeviceChanged = m_ActionsTree.SetDeviceFilter; m_ActionsTree.SetNameFilter(m_InputActionWindowToolbar.nameFilter); if (m_InputActionWindowToolbar.selectedControlSchemeName != null) { var group = m_ActionAssetManager.m_AssetObjectForEditing.GetControlScheme(m_InputActionWindowToolbar.selectedControlSchemeName).bindingGroup; m_ActionsTree.SetSchemeBindingGroupFilter(group); } m_ActionsTree.SetDeviceFilter(m_InputActionWindowToolbar.selectedDevice); m_CopyPasteUtility = new InputActionCopyPasteUtility(ApplyAndReload, m_ActionMapsTree, m_ActionsTree, m_ActionAssetManager.serializedObject); if (m_PickerTreeViewState == null) { m_PickerTreeViewState = new InputControlPickerState(); } }
private void LoadPropertiesForSelection() { m_BindingPropertyView = null; m_ActionPropertyView = null; ////TODO: preserve interaction/processor selection when reloading // Nothing else to do if we don't have a selection in the middle pane or if // multiple items are selected (we don't currently have the ability to multi-edit). if (!m_ActionsTree.HasSelection() || m_ActionsTree.GetSelection().Count != 1) { return; } var item = m_ActionsTree.GetSelectedItems().FirstOrDefault(); if (item is BindingTreeItem) { // Grab the action for the binding and see if we have an expected control layout // set on it. Pass that on to the control picking machinery. var isCompositePartBinding = item is PartOfCompositeBindingTreeItem; var isCompositeBinding = item is CompositeBindingTreeItem; var actionItem = (isCompositePartBinding ? item.parent.parent : item.parent) as ActionTreeItem; Debug.Assert(actionItem != null); if (m_ControlPickerViewState == null) { m_ControlPickerViewState = new InputControlPickerState(); } // The toolbar may constrain the set of devices we're currently interested in by either // having one specific device selected from the current scheme or having at least a control // scheme selected. var controlPathsToMatch = (IEnumerable <string>)null; if (m_Toolbar.selectedDeviceRequirement != null) { // Single device selected from set of devices in control scheme. controlPathsToMatch = new[] { m_Toolbar.selectedDeviceRequirement.Value.controlPath }; } else if (m_Toolbar.selectedControlScheme != null) { // Constrain to devices from current control scheme. controlPathsToMatch = m_Toolbar.selectedControlScheme.Value.deviceRequirements.Select(x => x.controlPath); } else { // If there's no device filter coming from a control scheme, filter by supported // devices as given by settings. controlPathsToMatch = InputSystem.settings.supportedDevices; } // Show properties for binding. m_BindingPropertyView = new InputBindingPropertiesView( item.property, change => { if (change == InputBindingPropertiesView.k_PathChanged || change == InputBindingPropertiesView.k_CompositePartAssignmentChanged || change == InputBindingPropertiesView.k_CompositeTypeChanged) { ApplyAndReloadTrees(); } else { // Simple property change that doesn't affect the rest of the UI. Apply(); } }, m_ControlPickerViewState, expectedControlLayout: item.expectedControlLayout, controlSchemes: m_Toolbar.controlSchemes, controlPathsToMatch: controlPathsToMatch); } else if (item is ActionTreeItem actionItem) { // Show properties for action. m_ActionPropertyView = new InputActionPropertiesView( actionItem.property, // Apply without reload is enough here as modifying the properties of an action will // never change the structure of the data. change => Apply()); } }
public InputControlPicker(Mode mode, Action <string> onPick, InputControlPickerState state) { m_State = state ?? new InputControlPickerState(); m_Dropdown = new InputControlPickerDropdown(state, onPick, mode: mode); }
private void ShowInputControlPicker(Rect rect, SerializedProperty pathProperty, InputControlPickerState pickerState, Action onPickCallback) { if (m_InputControlPickerDropdown == null) { m_InputControlPickerDropdown = new InputControlPickerDropdown(pickerState.state, path => { pathProperty.stringValue = path; onPickCallback(); }); } var haveDeviceFilterFromControlScheme = false; if (m_Toolbar != null) { if (m_Toolbar.selectedDevice != null) { // Single device selected from set of devices in control scheme. m_InputControlPickerDropdown.SetDeviceFilter(new[] { m_Toolbar.selectedDevice }); haveDeviceFilterFromControlScheme = true; } else { var allDevices = m_Toolbar.allDevices; if (allDevices.Length > 0) { // Filter by all devices in current control scheme. m_InputControlPickerDropdown.SetDeviceFilter(allDevices); haveDeviceFilterFromControlScheme = true; } } if (m_ExpectedControlLayout != null) { m_InputControlPickerDropdown.SetExpectedControlLayoutFilter(m_ExpectedControlLayout); } } // If there's no device filter coming from a control scheme, filter by supported // devices as given by settings . if (!haveDeviceFilterFromControlScheme) { m_InputControlPickerDropdown.SetDeviceFilter(InputSystem.settings.supportedDevices.ToArray()); } m_InputControlPickerDropdown.Show(rect); }
////TODO: interactive picker; if more than one control makes it through the filters, present list of //// candidates for user to choose from ////REVIEW: refactor this out of here; this should be a public API that allows anyone to have an inspector field to select a control binding internal void DrawBindingGUI(SerializedProperty pathProperty, ref bool manualPathEditMode, InputControlPickerState pickerState, Action onModified) { EditorGUILayout.BeginHorizontal(); var lineRect = GUILayoutUtility.GetRect(0, EditorGUIUtility.singleLineHeight); var labelRect = lineRect; labelRect.width = 60; EditorGUI.LabelField(labelRect, s_PathLabel); lineRect.x += 65; lineRect.width -= 65; var bindingTextRect = lineRect; var editButtonRect = lineRect; var interactivePickButtonRect = lineRect; bindingTextRect.width -= 42; editButtonRect.x += bindingTextRect.width + 21; editButtonRect.width = 21; editButtonRect.height = 15; interactivePickButtonRect.x += bindingTextRect.width; interactivePickButtonRect.width = 21; interactivePickButtonRect.height = 15; var path = pathProperty.stringValue; ////TODO: this should be cached; generates needless GC churn var displayName = InputControlPath.ToHumanReadableString(path); if (manualPathEditMode || (!string.IsNullOrEmpty(path) && string.IsNullOrEmpty(displayName))) { EditorGUI.BeginChangeCheck(); path = EditorGUI.DelayedTextField(bindingTextRect, path); if (EditorGUI.EndChangeCheck()) { pathProperty.stringValue = path; pathProperty.serializedObject.ApplyModifiedProperties(); onModified(); } DrawInteractivePickButton(interactivePickButtonRect, pathProperty, onModified); if (GUI.Button(editButtonRect, "˅")) { bindingTextRect.x += editButtonRect.width; ShowInputControlPicker(bindingTextRect, pathProperty, pickerState, onModified); } } else { // Dropdown that shows binding text and allows opening control picker. if (EditorGUI.DropdownButton(bindingTextRect, new GUIContent(displayName), FocusType.Keyboard)) { ////TODO: pass expectedControlLayout filter on to control picker ////TODO: for bindings that are part of composites, use the layout information from the [InputControl] attribute on the field ShowInputControlPicker(bindingTextRect, pathProperty, pickerState, onModified); } // Button to bind interactively. DrawInteractivePickButton(interactivePickButtonRect, pathProperty, onModified); // Button that switches binding into text edit mode. if (GUI.Button(editButtonRect, "...", EditorStyles.miniButton)) { manualPathEditMode = true; } } EditorGUILayout.EndHorizontal(); }