/// <summary> /// Draw all UnityEventBase fields /// </summary> /// <param name="component"></param> /// <param name="eventProperty"></param> /// <returns></returns> public static int DrawComponentEvents(SerializedProperty component, SerializedProperty eventProperty) { if (component.objectReferenceValue != null) { FieldInfo[] unityEventFields = GetAllFields(component.objectReferenceValue.GetType()) .Where( field => typeof(UnityEventBase).IsAssignableFrom(field.FieldType) && (field.IsPublic || field.GetCustomAttributes(typeof(SerializeField), false).Length > 0)).ToArray(); var currentSelectedIndex = Array.FindIndex(unityEventFields, p => p.Name == eventProperty.stringValue); var unityEventsDropDown = new DropDownMenu(); for (int i = 0; i < unityEventFields.Length; i++) { FieldInfo unityEventField = unityEventFields[i]; unityEventsDropDown.Add(new DropDownItem { Label = ObjectNames.NicifyVariableName(unityEventField.Name), IsSelected = currentSelectedIndex == i, Command = () => eventProperty.stringValue = unityEventField.Name, }); } if (unityEventFields.Length > 0) { EditorGUI.indentLevel++; unityEventsDropDown.OnGUI("Event"); EditorGUI.indentLevel--; } else { EditorGUI.indentLevel++; EditorGUILayout.LabelField("Event", "No available events"); eventProperty.stringValue = ""; EditorGUI.indentLevel--; } return(unityEventFields.Length); } return(0); }
/// <summary> /// Draw all UnityEventBase fields /// </summary> /// <param name="component"></param> /// <param name="eventProperty"></param> /// <returns></returns> public static int DrawComponentEvents(SerializedProperty component, SerializedProperty eventProperty) { List <DropDownItem> unityEvents = PropertyBindingEditor.GetDropUnityEventDownItems(component.objectReferenceValue?.GetType(), eventProperty.stringValue, eventName => eventProperty.stringValue = eventName).ToList(); if (unityEvents.Count > 0) { var unityEventsDropDown = new DropDownMenu(); unityEvents.ForEach(dropDownItem => unityEventsDropDown.Add(dropDownItem)); EditorGUI.indentLevel++; unityEventsDropDown.OnGUI("Event"); EditorGUI.indentLevel--; } else { EditorGUI.indentLevel++; EditorGUILayout.LabelField("Event", "No available events"); eventProperty.stringValue = ""; EditorGUI.indentLevel--; } return(unityEvents.Count); }
/// <summary> /// Renders the given control. /// </summary> /// <param name="position">Rectangle on the screen to use for the render.</param> /// <param name="property">The <see cref="SerializedProperty"/> for which to render the custom GUI.</param> /// <param name="label">The label to render with the <paramref name="property"/>.</param> public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var dropDownPosition = EditorGUI.PrefixLabel(position, label); var enumType = typeof(EnumT); var names = Enum.GetNames(enumType); var values = Enum.GetValues(enumType).Cast <int>().ToList(); var selectedItem = property.intValue; int newSelectedItem = selectedItem; DropDownMenu menu = new DropDownMenu(); for (int i = 0; i < names.Length; i++) { var name = names[i]; var value = values[i]; var enumValueMember = enumType.GetMember(name).First(); var isObsolete = enumValueMember.GetCustomAttributes(typeof(ObsoleteAttribute), false).Any(); if (!isObsolete) { menu.Add(new DropDownItem { Label = name, IsSelected = property.intValue == value, Command = () => { property.intValue = value; }, }); } } menu.OnGUI(dropDownPosition); if (newSelectedItem != selectedItem) { property.intValue = newSelectedItem; } }
private static int DrawBindingComponent(SerializedProperty componentPathProperty, string componentDescription, SerializedProperty updateTriggerProperty, SerializedProperty unityEventProperty, bool enableUpdateTriggers, bool resolveDataContext) { using (var changeScope = new EditorGUI.ChangeCheckScope()) { EditorGUILayout.PropertyField(componentPathProperty, new GUIContent(componentPathProperty.displayName, componentDescription)); // If the binding target changes, reset the binding update trigger (since the type of the target will determine the available update triggers) if (changeScope.changed) { updateTriggerProperty.intValue = (int)BindingUpdateTrigger.None; unityEventProperty.stringValue = null; } } Type resolvedType = PropertyBinding.GetComponentType((Component)componentPathProperty.FindPropertyRelative(nameof(PropertyBinding.ComponentPath.Component)).objectReferenceValue, resolveDataContext); bool isINotifyPropertyChanged = typeof(System.ComponentModel.INotifyPropertyChanged).IsAssignableFrom(resolvedType); // Try to set the target update trigger to a reasonable default if (updateTriggerProperty.intValue == (int)BindingUpdateTrigger.None) { if (isINotifyPropertyChanged) { updateTriggerProperty.intValue = (int)BindingUpdateTrigger.PropertyChangedEvent; } } // If the value never flows back from the target to the source, then there is no reason to pay attention to value change events on the target. int updateTriggerCount = -1; if (enableUpdateTriggers) { var dropDownMenu = new DropDownMenu(); if (isINotifyPropertyChanged) { dropDownMenu.Add(new DropDownItem { Label = "Property Changed", IsSelected = updateTriggerProperty.intValue == (int)BindingUpdateTrigger.PropertyChangedEvent, Command = () => { updateTriggerProperty.intValue = (int)BindingUpdateTrigger.PropertyChangedEvent; unityEventProperty.stringValue = null; } }); } List <DropDownItem> unityEvents = PropertyBindingEditor.GetDropUnityEventDownItems(resolvedType, unityEventProperty.stringValue, unityEvent => { unityEventProperty.stringValue = unityEvent; updateTriggerProperty.intValue = (int)BindingUpdateTrigger.UnityEvent; }).ToList(); if (dropDownMenu.ItemCount > 0 && unityEvents.Any()) { dropDownMenu.Add(new DropDownItem()); } unityEvents.ForEach(dropDownItem => dropDownMenu.Add(dropDownItem)); // Only show the update trigger dropdown if there is more than one choice if (dropDownMenu.ItemCount > 1) { using (new EditorGUI.IndentLevelScope()) { dropDownMenu.OnGUI("Event"); } if (dropDownMenu.SelectedIndex < 0) { EditorGUILayout.HelpBox($"Select an event that indicates the property has changed, or update the binding mode.", MessageType.Warning); } } updateTriggerCount = dropDownMenu.ItemCount; } return(updateTriggerCount); }
public static void PropertyField(Rect position, SerializedProperty property, GUIContent label) { const float DropDownWidthFraction = 0.4f; float dropDownWidth = (position.width - EditorGUIUtility.labelWidth) * DropDownWidthFraction; position.width -= dropDownWidth; EditorGUI.PropertyField(position, property, label); var dropDownPosition = new Rect(position.xMax, position.y, dropDownWidth, EditorGUIUtility.singleLineHeight); var menu = new DropDownMenu(); if (clipboard != null) { menu.Add(new DropDownItem { Label = $"Paste component: {clipboard.name} ({clipboard.GetType().Name})", Command = () => { property.objectReferenceValue = clipboard; }, }); } var component = property.objectReferenceValue as Component; if (component != null && component.gameObject != null) { if (menu.ItemCount > 0) { menu.Add(new DropDownItem { Label = null }); } var siblingComponents = component.gameObject.GetComponents <Component>(); var existingComponents = new Dictionary <string, int>(); foreach (var siblingComponent in siblingComponents) { bool currentlySelected = siblingComponent == component; var componentName = siblingComponent.GetType().Name; // The underlying UnityEditor.EditorGUI.Popup will not render duplicate entries. (aka. entries with the same display name). // So if there are more than 1 component with the same name, then we must append a number to the name to make it unique. var countOfComponentsWithSameName = siblingComponents.Count((c) => c.GetType().Name == componentName); if (countOfComponentsWithSameName > 1) { if (!existingComponents.ContainsKey(componentName)) { // For this loop through the components, this is the first one we've hit with this name. existingComponents[componentName] = 1; } else { // Some number of components with this name already exist. existingComponents[componentName]++; } componentName = $"{componentName} {existingComponents[componentName]}"; } menu.Add(new DropDownItem { Label = $"{componentName}", Command = () => { property.objectReferenceValue = siblingComponent; }, IsSelected = currentlySelected, }); } } if (menu.ItemCount == 0) { menu.Add(new DropDownItem { Label = "Instructions" }); menu.Add(new DropDownItem()); menu.Add(new DropDownItem { Label = "You can right click on a component and select 'Copy Component Reference' and then paste here using this menu." }); menu.Add(new DropDownItem { Label = "Or you can drag and drop a gameObject in the box to the left then use this menu to choose the component from that gameObject." }); } // Render the menu. If the user selects an item, it will execute that item's command. menu.OnGUI(dropDownPosition); }