示例#1
0
        string ConvertPotentialAliasToName(InputControlLayout layout, string nameOrAlias)
        {
            InternedString internedNameOrAlias = new InternedString(nameOrAlias);
            ReadOnlyArray <InputControlLayout.ControlItem> controls = layout.controls;

            for (int i = 0; i < controls.Count; i++)
            {
                InputControlLayout.ControlItem controlItem = controls[i];

                if (controlItem.name == internedNameOrAlias)
                {
                    return(nameOrAlias);
                }

                ReadOnlyArray <InternedString> aliases = controlItem.aliases;
                for (int j = 0; j < aliases.Count; j++)
                {
                    if (aliases[j] == nameOrAlias)
                    {
                        return(controlItem.name.ToString());
                    }
                }
            }
            return(nameOrAlias);
        }
示例#2
0
        private void AddDeviceTreeItem(InputControlLayout layout, AdvancedDropdownItem parent)
        {
            // Ignore devices that have no controls. We're looking at fully merged layouts here so
            // we're also taking inherited controls into account.
            if (layout.controls.Count == 0)
            {
                return;
            }

            var deviceItem = new DeviceTreeViewItem(layout);

            AddControlTreeItemsRecursive(layout, deviceItem, "", layout.name, null);

            if (deviceItem.children.Any())
            {
                parent.AddChild(deviceItem);
            }

            foreach (var commonUsage in layout.commonUsages)
            {
                var commonUsageGroup = new DeviceTreeViewItem(layout, commonUsage);
                AddControlTreeItemsRecursive(layout, commonUsageGroup, "", layout.name, commonUsage);
                if (commonUsageGroup.children.Any())
                {
                    parent.AddChild(commonUsageGroup);
                }
            }
        }
            private TreeViewItem AddControlLayoutItem(InputControlLayout layout, TreeViewItem parent, ref int id)
            {
                var item = AddChild(parent, layout.name, ref id);

                item.icon = EditorInputControlLayoutCache.GetIconForLayout(layout.name);

                // Header.
                AddChild(item, "Type: " + layout.type.Name, ref id);
                if (!string.IsNullOrEmpty(layout.m_DisplayName))
                {
                    AddChild(item, "Display Name: " + layout.m_DisplayName, ref id);
                }
                var baseLayouts = StringHelpers.Join(layout.baseLayouts, ", ");

                if (!string.IsNullOrEmpty(baseLayouts))
                {
                    AddChild(item, "Extends: " + baseLayouts, ref id);
                }
                if (layout.stateFormat != 0)
                {
                    AddChild(item, "Format: " + layout.stateFormat, ref id);
                }
                if (layout.m_UpdateBeforeRender != null)
                {
                    var value = layout.m_UpdateBeforeRender.Value ? "Update" : "Disabled";
                    AddChild(item, "Before Render: " + value, ref id);
                }
                if (layout.commonUsages.Count > 0)
                {
                    AddChild(item,
                             "Common Usages: " +
                             string.Join(", ", layout.commonUsages.Select(x => x.ToString()).ToArray()), ref id);
                }

                ////TODO: find a more elegant solution than multiple "Matching Devices" parents when having multiple
                ////      matchers
                // Device matchers.
                foreach (var matcher in EditorInputControlLayoutCache.GetDeviceMatchers(layout.name))
                {
                    var node = AddChild(item, "Matching Devices", ref id);
                    foreach (var pattern in matcher.patterns)
                    {
                        AddChild(node, $"{pattern.Key} => \"{pattern.Value}\"", ref id);
                    }
                }

                // Controls.
                if (layout.controls.Count > 0)
                {
                    var controls = AddChild(item, "Controls", ref id);
                    foreach (var control in layout.controls)
                    {
                        AddControlItem(control, controls, ref id);
                    }

                    controls.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                }

                return(item);
            }
        private static void ScanLayout(InputControlLayout layout)
        {
            foreach (var control in layout.controls)
            {
                // Collect unique usages and the layouts used with them.
                foreach (var usage in control.usages)
                {
                    var internedUsage  = new InternedString(usage);
                    var internedLayout = new InternedString(control.layout);

                    List <InternedString> layoutList;
                    if (!s_Usages.TryGetValue(internedUsage, out layoutList))
                    {
                        layoutList = new List <InternedString> {
                            internedLayout
                        };
                        s_Usages[internedUsage] = layoutList;
                    }
                    else
                    {
                        var layoutAlreadyInList =
                            layoutList.Any(x => x == internedLayout);
                        if (!layoutAlreadyInList)
                        {
                            layoutList.Add(internedLayout);
                        }
                    }
                }
            }
        }
示例#5
0
        private int ResolveProcessors(string processorString)
        {
            var firstProcessorIndex = totalProcessorCount;

            if (!InputControlLayout.ParseNameAndParameterList(processorString, ref m_Parameters))
            {
                return(firstProcessorIndex);
            }

            for (var i = 0; i < m_Parameters.Count; ++i)
            {
                // Look up processor.
                var type = InputControlProcessor.s_Processors.LookupTypeRegistration(m_Parameters[i].name);
                if (type == null)
                {
                    throw new Exception(string.Format(
                                            "No processor with name '{0}' (mentioned in '{1}') has been registered", m_Parameters[i].name,
                                            processorString));
                }

                // Instantiate it.
                var processor = Activator.CreateInstance(type);

                // Pass parameters to it.
                InputDeviceBuilder.SetParameters(processor, m_Parameters[i].parameters);

                // Add to list.
                ArrayHelpers.AppendWithCapacity(ref processors, ref totalProcessorCount, processor);
            }

            return(firstProcessorIndex);
        }
示例#6
0
        private void AddChildControlIfMissing(InputControlLayout layout, InternedString variants, InputControl parent,
                                              ref bool haveChildrenUsingStateFromOtherControls,
                                              ref InputControlLayout.ControlItem controlItem)
        {
            ////TODO: support arrays (we may modify an entire array in bulk)

            // Find the child control.
            var child = InputControlPath.TryFindChild(parent, controlItem.name);

            if (child != null)
            {
                return;
            }

            // We're adding a child somewhere in the existing hierarchy. This is a tricky
            // case as we have to potentially shift indices around in the hierarchy to make
            // room for the new control.

            ////TODO: this path does not support recovering existing controls? does it matter?

            child = InsertChildControl(layout, variants, parent,
                                       ref haveChildrenUsingStateFromOtherControls, ref controlItem);

            // Apply layout change.
            if (!ReferenceEquals(child.parent, parent))
            {
                ComputeStateLayout(child.parent);
            }
        }
示例#7
0
        private static void AddControlTreeItemsRecursive(InputControlLayout layout, TreeViewItem parent, string prefix, string deviceControlId, string commonUsage)
        {
            foreach (var control in layout.controls.OrderBy(a => a.name))
            {
                if (control.isModifyingChildControlByPath)
                {
                    continue;
                }

                // Skip variants except the default variant and variants dictated by the layout itself.
                if (!control.variants.IsEmpty() && control.variants != InputControlLayout.DefaultVariant &&
                    (layout.variants.IsEmpty() || !InputControlLayout.VariantsMatch(layout.variants, control.variants)))
                {
                    continue;
                }

                var child = new ControlTreeViewItem(control, prefix, deviceControlId, commonUsage)
                {
                    depth = parent.depth + 1,
                };
                parent.AddChild(child);

                var childLayout = EditorInputControlLayoutCache.TryGetLayout(control.layout);
                if (childLayout != null)
                {
                    AddControlTreeItemsRecursive(childLayout, parent, child.controlPath, deviceControlId, commonUsage);
                }
            }
        }
示例#8
0
        private static void AddDeviceTreeItem(InputControlLayout layout, TreeViewItem parent)
        {
            // Ignore devices that have no controls. We're looking at fully merged layouts here so
            // we're also taking inherited controls into account.
            if (layout.controls.Count == 0)
            {
                return;
            }

            var deviceItem = new DeviceTreeViewItem(layout)
            {
                depth = parent.depth + 1
            };

            AddControlTreeItemsRecursive(layout, deviceItem, "", layout.name, null);

            parent.AddChild(deviceItem);

            foreach (var commonUsage in layout.commonUsages)
            {
                var commonUsageGroup = new DeviceTreeViewItem(layout, commonUsage)
                {
                    depth = parent.depth + 1
                };
                parent.AddChild(commonUsageGroup);
                AddControlTreeItemsRecursive(layout, commonUsageGroup, "", layout.name, commonUsage);
            }
        }
示例#9
0
        private static string ConvertPotentialAliasToName(InputControlLayout layout, string nameOrAlias)
        {
            var internedNameOrAlias = new InternedString(nameOrAlias);
            var controls            = layout.controls;

            for (var i = 0; i < controls.Count; i++)
            {
                var controlItem = controls[i];

                if (controlItem.name == internedNameOrAlias)
                {
                    return(nameOrAlias);
                }

                var aliases = controlItem.aliases;
                for (var j = 0; j < aliases.Count; j++)
                {
                    if (aliases[j] == nameOrAlias)
                    {
                        return(controlItem.name.ToString());
                    }
                }
            }
            return(nameOrAlias);
        }
示例#10
0
        private void AddControlTreeItemsRecursive(InputControlLayout layout, DeviceDropdownItem parent,
                                                  string device, string usage, bool searchable, ControlDropdownItem parentControl = null)
        {
            foreach (var control in layout.controls.OrderBy(a => a.name))
            {
                if (control.isModifyingChildControlByPath)
                {
                    continue;
                }

                // Skip variants except the default variant and variants dictated by the layout itself.
                if (!control.variants.IsEmpty() && control.variants != InputControlLayout.DefaultVariant &&
                    (layout.variants.IsEmpty() || !InputControlLayout.VariantsMatch(layout.variants, control.variants)))
                {
                    continue;
                }

                var child = new ControlDropdownItem(parentControl, control.name, control.displayName,
                                                    device, usage, searchable);
                child.icon = EditorInputControlLayoutCache.GetIconForLayout(control.layout);

                if (LayoutMatchesExpectedControlLayoutFilter(control.layout))
                {
                    parent.AddChild(child);
                }

                var controlLayout = EditorInputControlLayoutCache.TryGetLayout(control.layout);
                if (controlLayout != null)
                {
                    AddControlTreeItemsRecursive(controlLayout, parent, device, usage,
                                                 searchable, child);
                }
            }

            // Add optional controls for devices.
            var optionalControls = EditorInputControlLayoutCache.GetOptionalControlsForLayout(layout.name);

            if (optionalControls.Any() && layout.isDeviceLayout)
            {
                var optionalGroup = new AdvancedDropdownItem("Optional Controls");
                foreach (var optionalControl in optionalControls)
                {
                    if (LayoutMatchesExpectedControlLayoutFilter(optionalControl.layout))
                    {
                        var child = new OptionalControlDropdownItem(optionalControl, device, usage);
                        child.icon = EditorInputControlLayoutCache.GetIconForLayout(optionalControl.layout);
                        optionalGroup.AddChild(child);
                    }
                }

                if (optionalGroup.children.Any())
                {
                    var deviceName = EditorInputControlLayoutCache.TryGetLayout(device).m_DisplayName ??
                                     ObjectNames.NicifyVariableName(device);
                    parent.AddSeparator("Controls Present on More Specific " + deviceName.GetPlural());
                    parent.AddChild(optionalGroup);
                }
            }
        }
示例#11
0
 public DeviceTreeViewItem(InputControlLayout layout, string commonUsage)
 {
     displayName = layout.name;
     if (commonUsage != null)
     {
         displayName += " (" + commonUsage + ")";
     }
     id    = (displayName).GetHashCode();
     depth = 1;
 }
示例#12
0
 public DeviceTreeViewItem(InputControlLayout layout, string commonUsage) : base(layout.name)
 {
     m_Device = layout.name;
     m_Usage  = commonUsage;
     if (commonUsage != null)
     {
         name += " (" + commonUsage + ")";
     }
     id = name.GetHashCode();
     m_SearchableName = InputControlPath.ToHumanReadableString(controlPathWithDevice);
 }
示例#13
0
 void OnSelection(ReorderableList list)
 {
     if (list.index < 0)
     {
         m_SelectedRow = null;
         return;
     }
     m_SelectedRow           = (string)list.list[list.index];
     m_NamesAndParams        = InputControlLayout.ParseNameAndParameterList(m_Property.stringValue);
     m_SelectedParameterList = GetFieldsFromClass();
 }
        public void Setup(InternedString layout, InternedString variants,
                          InputDeviceDescription deviceDescription = default)
        {
            m_LayoutCacheRef = InputControlLayout.CacheRef();

            InstantiateLayout(layout, variants, new InternedString(), null);
            FinalizeControlHierarchy();

            m_Device.m_Description = deviceDescription;
            m_Device.CallFinishSetupRecursive();
        }
示例#15
0
        private InputControl InsertChildControl(InputControlLayout layout, InternedString variant, InputControl parent,
                                                ref bool haveChildrenUsingStateFromOtherControls,
                                                ref InputControlLayout.ControlItem controlItem)
        {
            var path = controlItem.name.ToString();

            // First we need to find the immediate parent from the given path.
            var indexOfSlash = path.LastIndexOf('/');

            if (indexOfSlash == -1)
            {
                throw new InvalidOperationException("InsertChildControl has to be called with a slash-separated path");
            }
            Debug.Assert(indexOfSlash != 0, "Could not find slash in path");
            var immediateParentPath = path.Substring(0, indexOfSlash);
            var immediateParent     = InputControlPath.TryFindChild(parent, immediateParentPath);

            if (immediateParent == null)
            {
                throw new InvalidOperationException(
                          $"Cannot find parent '{immediateParentPath}' of control '{controlItem.name}' in layout '{layout.name}'");
            }

            var controlName = path.Substring(indexOfSlash + 1);

            if (controlName.Length == 0)
            {
                throw new InvalidOperationException(
                          $"Path cannot end in '/' (control '{controlItem.name}' in layout '{layout.name}')");
            }

            // Make room in the device's child array.
            var childStartIndex = immediateParent.m_ChildStartIndex;

            if (childStartIndex == default)
            {
                // First child of parent.
                childStartIndex = m_Device.m_ChildrenForEachControl.LengthSafe();
                immediateParent.m_ChildStartIndex = childStartIndex;
            }
            var childIndex = childStartIndex + immediateParent.m_ChildCount;

            ShiftChildIndicesInHierarchyOneUp(m_Device, childIndex, immediateParent);
            ArrayHelpers.InsertAt(ref m_Device.m_ChildrenForEachControl, childIndex, null);
            ++immediateParent.m_ChildCount;

            // Insert the child.
            // NOTE: This may *add several* controls depending on the layout of the control we are inserting.
            //       The children will be appended to the child array.
            var control = AddChildControl(layout, variant, immediateParent,
                                          ref haveChildrenUsingStateFromOtherControls, controlItem, childIndex, controlName);

            return(control);
        }
示例#16
0
        private static string FindControlLayoutRecursive(ref PathParser parser, InputControlLayout layout)
        {
            string currentResult = null;

            var controlCount = layout.controls.Count;

            for (var i = 0; i < controlCount; ++i)
            {
                if (layout.m_Controls[i].isModifyingChildControlByPath)
                {
                    throw new NotImplementedException();
                }

                ////TODO: shortcut the search if we have a match and there's no wildcards to consider

                // Skip control layout if it doesn't match.
                if (!ControlLayoutMatchesPathComponent(ref layout.m_Controls[i], ref parser))
                {
                    continue;
                }

                var controlLayoutName = layout.m_Controls[i].layout;

                // If there's more in the path, try to dive into children by jumping to the
                // control's layout.
                if (!parser.isAtEnd)
                {
                    var childPathParser = parser;
                    if (childPathParser.MoveToNextComponent())
                    {
                        var childControlLayoutName = FindControlLayoutRecursive(ref childPathParser, controlLayoutName);
                        if (childControlLayoutName != null)
                        {
                            if (currentResult != null && childControlLayoutName != currentResult)
                            {
                                return(null);
                            }
                            currentResult = childControlLayoutName;
                        }
                    }
                }
                else if (currentResult != null && controlLayoutName != currentResult)
                {
                    return(null);
                }
                else
                {
                    currentResult = controlLayoutName.ToString();
                }
            }

            return(currentResult);
        }
 public DeviceDropdownItem(InputControlLayout layout, string usage = null, bool searchable = true)
     : base(layout.m_DisplayName ?? ObjectNames.NicifyVariableName(layout.name))
 {
     m_Device = layout.name;
     m_Usage  = usage;
     if (usage != null)
     {
         name += " (" + usage + ")";
     }
     id           = name.GetHashCode();
     m_Searchable = searchable;
 }
示例#18
0
        private static void ScanLayout(InputControlLayout layout)
        {
            var controls = layout.controls;

            for (var i = 0; i < controls.Count; ++i)
            {
                var control = controls[i];

                // If it's not just a control modifying some inner child control, add control to all base
                // layouts as an optional control.
                //
                // NOTE: We're looking at layouts post-merging here. Means we have already picked up all the
                //       controls present on the base.
                if (control.isFirstDefinedInThisLayout && !control.isModifyingExistingControl && !control.layout.IsEmpty())
                {
                    foreach (var baseLayout in layout.baseLayouts)
                    {
                        AddOptionalControlRecursive(baseLayout, ref control);
                    }
                }

                // Collect unique usages and the layouts used with them.
                foreach (var usage in control.usages)
                {
                    // Empty usages can occur for controls that want to reset inherited usages.
                    if (string.IsNullOrEmpty(usage))
                    {
                        continue;
                    }

                    var internedUsage  = new InternedString(usage);
                    var internedLayout = new InternedString(control.layout);

                    if (!s_Usages.TryGetValue(internedUsage, out var layoutList))
                    {
                        layoutList = new List <InternedString> {
                            internedLayout
                        };
                        s_Usages[internedUsage] = layoutList;
                    }
                    else
                    {
                        var layoutAlreadyInList =
                            layoutList.Any(x => x == internedLayout);
                        if (!layoutAlreadyInList)
                        {
                            layoutList.Add(internedLayout);
                        }
                    }
                }
            }
        }
        private void OnCompositeParametersModified()
        {
            Debug.Assert(m_CompositeParameters != null);

            var path = m_PathProperty.stringValue;
            var nameAndParameters = InputControlLayout.ParseNameAndParameters(path);

            nameAndParameters.parameters = m_CompositeParameters.GetParameters();

            m_PathProperty.stringValue = nameAndParameters.ToString();

            OnPathModified();
        }
        void AddDeviceTreeItem(InputControlLayout layout, List <DeviceEntryForList> deviceList)
        {
            var entry = new DeviceEntryForList();

            entry.name = layout.name;
            deviceList.Add(entry);
            foreach (var commonUsage in layout.commonUsages)
            {
                var entryWithUsage = new DeviceEntryForList();
                entryWithUsage.name        = layout.name;
                entryWithUsage.commonUsage = commonUsage;
                deviceList.Add(entryWithUsage);
            }
        }
            private TreeViewItem AddControlLayoutItem(InputControlLayout layout, TreeViewItem parent, ref int id)
            {
                var item = AddChild(parent, layout.name, ref id);

                // Header.
                AddChild(item, "Type: " + layout.type.Name, ref id);
                var baseLayouts = StringHelpers.Join(layout.baseLayouts, ", ");

                if (!string.IsNullOrEmpty(baseLayouts))
                {
                    AddChild(item, "Extends: " + baseLayouts, ref id);
                }
                if (layout.stateFormat != 0)
                {
                    AddChild(item, "Format: " + layout.stateFormat, ref id);
                }
                if (layout.m_UpdateBeforeRender != null)
                {
                    var value = layout.m_UpdateBeforeRender.Value ? "Update" : "Disabled";
                    AddChild(item, "Before Render: " + value, ref id);
                }
                if (layout.commonUsages.Count > 0)
                {
                    AddChild(item,
                             "Common Usages: " +
                             string.Join(", ", layout.commonUsages.Select(x => x.ToString()).ToArray()), ref id);
                }
                if (!layout.deviceMatcher.empty)
                {
                    var node = AddChild(item, "Matching Devices", ref id);
                    foreach (var pattern in layout.deviceMatcher.patterns)
                    {
                        AddChild(node, string.Format("{0} => \"{1}\"", pattern.Key, pattern.Value), ref id);
                    }
                }

                // Controls.
                if (layout.controls.Count > 0)
                {
                    var controls = AddChild(item, "Controls", ref id);
                    foreach (var control in layout.controls)
                    {
                        AddControlItem(control, controls, ref id);
                    }

                    controls.children.Sort((a, b) => string.Compare(a.displayName, b.displayName));
                }

                return(item);
            }
示例#22
0
        private void InitializeCompositeProperties()
        {
            // Find name of current composite.
            var path = m_PathProperty.stringValue;
            var compositeNameAndParameters = InputControlLayout.ParseNameAndParameters(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);
            }
        }
示例#23
0
        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 = InputControlLayout.ParseNameAndParameters(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;
        }
        private void AddControlTreeItemsRecursive(InputControlLayout layout, AdvancedDropdownItem parent, string prefix, string deviceControlId, string commonUsage)
        {
            foreach (var control in layout.controls.OrderBy(a => a.name))
            {
                if (control.isModifyingChildControlByPath)
                {
                    continue;
                }

                // Skip variants except the default variant and variants dictated by the layout itself.
                if (!control.variants.IsEmpty() && control.variants != InputControlLayout.DefaultVariant &&
                    (layout.variants.IsEmpty() || !InputControlLayout.VariantsMatch(layout.variants, control.variants)))
                {
                    continue;
                }

                var child = new ControlTreeViewItem(control, prefix, deviceControlId, commonUsage);

                if (LayoutMatchesExpectedControlLayoutFilter(control.layout))
                {
                    parent.AddChild(child);
                }

                var childLayout = EditorInputControlLayoutCache.TryGetLayout(control.layout);
                if (childLayout != null)
                {
                    AddControlTreeItemsRecursive(childLayout, parent, child.controlPath, deviceControlId, commonUsage);
                }
            }

            // Add optional layouts for devices
            var optionalLayouts = EditorInputControlLayoutCache.GetOptionalControlsForLayout(layout.name);

            if (optionalLayouts.Any() && layout.isDeviceLayout)
            {
                var optionalGroup = new AdvancedDropdownItem("Optional");
                foreach (var optionalLayout in optionalLayouts)
                {
                    if (LayoutMatchesExpectedControlLayoutFilter(optionalLayout.layout))
                    {
                        optionalGroup.AddChild(new OptionalControlTreeViewItem(optionalLayout, deviceControlId, commonUsage));
                    }
                }
                if (optionalGroup.children.Any())
                {
                    parent.AddChild(optionalGroup);
                }
            }
        }
示例#25
0
        private InputControl InsertChildControl(InputControlLayout layout, InternedString variant, InputControl parent,
                                                ref bool haveChildrenUsingStateFromOtherControls,
                                                ref InputControlLayout.ControlItem controlItem)
        {
            var path = controlItem.name.ToString();

            // First we need to find the immediate parent from the given path.
            var indexOfSlash = path.LastIndexOf('/');

            if (indexOfSlash == -1)
            {
                throw new ArgumentException("InsertChildControl has to be called with a slash-separated path", "path");
            }
            Debug.Assert(indexOfSlash != 0);
            var immediateParentPath = path.Substring(0, indexOfSlash);
            var immediateParent     = InputControlPath.TryFindChild(parent, immediateParentPath);

            if (immediateParent == null)
            {
                throw new Exception(
                          string.Format("Cannot find parent '{0}' of control '{1}' in layout '{2}'", immediateParentPath,
                                        controlItem.name, layout.name));
            }

            var controlName = path.Substring(indexOfSlash + 1);

            if (controlName.Length == 0)
            {
                throw new Exception(
                          string.Format("Path cannot end in '/' (control '{0}' in layout '{1}')", controlItem.name,
                                        layout.name));
            }

            // Make room in the device's child array.
            var childStartIndex = immediateParent.m_ChildrenReadOnly.m_StartIndex;
            var childIndex      = childStartIndex + immediateParent.m_ChildrenReadOnly.m_Length;

            ArrayHelpers.InsertAt(ref m_Device.m_ChildrenForEachControl, childIndex, null);
            ++immediateParent.m_ChildrenReadOnly.m_Length;

            // Insert the child.
            var control = AddChildControl(layout, variant, immediateParent, null,
                                          ref haveChildrenUsingStateFromOtherControls, ref controlItem, ref childIndex, controlName);

            // Adjust indices of control's that have been shifted around by our insertion.
            ShiftChildIndicesInHierarchyOneUp(parent, childIndex);

            return(control);
        }
示例#26
0
        protected PropertiesReorderableList(SerializedProperty property, Action applyAction)
        {
            m_Property    = property;
            m_Apply       = applyAction;
            m_ListItems   = new List <string>();
            m_ListOptions = GetOptions();
            m_EditableParametersForSelectedItem = new ParameterListView {
                onChange = OnParametersChanged
            };
            m_ParametersForEachListItem = InputControlLayout.ParseNameAndParameterList(m_Property.stringValue)
                                          ?? new InputControlLayout.NameAndParameters[0];

            foreach (var nameAndParams in m_ParametersForEachListItem)
            {
                m_ListItems.Add(nameAndParams.name);
            }

            m_ListView = new ReorderableList(m_ListItems, typeof(string))
            {
                headerHeight          = 3,
                onAddDropdownCallback = (rect, list) =>
                {
                    var menu = new GenericMenu();
                    foreach (var name in m_ListOptions.names)
                    {
                        menu.AddItem(new GUIContent(name), false, OnAddElement, name);
                    }
                    menu.ShowAsContext();
                },
                onRemoveCallback = list =>
                {
                    var index = list.index;
                    list.list.RemoveAt(index);
                    ArrayHelpers.EraseAt(ref m_ParametersForEachListItem, index);
                    m_EditableParametersForSelectedItem.Clear();
                    m_Apply();
                    list.index = -1;
                },
                onReorderCallbackWithDetails = (list, oldIndex, newIndex) =>
                {
                    MemoryHelpers.Swap(ref m_ParametersForEachListItem[oldIndex],
                                       ref m_ParametersForEachListItem[newIndex]);
                    OnSelection(list);
                    m_Apply();
                },
                onSelectCallback = OnSelection
            };
        }
示例#27
0
        private int ResolveInteractions(string interactionString)
        {
            ////REVIEW: We're piggybacking off the processor parsing here as the two syntaxes are identical. Might consider
            ////        moving the logic to a shared place.
            ////        Alternatively, may split the paths. May help in getting rid of unnecessary allocations.

            var firstInteractionIndex = totalInteractionCount;

            if (!InputControlLayout.ParseNameAndParameterList(interactionString, ref m_Parameters))
            {
                return(firstInteractionIndex);
            }

            for (var i = 0; i < m_Parameters.Count; ++i)
            {
                // Look up interaction.
                var type = InputInteraction.s_Interactions.LookupTypeRegistration(m_Parameters[i].name);
                if (type == null)
                {
                    throw new Exception(string.Format(
                                            "No interaction with name '{0}' (mentioned in '{1}') has been registered", m_Parameters[i].name,
                                            interactionString));
                }

                // Instantiate it.
                var interaction = Activator.CreateInstance(type) as IInputInteraction;
                if (interaction == null)
                {
                    throw new Exception(string.Format("Interaction '{0}' is not an IInputInteraction", m_Parameters[i].name));
                }

                // Pass parameters to it.
                InputDeviceBuilder.SetParameters(interaction, m_Parameters[i].parameters);

                // Add to list.
                var interactionStateCount = totalInteractionCount;
                ArrayHelpers.AppendWithCapacity(ref interactionStates, ref interactionStateCount,
                                                new InputActionMapState.InteractionState
                {
                    phase = InputActionPhase.Waiting
                });
                ArrayHelpers.AppendWithCapacity(ref interactions, ref totalInteractionCount, interaction);
                Debug.Assert(interactionStateCount == totalInteractionCount);
            }

            return(firstInteractionIndex);
        }
        private bool ShouldIncludeDeviceLayout(InputControlLayout layout)
        {
            if (layout.hideInUI)
            {
                return(false);
            }

            // By default, if a device has no (usable) controls, we don't want it listed in the control picker
            // except if we're picking devices.
            if (!layout.controls.Any(x => LayoutMatchesExpectedControlLayoutFilter(x.layout)) && layout.controls.Any(x => true) &&
                m_Mode != InputControlPicker.Mode.PickDevice)
            {
                return(false);
            }

            // If we have a device filter, see if we should ignore the device.
            if (m_ControlPathsToMatch != null && m_ControlPathsToMatch.Length > 0)
            {
                var matchesAnyInDeviceFilter = false;
                foreach (var entry in m_ControlPathsToMatch)
                {
                    if (entry == layout.name ||
                        InputControlLayout.s_Layouts.IsBasedOn(new InternedString(entry), layout.name))
                    {
                        matchesAnyInDeviceFilter = true;
                    }
                    else
                    {
                        ////FIXME: this also needs to work for full control paths and not just stuff like "<Gamepad>"
                        var expectedLayout = InputControlPath.TryGetDeviceLayout(entry);
                        if (!string.IsNullOrEmpty(expectedLayout) &&
                            (expectedLayout == layout.name ||
                             InputControlLayout.s_Layouts.IsBasedOn(new InternedString(expectedLayout), layout.name)))
                        {
                            matchesAnyInDeviceFilter = true;
                        }
                    }
                }

                if (!matchesAnyInDeviceFilter)
                {
                    return(false);
                }
            }

            return(true);
        }
        private void InitializeCompositeParameters()
        {
            m_CompositeParameters = new ParameterListView
            {
                onChange = OnCompositeParametersModified
            };

            var path = m_PathProperty.stringValue;
            var nameAndParameters = InputControlLayout.ParseNameAndParameters(path);

            var compositeType = InputBindingComposite.s_Composites.LookupTypeRegistration(nameAndParameters.name);

            if (compositeType != null)
            {
                m_CompositeParameters.Initialize(compositeType, nameAndParameters.parameters);
            }
        }
示例#30
0
            private TreeViewItem BuildTreeForDevice(InputControlLayout layout, TreeViewItem parent, ref int id)
            {
                var deviceRoot = new Item
                {
                    displayName = layout.name,
                    id          = id++,
                    depth       = parent.depth + 1,
                    device      = layout.name,
                    layout      = layout
                };

                parent.AddChild(deviceRoot);

                BuildControlsRecursive(deviceRoot, layout, string.Empty, ref id);

                return(deviceRoot);
            }