示例#1
0
            private unsafe void AddActionItem(TreeViewItem parent, InputAction action, ref int id)
            {
                // Add item for action.
                var name = action.actionMap != null ? $"{action.actionMap.name}/{action.name}" : action.name;

                if (!action.enabled)
                {
                    name += " (Disabled)";
                }
                var item = AddChild(parent, name, ref id);

                // Grab state.
                var actionMap = action.GetOrCreateActionMap();

                actionMap.ResolveBindingsIfNecessary();
                var state = actionMap.m_State;

                // Add list of resolved controls.
                var actionIndex       = action.m_ActionIndexInState;
                var totalBindingCount = state.totalBindingCount;

                for (var i = 0; i < totalBindingCount; ++i)
                {
                    ref var bindingState = ref state.bindingStates[i];
                    if (bindingState.actionIndex != actionIndex)
                    {
                        continue;
                    }
                    if (bindingState.isComposite)
                    {
                        continue;
                    }

                    var binding           = state.GetBinding(i);
                    var controlCount      = bindingState.controlCount;
                    var controlStartIndex = bindingState.controlStartIndex;
                    for (var n = 0; n < controlCount; ++n)
                    {
                        var control      = state.controls[controlStartIndex + n];
                        var interactions =
                            StringHelpers.Join(new[] { binding.effectiveInteractions, action.interactions }, ",");

                        var text = control.path;
                        if (!string.IsNullOrEmpty(interactions))
                        {
                            var namesAndParameters = NameAndParameters.ParseMultiple(interactions);
                            text += " [";
                            text += string.Join(",", namesAndParameters.Select(x => x.name));
                            text += "]";
                        }

                        AddChild(item, text, ref id);
                    }
                }
示例#2
0
        private void OnParametersChanged()
        {
            for (int i = 0; i < m_ParametersForEachListItem.Length; i++)
            {
                m_ParametersForEachListItem[i] = new NameAndParameters
                {
                    name       = m_ParametersForEachListItem[i].name,
                    parameters = m_EditableParametersForEachListItem[i].GetParameters(),
                };
            }

            m_Apply();
        }
示例#3
0
        public new static CompositeBindingTreeItem AddTo(TreeViewItem parent, SerializedProperty bindingProperty)
        {
            var item = new CompositeBindingTreeItem(bindingProperty);

            item.depth       = parent.depth + 1;
            item.displayName = !string.IsNullOrEmpty(item.name)
                ? item.name
                : ObjectNames.NicifyVariableName(NameAndParameters.ParseName(item.path));

            parent.AddChild(item);

            return(item);
        }
        private void OnCompositeTypeChanged()
        {
            var nameAndParameters = new NameAndParameters
            {
                name       = m_CompositeTypes[m_SelectedCompositeType],
                parameters = m_CompositeParameters.GetParameters()
            };

            InputActionSerializationHelpers.ChangeCompositeBindingType(m_BindingProperty, nameAndParameters);
            m_PathProperty.serializedObject.ApplyModifiedProperties();

            onChange?.Invoke(k_CompositeTypeChanged);
        }
        private void OnCompositeParametersModified()
        {
            Debug.Assert(m_CompositeParameters != null);

            var path = m_PathProperty.stringValue;
            var nameAndParameters = NameAndParameters.Parse(path);

            nameAndParameters.parameters = m_CompositeParameters.GetParameters();

            m_PathProperty.stringValue = nameAndParameters.ToString();
            m_PathProperty.serializedObject.ApplyModifiedProperties();

            OnPathChanged();
        }
        private void InitializeCompositeProperties()
        {
            // Find name of current composite.
            var path = m_PathProperty.stringValue;
            var compositeNameAndParameters = NameAndParameters.Parse(path);
            var compositeName = compositeNameAndParameters.name;
            var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(compositeName);

            // Collect all possible composite types.
            var selectedCompositeIndex   = -1;
            var compositeTypeOptionsList = new List <GUIContent>();
            var compositeTypeList        = new List <string>();
            var currentIndex             = 0;

            foreach (var composite in InputBindingComposite.s_Composites.internedNames.Where(x =>
                                                                                             !InputBindingComposite.s_Composites.aliases.Contains(x)).OrderBy(x => x))
            {
                if (InputBindingComposite.s_Composites.LookupTypeRegistration(composite) == compositeType)
                {
                    selectedCompositeIndex = currentIndex;
                }
                var name = ObjectNames.NicifyVariableName(composite);
                compositeTypeOptionsList.Add(new GUIContent(name));
                compositeTypeList.Add(composite);
                ++currentIndex;
            }

            // If the current composite type isn't a registered type, add it to the list as
            // an extra option.
            if (selectedCompositeIndex == -1)
            {
                selectedCompositeIndex = compositeTypeList.Count;
                compositeTypeOptionsList.Add(new GUIContent(ObjectNames.NicifyVariableName(compositeName)));
                compositeTypeList.Add(compositeName);
            }

            m_CompositeTypes        = compositeTypeList.ToArray();
            m_CompositeTypeOptions  = compositeTypeOptionsList.ToArray();
            m_SelectedCompositeType = selectedCompositeIndex;

            // Initialize parameters.
            m_CompositeParameters = new ParameterListView
            {
                onChange = OnCompositeParametersModified
            };
            if (compositeType != null)
            {
                m_CompositeParameters.Initialize(compositeType, compositeNameAndParameters.parameters);
            }
        }
示例#7
0
        protected NameAndParameterListView(SerializedProperty property, Action applyAction, string expectedControlLayout, TypeTable listOptions, Func <Type, Type> getValueType, string itemName)
        {
            m_ItemName     = itemName;
            m_GetValueType = getValueType;
            m_DeleteButton = EditorGUIUtility.TrIconContent("Toolbar Minus", $"Delete {itemName}");
            m_UpButton     = EditorGUIUtility.TrIconContent(GUIHelpers.LoadIcon("ChevronUp"), $"Move {itemName} up");
            m_DownButton   = EditorGUIUtility.TrIconContent(GUIHelpers.LoadIcon("ChevronDown"), $"Move {itemName} down");

            m_Property    = property;
            m_Apply       = applyAction;
            m_ListOptions = listOptions;

            m_ExpectedControlLayout = expectedControlLayout;
            if (!string.IsNullOrEmpty(m_ExpectedControlLayout))
            {
                m_ExpectedValueType = EditorInputControlLayoutCache.GetValueType(m_ExpectedControlLayout);
            }

            m_ParametersForEachListItem         = NameAndParameters.ParseMultiple(m_Property.stringValue).ToArray();
            m_EditableParametersForEachListItem = new ParameterListView[m_ParametersForEachListItem.Length];

            for (var i = 0; i < m_ParametersForEachListItem.Length; i++)
            {
                m_EditableParametersForEachListItem[i] = new ParameterListView {
                    onChange = OnParametersChanged
                };
                var typeName = m_ParametersForEachListItem[i].name;
                var rowType  = m_ListOptions.LookupTypeRegistration(typeName);
                m_EditableParametersForEachListItem[i].Initialize(rowType, m_ParametersForEachListItem[i].parameters);

                var name = ObjectNames.NicifyVariableName(typeName);

                ////REVIEW: finding this kind of stuff should probably have better support globally on the asset; e.g. some
                ////        notification that pops up and allows fixing all occurrences in one click
                // Find out if we still support this option and indicate it in the list, if we don't.
                if (rowType == null)
                {
                    name += " (Obsolete)";
                }
                else if (m_ExpectedValueType != null)
                {
                    var valueType = getValueType(rowType);
                    if (!m_ExpectedValueType.IsAssignableFrom(valueType))
                    {
                        name += " (Ignored)";
                    }
                }
                m_EditableParametersForEachListItem[i].name = name;
            }
        }
        private void InitializeCompositePartProperties()
        {
            var currentCompositePart = m_BindingProperty.FindPropertyRelative("m_Name").stringValue;

            ////REVIEW: this makes a lot of assumptions about the serialized data based on the one property we've been given in the ctor
            // Determine the name of the current composite type that the part belongs to.
            var bindingArrayProperty  = m_BindingProperty.GetArrayPropertyFromElement();
            var partBindingIndex      = InputActionSerializationHelpers.GetIndex(bindingArrayProperty, m_BindingProperty);
            var compositeBindingIndex =
                InputActionSerializationHelpers.GetCompositeStartIndex(bindingArrayProperty, partBindingIndex);

            if (compositeBindingIndex == -1)
            {
                return;
            }
            var compositeBindingProperty   = bindingArrayProperty.GetArrayElementAtIndex(compositeBindingIndex);
            var compositePath              = compositeBindingProperty.FindPropertyRelative("m_Path").stringValue;
            var compositeNameAndParameters = NameAndParameters.Parse(compositePath);

            // Initialize option list from all parts available for the composite.
            var optionList            = new List <GUIContent>();
            var nameList              = new List <string>();
            var currentIndex          = 0;
            var selectedPartNameIndex = -1;

            foreach (var partName in InputBindingComposite.GetPartNames(compositeNameAndParameters.name))
            {
                if (partName.Equals(currentCompositePart, StringComparison.InvariantCultureIgnoreCase))
                {
                    selectedPartNameIndex = currentIndex;
                }
                var niceName = ObjectNames.NicifyVariableName(partName);
                optionList.Add(new GUIContent(niceName));
                nameList.Add(partName);
                ++currentIndex;
            }

            // If currently selected part is not in list, add it as an option.
            if (selectedPartNameIndex == -1)
            {
                selectedPartNameIndex = nameList.Count;
                optionList.Add(new GUIContent(ObjectNames.NicifyVariableName(currentCompositePart)));
                nameList.Add(currentCompositePart);
            }

            m_CompositeParts        = nameList.ToArray();
            m_CompositePartOptions  = optionList.ToArray();
            m_SelectedCompositePart = selectedPartNameIndex;
        }
示例#9
0
    public void Utilities_CanParseMultipleNameAndParameterLists()
    {
        Assert.That(NameAndParameters.ParseMultiple("a,b").Count(), Is.EqualTo(2));
        Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[0].name, Is.EqualTo("a"));
        Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[0].parameters, Is.Empty);
        Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[1].name, Is.EqualTo("b"));
        Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[1].parameters, Is.Empty);

        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").Count(), Is.EqualTo(3));
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[0].name, Is.EqualTo("a"));
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[0].parameters, Is.Empty);
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[1].name, Is.EqualTo("b"));
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[1].parameters, Has.Count.EqualTo(2));
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[2].name, Is.EqualTo("c"));
        Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[2].parameters, Is.Empty);

        Assert.That(NameAndParameters.ParseMultiple("a(b,c=123)").Count(), Is.EqualTo(1));
    }
示例#10
0
 public void Utilities_CanParseNameAndParameterList()
 {
     Assert.That(NameAndParameters.Parse("name()").name, Is.EqualTo("name"));
     Assert.That(NameAndParameters.Parse("name()").parameters, Is.Empty);
     Assert.That(NameAndParameters.Parse("name").name, Is.EqualTo("name"));
     Assert.That(NameAndParameters.Parse("name").parameters, Is.Empty);
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").name, Is.EqualTo("Name"));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters, Has.Count.EqualTo(3));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[0].name, Is.EqualTo("foo"));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[1].name, Is.EqualTo("Bar"));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[2].name, Is.EqualTo("blub"));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[0].type, Is.EqualTo(TypeCode.Boolean));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[1].type, Is.EqualTo(TypeCode.Int32));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[2].type, Is.EqualTo(TypeCode.Double));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[0].value.ToBoolean(), Is.EqualTo(true));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[1].value.ToInt32(), Is.EqualTo(123));
     Assert.That(NameAndParameters.Parse("Name(foo,Bar=123,blub=234.56)").parameters[2].value.ToDouble(), Is.EqualTo(234.56).Within(0.0001));
 }
示例#11
0
            public ModifyPopupWindow(SerializedProperty bindingProperty)
            {
                m_FlagsProperty        = bindingProperty.FindPropertyRelative("m_Flags");
                m_InteractionsProperty = bindingProperty.FindPropertyRelative("m_Interactions");
                m_Flags = (InputBinding.Flags)m_FlagsProperty.intValue;

                var interactions = InputSystem.ListInteractions().ToList();

                interactions.Sort();
                m_InteractionChoices = interactions.Select(x => new GUIContent(x)).ToArray();

                var interactionString = m_InteractionsProperty.stringValue;

                if (!string.IsNullOrEmpty(interactionString))
                {
                    m_Interactions = NameAndParameters.ParseMultiple(interactionString).ToArray();
                }
                else
                {
                    m_Interactions = new NameAndParameters[0];
                }

                InitializeInteractionListView();
            }
        public static SerializedProperty ChangeCompositeBindingType(SerializedProperty bindingProperty,
                                                                    NameAndParameters nameAndParameters)
        {
            var bindingsArrayProperty = bindingProperty.GetArrayPropertyFromElement();

            Debug.Assert(bindingsArrayProperty != null, "SerializedProperty is not an array of bindings");
            var bindingIndex = bindingProperty.GetIndexOfArrayElement();

            Debug.Assert(IsCompositeBinding(bindingProperty),
                         $"Binding {bindingProperty.propertyPath} is not a composite");

            // If the composite still has the default name, change it to the default
            // one for the new composite type.
            var pathProperty = bindingProperty.FindPropertyRelative("m_Path");
            var nameProperty = bindingProperty.FindPropertyRelative("m_Name");

            if (nameProperty.stringValue ==
                ObjectNames.NicifyVariableName(NameAndParameters.Parse(pathProperty.stringValue).name))
            {
                nameProperty.stringValue = ObjectNames.NicifyVariableName(nameAndParameters.name);
            }

            pathProperty.stringValue = nameAndParameters.ToString();

            // Adjust part bindings if we have information on the registered composite. If we don't have
            // a type, we don't know about the parts. In that case, leave part bindings untouched.
            var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(nameAndParameters.name);

            if (compositeType != null)
            {
                var actionName = bindingProperty.FindPropertyRelative("m_Action").stringValue;

                // Repurpose existing part bindings for the new composite or add any part bindings that
                // we're missing.
                var fields    = compositeType.GetFields(BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);
                var partIndex = 0;
                var partBindingsStartIndex = bindingIndex + 1;
                foreach (var field in fields)
                {
                    // Skip fields that aren't marked with [InputControl] attribute.
                    if (field.GetCustomAttribute <InputControlAttribute>(false) == null)
                    {
                        continue;
                    }

                    // See if we can reuse an existing part binding.
                    SerializedProperty partProperty = null;
                    if (partBindingsStartIndex + partIndex < bindingsArrayProperty.arraySize)
                    {
                        ////REVIEW: this should probably look up part bindings by name rather than going sequentially
                        var element = bindingsArrayProperty.GetArrayElementAtIndex(partBindingsStartIndex + partIndex);
                        if (((InputBinding.Flags)element.FindPropertyRelative("m_Flags").intValue & InputBinding.Flags.PartOfComposite) != 0)
                        {
                            partProperty = element;
                        }
                    }

                    // If not, insert a new binding.
                    if (partProperty == null)
                    {
                        partProperty = AddBindingToBindingArray(bindingsArrayProperty, partBindingsStartIndex + partIndex,
                                                                flags: InputBinding.Flags.PartOfComposite);
                    }

                    // Initialize.
                    partProperty.FindPropertyRelative("m_Name").stringValue   = ObjectNames.NicifyVariableName(field.Name);
                    partProperty.FindPropertyRelative("m_Action").stringValue = actionName;
                    ++partIndex;
                }

                ////REVIEW: when we allow adding the same part multiple times, we may want to do something smarter here
                // Delete extraneous part bindings.
                while (partBindingsStartIndex + partIndex < bindingsArrayProperty.arraySize)
                {
                    var element = bindingsArrayProperty.GetArrayElementAtIndex(partBindingsStartIndex + partIndex);
                    if (((InputBinding.Flags)element.FindPropertyRelative("m_Flags").intValue & InputBinding.Flags.PartOfComposite) == 0)
                    {
                        break;
                    }

                    bindingsArrayProperty.DeleteArrayElementAtIndex(partBindingsStartIndex + partIndex);
                    // No incrementing of partIndex.
                }
            }

            return(bindingProperty);
        }
示例#13
0
        ////TODO: move this out into a general routine that can take a path and construct a display name
        private static GUIContent GetContentForPath(string path, string interactions, InputBinding.Flags flags)
        {
            const int kUsageNameGroup   = 1;
            const int kDeviceNameGroup  = 1;
            const int kDeviceUsageGroup = 3;
            const int kControlPathGroup = 4;

            ////TODO: nuke the regex stuff in here

            if (s_UsageRegex == null)
            {
                s_UsageRegex = new Regex("\\*/{([A-Za-z0-9]+)}");
            }
            if (s_ControlRegex == null)
            {
                s_ControlRegex = new Regex("<([A-Za-z0-9:\\-]+)>({([A-Za-z0-9]+)})?/([A-Za-z0-9]+(/[A-Za-z0-9]+)*)");
            }

            var text = path;

            var usageMatch = s_UsageRegex.Match(path);

            if (usageMatch.Success)
            {
                text = usageMatch.Groups[kUsageNameGroup].Value;
            }
            else
            {
                var controlMatch = s_ControlRegex.Match(path);
                if (controlMatch.Success)
                {
                    var device      = controlMatch.Groups[kDeviceNameGroup].Value;
                    var deviceUsage = controlMatch.Groups[kDeviceUsageGroup].Value;
                    var control     = controlMatch.Groups[kControlPathGroup].Value;

                    ////TODO: would be nice to include layout name to print something like "Gamepad A Button" instead of "Gamepad A" (or whatever)

                    if (!string.IsNullOrEmpty(deviceUsage))
                    {
                        text = $"{deviceUsage} {device} {control}";
                    }
                    else
                    {
                        text = $"{device} {control}";
                    }
                }
            }

            ////REVIEW: would be nice to have icons for these

            // Show interactions.
            if (!string.IsNullOrEmpty(interactions))
            {
                var interactionList   = NameAndParameters.ParseMultiple(interactions);
                var interactionString = string.Join(" OR ", interactionList.Select(x => x.name).ToArray());
                text = $"{interactionString} {text}";
            }

            ////TODO: this looks ugly and not very obvious; find a better way
            // Show if linked with previous binding.
            if ((flags & InputBinding.Flags.ThisAndPreviousCombine) == InputBinding.Flags.ThisAndPreviousCombine)
            {
                text = "AND " + text;
            }

            return(new GUIContent(text));
        }
示例#14
0
 public void Utilities_ParsingNameAndParameterList_RequiresStringToNotBeEmpty()
 {
     Assert.That(() => NameAndParameters.Parse("").name,
                 Throws.Exception.With.Message.Contains("Expecting name"));
 }