public void AddControlItem(InputControlPickerDropdown dropdown, DeviceDropdownItem parent, ControlDropdownItem parentControl, InputControlLayout.ControlItem control, string device, string usage, bool searchable) { // for the Press control, show two variants, one for single touch presses, and another for multi-touch presses if (control.displayName == "Press") { dropdown.AddControlItem(this, parent, parentControl, new InputControlLayout.ControlItem { name = new InternedString("Press"), displayName = new InternedString("Press (Single touch)"), layout = control.layout }, device, usage, searchable); dropdown.AddControlItem(this, parent, parentControl, new InputControlLayout.ControlItem { name = new InternedString("Press"), displayName = new InternedString("Press (Multi-touch)"), layout = control.layout }, device, usage, searchable, "touch*/Press"); } else { dropdown.AddControlItem(this, parent, parentControl, control, device, usage, searchable); } }
private void AddControlItem(DeviceDropdownItem parent, ControlDropdownItem parentControl, InputControlLayout.ControlItem control, string device, string usage, bool searchable) { // If it's an array, generate a control entry for each array element. for (var i = 0; i < (control.isArray ? control.arraySize : 1); ++i) { var name = control.isArray ? control.name + i : control.name; var displayName = !string.IsNullOrEmpty(control.displayName) ? (control.isArray ? control.displayName + i : control.displayName) : name; var child = new ControlDropdownItem(parentControl, name, displayName, device, usage, searchable); child.icon = EditorInputControlLayoutCache.GetIconForLayout(control.layout); var controlLayout = EditorInputControlLayoutCache.TryGetLayout(control.layout); if (LayoutMatchesExpectedControlLayoutFilter(control.layout)) { parent.AddChild(child); } else if (controlLayout.controls.Any(x => LayoutMatchesExpectedControlLayoutFilter(x.layout))) { child.enabled = false; parent.AddChild(child); } // Add children. if (controlLayout != null) { AddControlTreeItemsRecursive(controlLayout, parent, device, usage, searchable, child); } } }
private static void AddProcessors(InputControl control, ref InputControlLayout.ControlItem controlItem, string layoutName) { var processorCount = controlItem.processors.Count; for (var n = 0; n < processorCount; ++n) { var name = controlItem.processors[n].name; var type = InputProcessor.s_Processors.LookupTypeRegistration(name); if (type == null) { throw new InvalidOperationException( $"Cannot find processor '{name}' referenced by control '{controlItem.name}' in layout '{layoutName}'"); } var processor = Activator.CreateInstance(type); var parameters = controlItem.processors[n].parameters; if (parameters.Count > 0) { NamedValue.ApplyAllToObject(processor, parameters); } control.AddProcessor(processor); } }
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); }
private static void AddProcessors(InputControl control, ref InputControlLayout.ControlItem controlItem, string layoutName) { var processorCount = controlItem.processors.Count; for (var n = 0; n < processorCount; ++n) { var name = controlItem.processors[n].name; var type = InputControlProcessor.s_Processors.LookupTypeRegistration(name); if (type == null) { throw new Exception( string.Format("Cannot find processor '{0}' referenced by control '{1}' in layout '{2}'", name, controlItem.name, layoutName)); } var processor = Activator.CreateInstance(type); var parameters = controlItem.processors[n].parameters; if (parameters.Count > 0) { SetParameters(processor, parameters); } control.AddProcessor(processor); } }
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); } }
private static bool ControlLayoutMatchesPathComponent(ref InputControlLayout.ControlItem controlItem, ref PathParser parser) { // Match layout. var layout = parser.current.layout; if (layout.length > 0) { if (!StringMatches(layout, controlItem.layout)) { return(false); } } // Match usage. if (parser.current.usages != null) { // All of usages should match to the one of usage in the control for (int usageIndex = 0; usageIndex < parser.current.usages.Length; ++usageIndex) { var usage = parser.current.usages[usageIndex]; if (usage.length > 0) { var usageCount = controlItem.usages.Count; var anyUsageMatches = false; for (var i = 0; i < usageCount; ++i) { if (StringMatches(usage, controlItem.usages[i])) { anyUsageMatches = true; break; } } if (!anyUsageMatches) { return(false); } } } } // Match name. var name = parser.current.name; if (name.length > 0) { if (!StringMatches(name, controlItem.name)) { return(false); } } return(true); }
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); }
private static void SetFormat(InputControl control, InputControlLayout.ControlItem controlItem) { control.m_StateBlock.format = controlItem.format; if (controlItem.sizeInBits == 0) { var primitiveFormatSize = InputStateBlock.GetSizeOfPrimitiveFormatInBits(controlItem.format); if (primitiveFormatSize != -1) { control.m_StateBlock.sizeInBits = (uint)primitiveFormatSize; } } }
public ControlTreeViewItem(InputControlLayout.ControlItem control, string prefix, string deviceId, string usage) { m_Device = deviceId; m_Usage = usage; if (!string.IsNullOrEmpty(prefix)) { m_ControlPath = prefix + "/"; displayName = prefix + "/"; } m_ControlPath += control.name; displayName += control.name; id = controlPathWithDevice.GetHashCode(); }
public ControlTreeViewItem(InputControlLayout.ControlItem control, string prefix, string deviceId, string usage) : base("") { m_Device = deviceId; m_Usage = usage; if (!string.IsNullOrEmpty(prefix)) { m_ControlPath = prefix + "/"; name = prefix + "/"; } m_ControlPath += control.name; name += control.name; id = controlPathWithDevice.GetHashCode(); m_SearchableName = InputControlPath.ToHumanReadableString(controlPathWithDevice); }
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); }
private void AddControlItem(InputControlLayout.ControlItem control, TreeViewItem parent, ref int id) { var item = AddChild(parent, control.variants.IsEmpty() ? control.name : string.Format("{0} ({1})", control.name, control.variants), ref id); ////TODO: fully merge TreeViewItems from isModifyingChildControlByPath control layouts into the control they modify ////TODO: allow clicking this field to jump to the layout if (!control.layout.IsEmpty()) AddChild(item, string.Format("Layout: {0}", control.layout), ref id); if (!control.variants.IsEmpty()) AddChild(item, string.Format("Variant: {0}", control.variants), ref id); if (control.format != 0) AddChild(item, string.Format("Format: {0}", control.format), ref id); if (control.offset != InputStateBlock.kInvalidOffset) AddChild(item, string.Format("Offset: {0}", control.offset), ref id); if (control.bit != InputStateBlock.kInvalidOffset) AddChild(item, string.Format("Bit: {0}", control.bit), ref id); if (control.sizeInBits != 0) AddChild(item, string.Format("Size In Bits: {0}", control.sizeInBits), ref id); if (control.isArray) AddChild(item, string.Format("Array Size: {0}", control.arraySize), ref id); if (!string.IsNullOrEmpty(control.useStateFrom)) AddChild(item, string.Format("Use State From: {0}", control.useStateFrom), ref id); if (control.usages.Count > 0) AddChild(item, "Usages: " + string.Join(", ", control.usages.Select(x => x.ToString()).ToArray()), ref id); if (control.aliases.Count > 0) AddChild(item, "Aliases: " + string.Join(", ", control.aliases.Select(x => x.ToString()).ToArray()), ref id); if (control.parameters.Count > 0) { var parameters = AddChild(item, "Parameters", ref id); foreach (var parameter in control.parameters) AddChild(parameters, parameter.ToString(), ref id); } if (control.processors.Count > 0) { var processors = AddChild(item, "Processors", ref id); foreach (var processor in control.processors) { var processorItem = AddChild(processors, processor.name, ref id); foreach (var parameter in processor.parameters) AddChild(processorItem, parameter.ToString(), ref id); } } }
private static bool ControlLayoutMatchesPathComponent(ref InputControlLayout.ControlItem controlItem, ref PathParser parser) { // Match layout. var layout = parser.current.layout; if (layout.length > 0) { if (!StringMatches(layout, controlItem.layout)) { return(false); } } // Match usage. var usage = parser.current.usage; if (usage.length > 0) { var usageCount = controlItem.usages.Count; var anyUsageMatches = false; for (var i = 0; i < usageCount; ++i) { if (StringMatches(usage, controlItem.usages[i])) { anyUsageMatches = true; break; } } if (!anyUsageMatches) { return(false); } } // Match name. var name = parser.current.name; if (name.length > 0) { if (!StringMatches(name, controlItem.name)) { return(false); } } return(true); }
private static void AddOptionalControlRecursive(InternedString layoutName, ref InputControlLayout.ControlItem controlItem) { Debug.Assert(!controlItem.isModifyingChildControlByPath); Debug.Assert(!controlItem.layout.IsEmpty()); // Recurse into base. InternedString baseLayoutName; if (InputControlLayout.s_Layouts.baseLayoutTable.TryGetValue(layoutName, out baseLayoutName)) { AddOptionalControlRecursive(baseLayoutName, ref controlItem); } // See if we already have this optional control. List <OptionalControl> list; var alreadyPresent = false; if (!s_OptionalControls.TryGetValue(layoutName, out list)) { list = new List <OptionalControl>(); s_OptionalControls[layoutName] = list; } else { // See if we already have this control. foreach (var item in list) { if (item.name == controlItem.name && item.layout == controlItem.layout) { alreadyPresent = true; break; } } } if (!alreadyPresent) { list.Add(new OptionalControl { name = controlItem.name, layout = controlItem.layout }); } }
private void InsertChildControlOverrides(InputControl parent, ref InputControlLayout.ControlItem controlItem) { if (m_ChildControlOverrides == null) { m_ChildControlOverrides = new Dictionary <string, InputControlLayout.ControlItem>(); } var path = InputControlPath.Combine(parent, controlItem.name); var pathLowerCase = path.ToLower(); // See if there are existing overrides for the control. if (!m_ChildControlOverrides.TryGetValue(pathLowerCase, out var existingOverrides)) { // So, so just insert our overrides and we're done. m_ChildControlOverrides[pathLowerCase] = controlItem; return; } // Yes, there's existing overrides so we have to merge. existingOverrides = existingOverrides.Merge(controlItem); m_ChildControlOverrides[pathLowerCase] = existingOverrides; }
private void InsertChildControlOverride(InputControl parent, ref InputControlLayout.ControlItem controlItem) { if (m_ChildControlOverrides == null) { m_ChildControlOverrides = new Dictionary <string, InputControlLayout.ControlItem>(); } var path = InputControlPath.Combine(parent, controlItem.name); var pathLowerCase = path.ToLower(); // See if there are existing overrides for the control. if (!m_ChildControlOverrides.TryGetValue(pathLowerCase, out var existingOverrides)) { // So, so just insert our overrides and we're done. m_ChildControlOverrides[pathLowerCase] = controlItem; return; } // Yes, there's existing overrides so we have to merge. // NOTE: The existing override's properties take precedence here. This is because // the override has been established from higher up in the layout hierarchy. existingOverrides = existingOverrides.Merge(controlItem); m_ChildControlOverrides[pathLowerCase] = existingOverrides; }
private InputControl AddChildControl(InputControlLayout layout, InternedString variant, InputControl parent, ReadOnlyArray <InputControl>?existingChildren, ref bool haveChildrenUsingStateFromOtherControls, ref InputControlLayout.ControlItem controlItem, ref int childIndex, string nameOverride = null) { var name = nameOverride ?? controlItem.name; var nameLowerCase = name.ToLower(); var nameInterned = new InternedString(name); string path = null; ////REVIEW: can we check this in InputControlLayout instead? if (string.IsNullOrEmpty(controlItem.layout)) { throw new Exception(string.Format("Layout has not been set on control '{0}' in '{1}'", controlItem.name, layout.name)); } // See if there is an override for the control. InputControlLayout.ControlItem?controlOverride = null; if (m_ChildControlOverrides != null) { path = string.Format("{0}/{1}", parent.path, name); var pathLowerCase = path.ToLower(); InputControlLayout.ControlItem match; if (m_ChildControlOverrides.TryGetValue(pathLowerCase, out match)) { controlOverride = match; } } // Get name of layout to use for control. var layoutName = controlItem.layout; if (controlOverride != null && !controlOverride.Value.layout.IsEmpty()) { layoutName = controlOverride.Value.layout; } // See if we have an existing control that we might be able to re-use. InputControl existingControl = null; if (existingChildren != null) { var existingChildCount = existingChildren.Value.Count; for (var n = 0; n < existingChildCount; ++n) { var existingChild = existingChildren.Value[n]; if (existingChild.layout == layoutName && existingChild.name.ToLower() == nameLowerCase) { existingControl = existingChild; break; } } } // Create control. InputControl control; try { control = InstantiateLayout(layoutName, variant, nameInterned, parent, existingControl); } catch (InputControlLayout.LayoutNotFoundException exception) { // Throw better exception that gives more info. throw new Exception( string.Format("Cannot find layout '{0}' used in control '{1}' of layout '{2}'", exception.layout, name, layout.name), exception); } // Add to array. m_Device.m_ChildrenForEachControl[childIndex] = control; ++childIndex; // Set display name. control.m_DisplayNameFromLayout = controlItem.displayName; // Set flags. control.m_IsNoisy = controlItem.isNoisy; // Pass state block config on to control. var usesStateFromOtherControl = !string.IsNullOrEmpty(controlItem.useStateFrom); if (!usesStateFromOtherControl) { control.m_StateBlock.byteOffset = controlItem.offset; if (controlItem.bit != InputStateBlock.kInvalidOffset) { control.m_StateBlock.bitOffset = controlItem.bit; } if (controlItem.sizeInBits != 0) { control.m_StateBlock.sizeInBits = controlItem.sizeInBits; } if (controlItem.format != 0) { SetFormat(control, controlItem); } } else { // Mark controls that don't have state blocks of their own but rather get their // blocks from other controls by setting their state size to kInvalidOffset. control.m_StateBlock.sizeInBits = kSizeForControlUsingStateFromOtherControl; haveChildrenUsingStateFromOtherControls = true; } ////REVIEW: the constant appending to m_UsagesForEachControl and m_AliasesForEachControl may lead to a lot //// of successive re-allocations // Add usages. var usages = controlOverride != null ? controlOverride.Value.usages : controlItem.usages; if (usages.Count > 0) { var usageCount = usages.Count; var usageIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_UsagesForEachControl, usages.m_Array); control.m_UsagesReadOnly = new ReadOnlyArray <InternedString>(m_Device.m_UsagesForEachControl, usageIndex, usageCount); ArrayHelpers.GrowBy(ref m_Device.m_UsageToControl, usageCount); for (var n = 0; n < usageCount; ++n) { m_Device.m_UsageToControl[usageIndex + n] = control; } } // Add aliases. if (controlItem.aliases.Count > 0) { var aliasCount = controlItem.aliases.Count; var aliasIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_AliasesForEachControl, controlItem.aliases.m_Array); control.m_AliasesReadOnly = new ReadOnlyArray <InternedString>(m_Device.m_AliasesForEachControl, aliasIndex, aliasCount); } // Set parameters. if (controlItem.parameters.Count > 0) { SetParameters(control, controlItem.parameters); } // Add processors. if (controlItem.processors.Count > 0) { AddProcessors(control, ref controlItem, layout.name); } return(control); }
private void AddControlItem(InputControlLayout.ControlItem control, TreeViewItem parent, ref int id) { var item = AddChild(parent, control.variants.IsEmpty() ? control.name : string.Format("{0} ({1})", control.name, control.variants), ref id); if (!control.layout.IsEmpty()) { item.icon = EditorInputControlLayoutCache.GetIconForLayout(control.layout); } ////TODO: fully merge TreeViewItems from isModifyingExistingControl control layouts into the control they modify ////TODO: allow clicking this field to jump to the layout if (!control.layout.IsEmpty()) { AddChild(item, $"Layout: {control.layout}", ref id); } if (!control.variants.IsEmpty()) { AddChild(item, $"Variant: {control.variants}", ref id); } if (!string.IsNullOrEmpty(control.displayName)) { AddChild(item, $"Display Name: {control.displayName}", ref id); } if (!string.IsNullOrEmpty(control.shortDisplayName)) { AddChild(item, $"Short Display Name: {control.shortDisplayName}", ref id); } if (control.format != 0) { AddChild(item, $"Format: {control.format}", ref id); } if (control.offset != InputStateBlock.InvalidOffset) { AddChild(item, $"Offset: {control.offset}", ref id); } if (control.bit != InputStateBlock.InvalidOffset) { AddChild(item, $"Bit: {control.bit}", ref id); } if (control.sizeInBits != 0) { AddChild(item, $"Size In Bits: {control.sizeInBits}", ref id); } if (control.isArray) { AddChild(item, $"Array Size: {control.arraySize}", ref id); } if (!string.IsNullOrEmpty(control.useStateFrom)) { AddChild(item, $"Use State From: {control.useStateFrom}", ref id); } if (!control.defaultState.isEmpty) { AddChild(item, $"Default State: {control.defaultState.ToString()}", ref id); } if (!control.minValue.isEmpty) { AddChild(item, $"Min Value: {control.minValue.ToString()}", ref id); } if (!control.maxValue.isEmpty) { AddChild(item, $"Max Value: {control.maxValue.ToString()}", ref id); } if (control.usages.Count > 0) { AddChild(item, "Usages: " + string.Join(", ", control.usages.Select(x => x.ToString()).ToArray()), ref id); } if (control.aliases.Count > 0) { AddChild(item, "Aliases: " + string.Join(", ", control.aliases.Select(x => x.ToString()).ToArray()), ref id); } if (control.isNoisy || control.isSynthetic) { var flags = "Flags: "; if (control.isNoisy) { flags += "Noisy"; } if (control.isSynthetic) { if (control.isNoisy) { flags += ", Synthetic"; } else { flags += "Synthetic"; } } AddChild(item, flags, ref id); } if (control.parameters.Count > 0) { var parameters = AddChild(item, "Parameters", ref id); foreach (var parameter in control.parameters) { AddChild(parameters, parameter.ToString(), ref id); } } if (control.processors.Count > 0) { var processors = AddChild(item, "Processors", ref id); foreach (var processor in control.processors) { var processorItem = AddChild(processors, processor.name, ref id); foreach (var parameter in processor.parameters) { AddChild(processorItem, parameter.ToString(), ref id); } } } }
private InputControl AddChildControl(InputControlLayout layout, InternedString variants, InputControl parent, ref bool haveChildrenUsingStateFromOtherControls, InputControlLayout.ControlItem controlItem, int childIndex, string nameOverride = null) { var name = nameOverride ?? controlItem.name; var nameInterned = new InternedString(name); ////REVIEW: can we check this in InputControlLayout instead? if (string.IsNullOrEmpty(controlItem.layout)) { throw new InvalidOperationException($"Layout has not been set on control '{controlItem.name}' in '{layout.name}'"); } // See if there is an override for the control. if (m_ChildControlOverrides != null) { var path = $"{parent.path}/{name}"; var pathLowerCase = path.ToLower(); if (m_ChildControlOverrides.TryGetValue(pathLowerCase, out var controlOverride)) { controlItem = controlOverride.Merge(controlItem); } } // Get name of layout to use for control. var layoutName = controlItem.layout; // Create control. InputControl control; try { control = InstantiateLayout(layoutName, variants, nameInterned, parent); } catch (InputControlLayout.LayoutNotFoundException exception) { // Throw better exception that gives more info. throw new InputControlLayout.LayoutNotFoundException( $"Cannot find layout '{exception.layout}' used in control '{name}' of layout '{layout.name}'", exception); } // Add to array. // NOTE: AddChildControls and InstantiateLayout take care of growing the array and making // room for the immediate children of each control. m_Device.m_ChildrenForEachControl[childIndex] = control; // Set flags and misc things. control.noisy = controlItem.isNoisy; control.synthetic = controlItem.isSynthetic; if (control.noisy) { m_Device.noisy = true; } // Remember the display names from the layout. We later do a proper pass once we have // the full hierarchy to set final names. control.m_DisplayNameFromLayout = controlItem.displayName; control.m_ShortDisplayNameFromLayout = controlItem.shortDisplayName; // Set default value. control.m_DefaultState = controlItem.defaultState; if (!control.m_DefaultState.isEmpty) { m_Device.hasControlsWithDefaultState = true; } // Set min and max value. Don't just overwrite here as the control's constructor may // have set a default value. if (!controlItem.minValue.isEmpty) { control.m_MinValue = controlItem.minValue; } if (!controlItem.maxValue.isEmpty) { control.m_MaxValue = controlItem.maxValue; } // Pass state block config on to control. var usesStateFromOtherControl = !string.IsNullOrEmpty(controlItem.useStateFrom); if (!usesStateFromOtherControl) { control.m_StateBlock.byteOffset = controlItem.offset; control.m_StateBlock.bitOffset = controlItem.bit; if (controlItem.sizeInBits != 0) { control.m_StateBlock.sizeInBits = controlItem.sizeInBits; } if (controlItem.format != 0) { SetFormat(control, controlItem); } } else { // Mark controls that don't have state blocks of their own but rather get their // blocks from other controls by setting their state size to InvalidOffset. control.m_StateBlock.sizeInBits = kSizeForControlUsingStateFromOtherControl; haveChildrenUsingStateFromOtherControls = true; } ////REVIEW: the constant appending to m_UsagesForEachControl and m_AliasesForEachControl may lead to a lot //// of successive re-allocations // Add usages. var usages = controlItem.usages; if (usages.Count > 0) { var usageCount = usages.Count; var usageIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_UsagesForEachControl, usages.m_Array); control.m_UsageStartIndex = usageIndex; control.m_UsageCount = usageCount; ArrayHelpers.GrowBy(ref m_Device.m_UsageToControl, usageCount); for (var n = 0; n < usageCount; ++n) { m_Device.m_UsageToControl[usageIndex + n] = control; } } // Add aliases. if (controlItem.aliases.Count > 0) { var aliasCount = controlItem.aliases.Count; var aliasIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_AliasesForEachControl, controlItem.aliases.m_Array); control.m_AliasStartIndex = aliasIndex; control.m_AliasCount = aliasCount; } // Set parameters. if (controlItem.parameters.Count > 0) { NamedValue.ApplyAllToObject(control, controlItem.parameters); } // Add processors. if (controlItem.processors.Count > 0) { AddProcessors(control, ref controlItem, layout.name); } return(control); }
private void ModifyChildControl(InputControlLayout layout, InternedString variants, InputControl parent, ref bool haveChildrenUsingStateFromOtherControls, ref InputControlLayout.ControlItem controlItem) { ////TODO: support arrays (we may modify an entire array in bulk) // Controls layout themselves as we come back up the hierarchy. However, when we // apply layout modifications reaching *into* the hierarchy, we need to retrigger // layouting on their parents. var haveChangedLayoutOfParent = false; // Find the child control. var child = InputControlPath.TryFindChild(parent, controlItem.name); if (child == null) { // 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); haveChangedLayoutOfParent = true; } else { // Apply modifications. if (controlItem.sizeInBits != 0 && child.m_StateBlock.sizeInBits != controlItem.sizeInBits) { child.m_StateBlock.sizeInBits = controlItem.sizeInBits; } if (controlItem.format != 0 && child.m_StateBlock.format != controlItem.format) { SetFormat(child, controlItem); haveChangedLayoutOfParent = true; } ////REVIEW: ATM, when you move a child with a fixed offset, we only move the child //// and don't move the parent or siblings. What this means is that if you move //// leftStick/x, for example, leftStick stays put. ATM you have to move *all* //// controls that are part of a chain manually. Not sure what the best behavior //// is. If we opt to move parents along with children, we have to make sure we //// are not colliding with any other relocations of children (e.g. if you move //// both leftStick/x and leftStick/y, leftStick itself should move only once and //// not at all if there indeed is a leftStick control layout with an offset; //// so, it'd get quite complicated) if (controlItem.offset != InputStateBlock.InvalidOffset) { child.m_StateBlock.byteOffset = controlItem.offset; } if (controlItem.bit != InputStateBlock.InvalidOffset) { child.m_StateBlock.bitOffset = controlItem.bit; } if (controlItem.processors.Count > 0) { AddProcessors(child, ref controlItem, layout.name); } ////REVIEW: ATM parameters applied using this path add on top instead of just overriding existing parameters if (controlItem.parameters.Count > 0) { NamedValue.ApplyAllToObject(child, controlItem.parameters); } if (!string.IsNullOrEmpty(controlItem.displayName)) { child.m_DisplayNameFromLayout = controlItem.displayName; } if (!controlItem.defaultState.isEmpty) { child.m_DefaultValue = controlItem.defaultState; m_Device.hasControlsWithDefaultState = true; } if (!controlItem.minValue.isEmpty) { child.m_MinValue = controlItem.minValue; } if (!controlItem.maxValue.isEmpty) { child.m_MaxValue = controlItem.maxValue; } ////TODO: other modifications } // Apply layout change. ////REVIEW: not sure what's better here; trigger this immediately means we may trigger //// it a number of times on the same parent but doing it as a final pass would //// require either collecting the necessary parents or doing another pass through //// the list of control layouts if (haveChangedLayoutOfParent && !ReferenceEquals(child.parent, parent)) { ComputeStateLayout(child.parent); } }
public void AddControlItem(InputControlPickerDropdown dropdown, DeviceDropdownItem parent, ControlDropdownItem parentControl, InputControlLayout.ControlItem control, string device, string usage, bool searchable) { dropdown.AddControlItem(this, parent, parentControl, control, device, usage, searchable); }