private unsafe void AddActionItem(TreeViewItem parent, InputAction action, ref int id) { // Add item for action. var name = action.actionMap != null ? $"{action.actionMap.name}/{action.name}" : action.name; if (!action.enabled) { name += " (Disabled)"; } var item = AddChild(parent, name, ref id); // Grab state. var actionMap = action.GetOrCreateActionMap(); actionMap.ResolveBindingsIfNecessary(); var state = actionMap.m_State; // Add list of resolved controls. var actionIndex = action.m_ActionIndexInState; var totalBindingCount = state.totalBindingCount; for (var i = 0; i < totalBindingCount; ++i) { ref var bindingState = ref state.bindingStates[i]; if (bindingState.actionIndex != actionIndex) { continue; } if (bindingState.isComposite) { continue; } var binding = state.GetBinding(i); var controlCount = bindingState.controlCount; var controlStartIndex = bindingState.controlStartIndex; for (var n = 0; n < controlCount; ++n) { var control = state.controls[controlStartIndex + n]; var interactions = StringHelpers.Join(new[] { binding.effectiveInteractions, action.interactions }, ","); var text = control.path; if (!string.IsNullOrEmpty(interactions)) { var namesAndParameters = NameAndParameters.ParseMultiple(interactions); text += " ["; text += string.Join(",", namesAndParameters.Select(x => x.name)); text += "]"; } AddChild(item, text, ref id); } }
protected NameAndParameterListView(SerializedProperty property, Action applyAction, string expectedControlLayout, TypeTable listOptions, Func <Type, Type> getValueType, string itemName) { m_ItemName = itemName; m_GetValueType = getValueType; m_DeleteButton = EditorGUIUtility.TrIconContent("Toolbar Minus", $"Delete {itemName}"); m_UpButton = EditorGUIUtility.TrIconContent(GUIHelpers.LoadIcon("ChevronUp"), $"Move {itemName} up"); m_DownButton = EditorGUIUtility.TrIconContent(GUIHelpers.LoadIcon("ChevronDown"), $"Move {itemName} down"); m_Property = property; m_Apply = applyAction; m_ListOptions = listOptions; m_ExpectedControlLayout = expectedControlLayout; if (!string.IsNullOrEmpty(m_ExpectedControlLayout)) { m_ExpectedValueType = EditorInputControlLayoutCache.GetValueType(m_ExpectedControlLayout); } m_ParametersForEachListItem = NameAndParameters.ParseMultiple(m_Property.stringValue).ToArray(); m_EditableParametersForEachListItem = new ParameterListView[m_ParametersForEachListItem.Length]; for (var i = 0; i < m_ParametersForEachListItem.Length; i++) { m_EditableParametersForEachListItem[i] = new ParameterListView { onChange = OnParametersChanged }; var typeName = m_ParametersForEachListItem[i].name; var rowType = m_ListOptions.LookupTypeRegistration(typeName); m_EditableParametersForEachListItem[i].Initialize(rowType, m_ParametersForEachListItem[i].parameters); var name = ObjectNames.NicifyVariableName(typeName); ////REVIEW: finding this kind of stuff should probably have better support globally on the asset; e.g. some //// notification that pops up and allows fixing all occurrences in one click // Find out if we still support this option and indicate it in the list, if we don't. if (rowType == null) { name += " (Obsolete)"; } else if (m_ExpectedValueType != null) { var valueType = getValueType(rowType); if (!m_ExpectedValueType.IsAssignableFrom(valueType)) { name += " (Ignored)"; } } m_EditableParametersForEachListItem[i].name = name; } }
public void Utilities_CanParseMultipleNameAndParameterLists() { Assert.That(NameAndParameters.ParseMultiple("a,b").Count(), Is.EqualTo(2)); Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[0].name, Is.EqualTo("a")); Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[0].parameters, Is.Empty); Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[1].name, Is.EqualTo("b")); Assert.That(NameAndParameters.ParseMultiple("a,b").ToArray()[1].parameters, Is.Empty); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").Count(), Is.EqualTo(3)); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[0].name, Is.EqualTo("a")); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[0].parameters, Is.Empty); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[1].name, Is.EqualTo("b")); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[1].parameters, Has.Count.EqualTo(2)); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[2].name, Is.EqualTo("c")); Assert.That(NameAndParameters.ParseMultiple("a,b(r=1,t),c").ToArray()[2].parameters, Is.Empty); Assert.That(NameAndParameters.ParseMultiple("a(b,c=123)").Count(), Is.EqualTo(1)); }
public ModifyPopupWindow(SerializedProperty bindingProperty) { m_FlagsProperty = bindingProperty.FindPropertyRelative("m_Flags"); m_InteractionsProperty = bindingProperty.FindPropertyRelative("m_Interactions"); m_Flags = (InputBinding.Flags)m_FlagsProperty.intValue; var interactions = InputSystem.ListInteractions().ToList(); interactions.Sort(); m_InteractionChoices = interactions.Select(x => new GUIContent(x)).ToArray(); var interactionString = m_InteractionsProperty.stringValue; if (!string.IsNullOrEmpty(interactionString)) { m_Interactions = NameAndParameters.ParseMultiple(interactionString).ToArray(); } else { m_Interactions = new NameAndParameters[0]; } InitializeInteractionListView(); }
////TODO: move this out into a general routine that can take a path and construct a display name private static GUIContent GetContentForPath(string path, string interactions, InputBinding.Flags flags) { const int kUsageNameGroup = 1; const int kDeviceNameGroup = 1; const int kDeviceUsageGroup = 3; const int kControlPathGroup = 4; ////TODO: nuke the regex stuff in here if (s_UsageRegex == null) { s_UsageRegex = new Regex("\\*/{([A-Za-z0-9]+)}"); } if (s_ControlRegex == null) { s_ControlRegex = new Regex("<([A-Za-z0-9:\\-]+)>({([A-Za-z0-9]+)})?/([A-Za-z0-9]+(/[A-Za-z0-9]+)*)"); } var text = path; var usageMatch = s_UsageRegex.Match(path); if (usageMatch.Success) { text = usageMatch.Groups[kUsageNameGroup].Value; } else { var controlMatch = s_ControlRegex.Match(path); if (controlMatch.Success) { var device = controlMatch.Groups[kDeviceNameGroup].Value; var deviceUsage = controlMatch.Groups[kDeviceUsageGroup].Value; var control = controlMatch.Groups[kControlPathGroup].Value; ////TODO: would be nice to include layout name to print something like "Gamepad A Button" instead of "Gamepad A" (or whatever) if (!string.IsNullOrEmpty(deviceUsage)) { text = $"{deviceUsage} {device} {control}"; } else { text = $"{device} {control}"; } } } ////REVIEW: would be nice to have icons for these // Show interactions. if (!string.IsNullOrEmpty(interactions)) { var interactionList = NameAndParameters.ParseMultiple(interactions); var interactionString = string.Join(" OR ", interactionList.Select(x => x.name).ToArray()); text = $"{interactionString} {text}"; } ////TODO: this looks ugly and not very obvious; find a better way // Show if linked with previous binding. if ((flags & InputBinding.Flags.ThisAndPreviousCombine) == InputBinding.Flags.ThisAndPreviousCombine) { text = "AND " + text; } return(new GUIContent(text)); }