/// <summary>
 /// Tries to ensure the there is a (IHasValue<Texture>) target/wrapper component
 /// to provide the Texture
 /// </summary>
 private void TryEnsurePropertyHasTarget()
 {
     PropertyBindingEditor.HandleDrivenProperty <Texture>(
         this.target,
         this.serializedObject.FindProperty("m_hasTexture"),
         true
         );
     this.serializedObject.ApplyModifiedProperties();
 }
    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        ComponentReferenceDrawer.PropertyField(EditorGUILayout.GetControlRect(), _vprop);

        if (_vprop.objectReferenceValue != null)
        {
            PropertyBindingEditor.DrawComponentEvents(_vprop, _veprop);
        }

        EditorGUILayout.PropertyField(_vmprop);

        var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);

        using (var propertyScope = new EditorGUI.PropertyScope(rect, null, _parmprop))
        {
            GUI.Label(rect, propertyScope.content);

            //parameter type
            var typeProp = _parmprop.FindPropertyRelative("Type");
            var trect    = rect;
            trect.x     += EditorGUIUtility.labelWidth;
            trect.width -= EditorGUIUtility.labelWidth;
            EditorGUI.PropertyField(trect, typeProp);

            //value field
            var typeValue = (BindingParameterType)Enum.GetValues(typeof(BindingParameterType)).GetValue(typeProp.enumValueIndex);
            SerializedProperty valueProp = null;
            switch (typeValue)
            {
            case BindingParameterType.None:
                break;

            default:
                valueProp = _parmprop.FindPropertyRelative(typeValue.ToString());
                break;
            }
            if (valueProp != null)
            {
                EditorGUI.indentLevel++;
                EditorGUILayout.PropertyField(valueProp);
                EditorGUI.indentLevel--;
            }
        }

        serializedObject.ApplyModifiedProperties();
    }
    static void FigureViewBinding(CommandBinding binding)
    {
        var sobj   = new SerializedObject(binding);
        var vcprop = sobj.FindProperty("_target");
        var veprop = sobj.FindProperty("_targetEvent");

        if (string.IsNullOrEmpty(veprop.stringValue))
        {
            return;
        }

        var vcomp = vcprop.objectReferenceValue as Component;

        if (vcomp == null)
        {
            return;
        }

        var @event = PropertyBindingEditor.GetEvent(vcomp, veprop);

        if (@event != null)
        {
            // Fixing adding multiple command binding event handlers when using prefabs
            var eventCount = @event.GetPersistentEventCount();
            for (var idx = 0; idx < eventCount; idx++)
            {
                var perTarget = @event.GetPersistentTarget(idx);
                // if we find a duplicate event skip over adding it
                if (perTarget == binding)
                {
                    return;
                }
            }

            UnityEditor.Events.UnityEventTools.AddVoidPersistentListener(@event, binding.ExecuteCommand);
        }

        sobj.ApplyModifiedProperties();
    }
    /// <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);
    }
    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);
    }