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); } } }
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 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); } } }
private void AddDeviceTreeItemRecursive(InputControlLayout layout, AdvancedDropdownItem parent, bool searchable = true) { // Find all layouts directly based on this one. var childLayouts = EditorInputControlLayoutCache.allLayouts .Where(x => x.isDeviceLayout && !x.hideInUI && x.baseLayouts.Contains(layout.name)).OrderBy(x => x.displayName); // See if the entire tree should be excluded. var shouldIncludeDeviceLayout = ShouldIncludeDeviceLayout(layout); var shouldIncludeAtLeastOneChildLayout = childLayouts.Any(ShouldIncludeDeviceLayout); if (!shouldIncludeDeviceLayout && !shouldIncludeAtLeastOneChildLayout) { return; } // Add toplevel item for device. var deviceItem = new DeviceDropdownItem(layout, searchable: searchable); parent.AddChild(deviceItem); // Add common usage variants. if (m_Mode != InputControlPicker.Mode.PickDevice && layout.commonUsages.Count > 0) { foreach (var usage in layout.commonUsages) { var usageItem = new DeviceDropdownItem(layout, usage); AddControlTreeItemsRecursive(layout, usageItem, layout.name, usage, searchable); deviceItem.AddChild(usageItem); } deviceItem.AddSeparator(); } // Add controls. var haveControls = false; if (shouldIncludeDeviceLayout && m_Mode != InputControlPicker.Mode.PickDevice) { var childCountBefore = deviceItem.children.Count(); // The keyboard is special in that we want to allow binding by display name (i.e. character // generated by a key) instead of only by physical key location. Also, we want to give an indication // of which specific key an entry refers to by taking the current keyboard layout into account. // // So what we do is add an extra level to the keyboard where key's can be bound by character // according to the current layout. And in the top level of the keyboard we display keys with // both physical and logical names. if (layout.type == typeof(Keyboard) && Keyboard.current != null) { var byLocationGroup = new AdvancedDropdownItem("By Location of Key (Using US Layout)"); var byCharacterGroup = new AdvancedDropdownItem("By Character Mapped to Key"); deviceItem.AddChild(byLocationGroup); deviceItem.AddChild(byCharacterGroup); var keyboard = Keyboard.current; AddCharacterKeyBindingsTo(byCharacterGroup, keyboard); AddPhysicalKeyBindingsTo(byLocationGroup, keyboard, searchable); } else { AddControlTreeItemsRecursive(layout, deviceItem, layout.name, null, searchable); } haveControls = deviceItem.children.Count() != childCountBefore; } // Add child items. var isFirstChild = true; foreach (var childLayout in childLayouts) { if (!ShouldIncludeDeviceLayout(childLayout)) { continue; } if (isFirstChild && haveControls) { deviceItem.AddSeparator("More Specific " + deviceItem.name.GetPlural()); } isFirstChild = false; AddDeviceTreeItemRecursive(childLayout, deviceItem, searchable && !childLayout.isGenericTypeOfDevice); } // When picking devices, it must be possible to select a device that itself has more specific types // of devices underneath it. However in the dropdown, such a device will be a foldout and not itself // be selectable. We solve this problem by adding an entry for the device underneath the device // itself (e.g. "Gamepad >> Gamepad"). if (m_Mode == InputControlPicker.Mode.PickDevice && deviceItem.m_Children.Count > 0) { var item = new DeviceDropdownItem(layout); deviceItem.m_Children.Insert(0, item); } }
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); }