예제 #1
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)
    {
        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);
    }
예제 #3
0
    /// <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);
    }
예제 #5
0
    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);
    }