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 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 InputControl AddChildControl(InputTemplate template, InternedString variant, InputControl parent, ReadOnlyArray <InputControl>?existingChildren, ref bool haveChildrenUsingStateFromOtherControls, ref InputTemplate.ControlTemplate controlTemplate, ref int childIndex, string nameOverride = null) { var name = nameOverride ?? controlTemplate.name; var nameLowerCase = nameOverride != null?nameOverride.ToLower() : controlTemplate.name.ToLower(); var nameInterned = nameOverride != null ? new InternedString(nameOverride) : controlTemplate.name; ////REVIEW: can we check this in InputTemplate instead? if (string.IsNullOrEmpty(controlTemplate.template)) { throw new Exception(string.Format("Template has not been set on control '{0}' in '{1}'", controlTemplate.name, template.name)); } // 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.template == controlTemplate.template && existingChild.name.ToLower() == nameLowerCase) { existingControl = existingChild; break; } } } // Create control. InputControl control; try { control = AddControl(controlTemplate.template, variant, nameInterned, parent, existingControl); } catch (InputTemplate.TemplateNotFoundException exception) { // Throw better exception that gives more info. throw new Exception( string.Format("Cannot find template '{0}' used in control '{1}' of template '{2}'", exception.template, controlTemplate.name, template.name), exception); } // Add to array. m_Device.m_ChildrenForEachControl[childIndex] = control; ++childIndex; // Set display name. control.m_DisplayNameFromTemplate = controlTemplate.displayName; // Pass state block config on to control. var usesStateFromOtherControl = !string.IsNullOrEmpty(controlTemplate.useStateFrom); if (!usesStateFromOtherControl) { control.m_StateBlock.byteOffset = controlTemplate.offset; if (controlTemplate.bit != InputStateBlock.kInvalidOffset) { control.m_StateBlock.bitOffset = controlTemplate.bit; } if (controlTemplate.sizeInBits != 0) { control.m_StateBlock.sizeInBits = controlTemplate.sizeInBits; } if (controlTemplate.format != 0) { SetFormat(control, controlTemplate); } } 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. if (controlTemplate.usages.Count > 0) { var usageCount = controlTemplate.usages.Count; var usageIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_UsagesForEachControl, controlTemplate.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 (controlTemplate.aliases.Count > 0) { var aliasCount = controlTemplate.aliases.Count; var aliasIndex = ArrayHelpers.AppendToImmutable(ref m_Device.m_AliasesForEachControl, controlTemplate.aliases.m_Array); control.m_AliasesReadOnly = new ReadOnlyArray <InternedString>(m_Device.m_AliasesForEachControl, aliasIndex, aliasCount); } // Set parameters. if (controlTemplate.parameters.Count > 0) { SetParameters(control, controlTemplate.parameters); } // Add processors. if (controlTemplate.processors.Count > 0) { AddProcessors(control, ref controlTemplate, template.name); } return(control); }