Esempio n. 1
0
        /************************************************************************************************************************/

        /// <summary>Draws the GUI the the target transition's main property.</summary>
        protected virtual void DoMainPropertyGUI(Rect area, out Rect labelArea,
                                                 SerializedProperty rootProperty, SerializedProperty mainProperty)
        {
            labelArea = area;
            if (mainProperty == null)
            {
                return;
            }

            var fullArea = area;

            labelArea = AnimancerGUI.StealFromLeft(ref area, EditorGUIUtility.labelWidth, AnimancerGUI.StandardSpacing);

            var mainPropertyReferenceIsMissing =
                mainProperty.propertyType == SerializedPropertyType.ObjectReference &&
                mainProperty.objectReferenceValue == null;

            var hierarchyMode = EditorGUIUtility.hierarchyMode;

            EditorGUIUtility.hierarchyMode = true;

            if (rootProperty.propertyType == SerializedPropertyType.ManagedReference)
            {
                if (rootProperty.isExpanded || _Mode == Mode.AlwaysExpanded)
                {
                    EditorGUI.indentLevel++;

                    AnimancerGUI.NextVerticalArea(ref fullArea);
                    using (ObjectPool.Disposable.AcquireContent(out var label, mainProperty))
                        EditorGUI.PropertyField(fullArea, mainProperty, label, true);

                    EditorGUI.indentLevel--;
                }
            }
            else
            {
                var indentLevel = EditorGUI.indentLevel;
                EditorGUI.indentLevel = 0;

                EditorGUI.PropertyField(area, mainProperty, GUIContent.none, true);

                EditorGUI.indentLevel = indentLevel;
            }

            EditorGUIUtility.hierarchyMode = hierarchyMode;

            // If the main Object reference was just assigned and all fields were at their type default,
            // reset the value to run its default constructor and field initializers then reassign the reference.
            var reference = mainProperty.objectReferenceValue;

            if (mainPropertyReferenceIsMissing && reference != null)
            {
                mainProperty.objectReferenceValue = null;
                if (Serialization.IsDefaultValueByType(rootProperty))
                {
                    rootProperty.GetAccessor().ResetValue(rootProperty);
                }
                mainProperty.objectReferenceValue = reference;
            }
        }
Esempio n. 2
0
        /************************************************************************************************************************/

        /// <summary>Draws the root property of a transition with an optional main property on the same line.</summary>
        public void DoHeaderGUI(ref Rect area, SerializedProperty rootProperty, SerializedProperty mainProperty,
                                GUIContent label, bool isPreviewing)
        {
            area.height = AnimancerGUI.LineHeight;
            var labelArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            if (rootProperty.propertyType != SerializedPropertyType.ManagedReference)
            {
                DoPreviewButtonGUI(ref labelArea, rootProperty, isPreviewing);
            }

            // Draw the Root Property after the Main Property to give better spacing between the label and field.

            // Drawing the main property might assign its details to the label so we keep our own copy.
            using (ObjectPool.Disposable.AcquireContent(out var rootLabel, label.text, label.tooltip))
            {
                // Main Property.

                DoMainPropertyGUI(labelArea, out labelArea, rootProperty, mainProperty);

                // Root Property.

                rootLabel = EditorGUI.BeginProperty(labelArea, rootLabel, rootProperty);
                EditorGUI.LabelField(labelArea, rootLabel);
                EditorGUI.EndProperty();

                if (_Mode != Mode.AlwaysExpanded)
                {
                    rootProperty.isExpanded = EditorGUI.Foldout(labelArea, rootProperty.isExpanded, GUIContent.none, true);
                }
            }
        }
Esempio n. 3
0
        /************************************************************************************************************************/

        private void DoChildPropertiesGUI(Rect area, float headerHeight, SerializedProperty property)
        {
            if (!property.isExpanded && _Mode != Mode.AlwaysExpanded)
            {
                return;
            }

            area.y += headerHeight + AnimancerGUI.StandardSpacing;

            EditorGUI.indentLevel++;

            var rootProperty = property;

            property = property.Copy();

            SerializedProperty eventsProperty = null;

            var depth = property.depth;

            property.NextVisible(true);
            while (property.depth > depth)
            {
                // Grab the Events property and draw it last.
                if (eventsProperty == null && property.propertyPath.EndsWith("._Events"))
                {
                    eventsProperty = property.Copy();
                }
                else if (MainPropertyPathSuffix == null || !property.propertyPath.EndsWith(MainPropertyPathSuffix))
                {
                    if (eventsProperty != null)
                    {
                        var accessor = property.GetAccessor();
                        if (accessor.Field.IsDefined(typeof(DrawAfterEventsAttribute), false))
                        {
                            var eventsLabel = AnimancerGUI.TempContent(eventsProperty);
                            DoPropertyGUI(ref area, rootProperty, eventsProperty, eventsLabel);
                            AnimancerGUI.NextVerticalArea(ref area);
                            eventsProperty = null;
                        }
                    }

                    var label = AnimancerGUI.TempContent(property);
                    DoPropertyGUI(ref area, rootProperty, property, label);
                    AnimancerGUI.NextVerticalArea(ref area);
                }

                if (!property.NextVisible(false))
                {
                    break;
                }
            }

            if (eventsProperty != null)
            {
                var label = AnimancerGUI.TempContent(eventsProperty);
                DoPropertyGUI(ref area, rootProperty, eventsProperty, label);
            }

            EditorGUI.indentLevel--;
        }
Esempio n. 4
0
        /// <summary>
        /// If the `property` is a "Start Time" field, this method draws it as well as the "End Time" below it and
        /// returns true.
        /// </summary>
        public static bool TryDoStartTimeField(ref Rect area, SerializedProperty rootProperty,
                                               SerializedProperty property, GUIContent label)
        {
            if (!property.propertyPath.EndsWith("." + NormalizedStartTimeFieldName))
            {
                return(false);
            }

            // Start Time.
            label.text = AnimancerGUI.GetNarrowText("Start Time");
            AnimationTimeAttribute.nextDefaultValue = AnimancerEvent.Sequence.GetDefaultNormalizedStartTime(Context.Transition.Speed);
            EditorGUI.PropertyField(area, property, label, false);

            AnimancerGUI.NextVerticalArea(ref area);

            // End Time.
            var events = rootProperty.FindPropertyRelative("_Events");

            using (var context = SerializableEventSequenceDrawer.Context.Get(events))
            {
                var areaCopy = area;
                var index    = Mathf.Max(0, context.Times.Count - 1);
                SerializableEventSequenceDrawer.DoTimeGUI(ref areaCopy, context, index, true);
            }

            return(true);
        }
Esempio n. 5
0
        /// <summary>
        /// If the `property` is a "Start Time" field, this method draws it as well as the "End Time" below it and
        /// returns true.
        /// </summary>
        public static bool TryDoStartTimeField(ref Rect area, SerializedProperty rootProperty,
                                               SerializedProperty property, GUIContent label)
        {
            if (!property.propertyPath.EndsWith("." + NormalizedStartTimeFieldName))
            {
                return(false);
            }

            // Start Time.
            label.text = AnimancerGUI.GetNarrowText("Start Time");
            var length           = Context.MaximumDuration;
            var defaultStartTime = AnimancerEvent.Sequence.GetDefaultNormalizedStartTime(Context.Transition.Speed);

            AnimancerGUI.DoOptionalTimeField(ref area, label, property, true, length, defaultStartTime);

            AnimancerGUI.NextVerticalArea(ref area);

            // End Time.
            var events = rootProperty.FindPropertyRelative("_Events");

            using (var context = EventSequenceDrawer.Context.Get(events))
            {
                var    areaCopy = area;
                var    index    = Mathf.Max(0, context.TimeCount - 1);
                string callbackLabel;
                EventSequenceDrawer.DoEventTimeGUI(ref areaCopy, context, index, true, out callbackLabel);
            }

            return(true);
        }
        /************************************************************************************************************************/

        private void DoHeaderGUI(ref Rect area, GUIContent label, Context context)
        {
            area.height = AnimancerGUI.LineHeight;
            var headerArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            label = EditorGUI.BeginProperty(headerArea, label, context.Property);

            if (!context.Property.hasMultipleDifferentValues)
            {
                var addEventArea = AnimancerGUI.StealFromRight(ref headerArea, headerArea.height, AnimancerGUI.StandardSpacing);
                DoAddRemoveEventButtonGUI(addEventArea, context);
            }

            if (context.TransitionContext != null && context.TransitionContext.Transition != null)
            {
                EditorGUI.EndProperty();

                TimelineGUI.DoGUI(headerArea, context, out var addEventNormalizedTime);

                if (!float.IsNaN(addEventNormalizedTime))
                {
                    AddEvent(context, addEventNormalizedTime);
                }
            }
            else
            {
                label.text = AnimancerGUI.GetNarrowText(label.text);

                string summary;
                if (context.Times.Count == 0)
                {
                    summary = "[0] End Time 1";
                }
                else
                {
                    var index   = context.Times.Count - 1;
                    var endTime = context.Times.GetElement(index).floatValue;
                    summary = $"[{index}] End Time {endTime:G3}";
                }

                using (ObjectPool.Disposable.AcquireContent(out var content, summary))
                    EditorGUI.LabelField(headerArea, label, content);

                EditorGUI.EndProperty();
            }

            EditorGUI.BeginChangeCheck();
            context.Property.isExpanded =
                EditorGUI.Foldout(headerArea, context.Property.isExpanded, GUIContent.none, true);
            if (EditorGUI.EndChangeCheck())
            {
                context.SelectedEvent = -1;
            }
        }
Esempio n. 7
0
        private static void DrawSpriteFrames(AnimationClip clip)
        {
            var keyframes = GetSpriteReferences(clip);

            if (keyframes == null)
            {
                return;
            }

            for (int i = 0; i < keyframes.Length; i++)
            {
                var keyframe = keyframes[i];
                var sprite   = keyframe.value as Sprite;
                if (sprite != null)
                {
                    if (_FrameCache == null)
                    {
                        _FrameCache = new ConversionCache <int, string>(
                            (value) => $"Frame: {value}");

                        _TimeCache = new ConversionCache <float, string>(
                            (value) => $"Time: {value}s");
                    }

                    var texture = sprite.texture;

                    var area  = GUILayoutUtility.GetRect(0, AnimancerGUI.LineHeight * 4);
                    var width = area.width;

                    var rect = sprite.rect;
                    area.width = area.height * rect.width / rect.height;

                    rect.x      /= texture.width;
                    rect.y      /= texture.height;
                    rect.width  /= texture.width;
                    rect.height /= texture.height;

                    GUI.DrawTextureWithTexCoords(area, texture, rect);

                    var offset = area.width + AnimancerGUI.StandardSpacing;
                    area.x     += offset;
                    area.width  = width - offset;
                    area.height = AnimancerGUI.LineHeight;
                    area.y     += Mathf.Round(area.height * 0.5f);

                    GUI.Label(area, _FrameCache.Convert(i));

                    AnimancerGUI.NextVerticalArea(ref area);
                    GUI.Label(area, _TimeCache.Convert(keyframe.time));

                    AnimancerGUI.NextVerticalArea(ref area);
                    GUI.Label(area, sprite.name);
                }
            }
        }
Esempio n. 8
0
        private void DoHeaderGUI(ref Rect area, GUIContent label, Context context)
        {
            area.height = AnimancerGUI.LineHeight;
            var headerArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            label = EditorGUI.BeginProperty(headerArea, label, context.Property);

            var addEventArea = AnimancerGUI.StealFromRight(ref headerArea, headerArea.height, AnimancerGUI.StandardSpacing);

            DoAddEventButtonGUI(addEventArea, context);

            if (context.TransitionContext != null && context.TransitionContext.Transition != null)
            {
                EditorGUI.EndProperty();

                float addEventNormalizedTime;
                TimeRuler.DoGUI(headerArea, context, out addEventNormalizedTime);

                if (!float.IsNaN(addEventNormalizedTime))
                {
                    AddEvent(context, addEventNormalizedTime);
                }
            }
            else
            {
                label.text = AnimancerGUI.GetNarrowText(label.text);

                var summary = AnimancerGUI.TempContent();
                if (context.TimeCount == 0)
                {
                    summary.text = "[0] End Time 1";
                }
                else
                {
                    var index   = context.TimeCount - 1;;
                    var endTime = context.GetTime(index).floatValue;
                    summary.text = string.Concat("[", index.ToString(), "] End Time ", endTime.ToString("G3"));
                }

                EditorGUI.LabelField(headerArea, label, summary);

                EditorGUI.EndProperty();
            }

            EditorGUI.BeginChangeCheck();
            context.Property.isExpanded =
                EditorGUI.Foldout(headerArea, context.Property.isExpanded, GUIContent.none, true);
            if (EditorGUI.EndChangeCheck())
            {
                context.SelectedEvent = -1;
            }
        }
Esempio n. 9
0
        /// <summary>Draws the GUI for the `animancerEvent`.</summary>
        public static void Draw(ref Rect area, string name, AnimancerEvent animancerEvent)
        {
            area.height = AnimancerGUI.LineHeight;

            if (_EventTimeCache == null)
            {
                _EventTimeCache = new ConversionCache <float, string>((time)
                                                                      => float.IsNaN(time) ? "Time = Auto" : $"Time = {time.ToStringCached()}x");
            }

            EditorGUI.LabelField(area, name, _EventTimeCache.Convert(animancerEvent.normalizedTime));

            AnimancerGUI.NextVerticalArea(ref area);

            EditorGUI.indentLevel++;
            DrawInvocationList(ref area, animancerEvent.callback);
            EditorGUI.indentLevel--;
        }
Esempio n. 10
0
            /************************************************************************************************************************/

            /// <summary>Draws a group of <see cref="NormalizedPixelField"/>s.</summary>
            public static void DoGroupGUI(SerializedProperty baseProperty, GUIContent label, NormalizedPixelField[] fields)
            {
                var height = (AnimancerGUI.LineHeight + AnimancerGUI.StandardSpacing) * (fields.Length + 1);
                var area   = GUILayoutUtility.GetRect(0, height);

                area.height = AnimancerGUI.LineHeight;
                label       = EditorGUI.BeginProperty(area, label, baseProperty);
                GUI.Label(area, label);
                EditorGUI.EndProperty();

                EditorGUI.indentLevel++;

                for (int i = 0; i < fields.Length; i++)
                {
                    AnimancerGUI.NextVerticalArea(ref area);
                    fields[i].DoTwinFloatFieldGUI(area);
                }

                EditorGUI.indentLevel--;
            }
Esempio n. 11
0
        /************************************************************************************************************************/

        /// <summary>Draws the target and name of the specified <see cref="Delegate"/>.</summary>
        public static void Draw(ref Rect area, Delegate del)
        {
            area.height = AnimancerGUI.LineHeight;

            if (del == null)
            {
                EditorGUI.LabelField(area, "Callback", "Null");
                AnimancerGUI.NextVerticalArea(ref area);
                return;
            }

            var method = del.Method;

            EditorGUI.LabelField(area, "Method", method.Name);

            AnimancerGUI.NextVerticalArea(ref area);

            var target = del.Target;

            if (target is Object obj)
            {
                var enabled = GUI.enabled;
                GUI.enabled = false;

                EditorGUI.ObjectField(area, "Target", obj, obj.GetType(), true);

                GUI.enabled = enabled;
            }
            else if (target != null)
            {
                EditorGUI.LabelField(area, "Target", target.ToString());
            }
            else
            {
                EditorGUI.LabelField(area, "Declaring Type", method.DeclaringType.GetNameCS());
            }

            AnimancerGUI.NextVerticalArea(ref area);
        }
Esempio n. 12
0
        /************************************************************************************************************************/

        /// <summary>Draws the target and name of the specified <see cref="Delegate"/>.</summary>
        public static void DrawInvocationList(ref Rect area, MulticastDelegate del)
        {
            if (del == null)
            {
                EditorGUI.LabelField(area, "Delegate", "Null");
                AnimancerGUI.NextVerticalArea(ref area);
                return;
            }

            var delegates = GetInvocationListIfMulticast(del);

            if (delegates == null)
            {
                Draw(ref area, del);
            }
            else
            {
                for (int i = 0; i < delegates.Length; i++)
                {
                    Draw(ref area, delegates[i]);
                }
            }
        }
        /// <summary>Draws the time field for the event at the specified `index`.</summary>
        public static void DoTimeGUI(ref Rect area, Context context, int index, bool autoSort,
                                     string timeLabel, float defaultTime, bool isEndEvent)
        {
            EditorGUI.BeginChangeCheck();

            area.height = EventTimeAttribute.GetPropertyHeight(null, null);
            var timeArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            float normalizedTime;

            using (ObjectPool.Disposable.AcquireContent(out var label, timeLabel,
                                                        isEndEvent ? Strings.Tooltips.EndTime : Strings.Tooltips.CallbackTime))
            {
                var length = context.TransitionContext?.MaximumDuration ?? float.NaN;

                if (index < context.Times.Count)
                {
                    var timeProperty = context.Times.GetElement(index);
                    if (timeProperty == null)// Multi-selection screwed up the property retrieval.
                    {
                        EditorGUI.BeginChangeCheck();

                        label = EditorGUI.BeginProperty(timeArea, label, context.Times.Property);
                        if (isEndEvent)
                        {
                            AnimationTimeAttribute.nextDefaultValue = defaultTime;
                        }
                        normalizedTime = float.NaN;
                        EventTimeAttribute.OnGUI(timeArea, label, ref normalizedTime);

                        EditorGUI.EndProperty();

                        if (EditorGUI.EndChangeCheck())
                        {
                            context.Times.Count     = context.Times.Count;
                            timeProperty            = context.Times.GetElement(index);
                            timeProperty.floatValue = normalizedTime;
                            SyncEventTimeChange(context, index, normalizedTime);
                        }
                    }
                    else// Event time property was correctly retrieved.
                    {
                        var wasEditingTextField = EditorGUIUtility.editingTextField;
                        if (!wasEditingTextField)
                        {
                            _PreviousTime = float.NaN;
                        }

                        EditorGUI.BeginChangeCheck();

                        label = EditorGUI.BeginProperty(timeArea, label, timeProperty);

                        if (isEndEvent)
                        {
                            AnimationTimeAttribute.nextDefaultValue = defaultTime;
                        }
                        normalizedTime = timeProperty.floatValue;
                        EventTimeAttribute.OnGUI(timeArea, label, ref normalizedTime);

                        EditorGUI.EndProperty();

                        if (AnimancerGUI.TryUseClickEvent(timeArea, 2))
                        {
                            normalizedTime = float.NaN;
                        }

                        var isEditingTextField = EditorGUIUtility.editingTextField;
                        if (EditorGUI.EndChangeCheck() || (wasEditingTextField && !isEditingTextField))
                        {
                            if (float.IsNaN(normalizedTime))
                            {
                                RemoveEvent(context, index);
                                AnimancerGUI.Deselect();
                            }
                            else if (isEndEvent)
                            {
                                timeProperty.floatValue = normalizedTime;
                                SyncEventTimeChange(context, index, normalizedTime);
                            }
                            else if (!autoSort && isEditingTextField)
                            {
                                _PreviousTime = normalizedTime;
                            }
                            else
                            {
                                if (!float.IsNaN(_PreviousTime))
                                {
                                    if (Event.current.keyCode != KeyCode.Escape)
                                    {
                                        normalizedTime = _PreviousTime;
                                        AnimancerGUI.Deselect();
                                    }

                                    _PreviousTime = float.NaN;
                                }

                                WrapEventTime(context, ref normalizedTime);

                                timeProperty.floatValue = normalizedTime;
                                SyncEventTimeChange(context, index, normalizedTime);

                                if (autoSort)
                                {
                                    SortEvents(context);
                                }
                            }

                            GUI.changed = true;
                        }
                    }
                }
                else// Dummy End Event (when there are no event times).
                {
                    AnimancerUtilities.Assert(index == 0, "Dummy end event index != 0");
                    EditorGUI.BeginChangeCheck();

                    EditorGUI.BeginProperty(timeArea, GUIContent.none, context.Times.Property);

                    AnimationTimeAttribute.nextDefaultValue = defaultTime;
                    normalizedTime = float.NaN;
                    EventTimeAttribute.OnGUI(timeArea, label, ref normalizedTime);

                    EditorGUI.EndProperty();

                    if (EditorGUI.EndChangeCheck() && !float.IsNaN(normalizedTime))
                    {
                        context.Times.Count = 1;
                        var timeProperty = context.Times.GetElement(0);
                        timeProperty.floatValue = normalizedTime;
                        SyncEventTimeChange(context, 0, normalizedTime);
                    }
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                var eventType = Event.current.type;
                if (eventType == EventType.Layout)
                {
                    return;
                }

                if (eventType == EventType.Used)
                {
                    normalizedTime = UnitsAttribute.GetDisplayValue(normalizedTime, defaultTime);
                    TransitionPreviewWindow.PreviewNormalizedTime = normalizedTime;
                }

                GUIUtility.ExitGUI();
            }
        }
Esempio n. 14
0
        /************************************************************************************************************************/

        private void DoChildPropertiesGUI(Rect area, SerializedProperty rootProperty, SerializedProperty mainProperty)
        {
            if (!rootProperty.isExpanded && _Mode != Mode.AlwaysExpanded)
            {
                return;
            }

            // Skip over the main property if it was already drawn by the header.
            if (rootProperty.propertyType == SerializedPropertyType.ManagedReference &&
                mainProperty != null)
            {
                AnimancerGUI.NextVerticalArea(ref area);
            }

            EditorGUI.indentLevel++;

            var property = rootProperty.Copy();

            SerializedProperty eventsProperty = null;

            var depth = property.depth;

            property.NextVisible(true);
            while (property.depth > depth)
            {
                // Grab the Events property and draw it last.
                var path = property.propertyPath;
                if (eventsProperty == null && path.EndsWith("._Events"))
                {
                    eventsProperty = property.Copy();
                }
                // Don't draw the main property again.
                else if (mainProperty != null && path.EndsWith(MainPropertyPathSuffix))
                {
                }
                else
                {
                    if (eventsProperty != null)
                    {
                        var type     = Context.Transition.GetType();
                        var accessor = property.GetAccessor();
                        var field    = Serialization.GetField(type, accessor.Name);
                        if (field != null && field.IsDefined(typeof(DrawAfterEventsAttribute), false))
                        {
                            using (ObjectPool.Disposable.AcquireContent(out var eventsLabel, eventsProperty))
                                DoChildPropertyGUI(ref area, rootProperty, eventsProperty, eventsLabel);
                            AnimancerGUI.NextVerticalArea(ref area);
                            eventsProperty = null;
                        }
                    }

                    using (ObjectPool.Disposable.AcquireContent(out var label, property))
                        DoChildPropertyGUI(ref area, rootProperty, property, label);
                    AnimancerGUI.NextVerticalArea(ref area);
                }

                if (!property.NextVisible(false))
                {
                    break;
                }
            }

            if (eventsProperty != null)
            {
                using (ObjectPool.Disposable.AcquireContent(out var label, eventsProperty))
                    DoChildPropertyGUI(ref area, rootProperty, eventsProperty, label);
            }

            EditorGUI.indentLevel--;
        }
        /************************************************************************************************************************/

        /// <summary>Draws the GUI fields for the event at the specified `index`.</summary>
        public static void DoCallbackGUI(ref Rect area, Context context, int index, bool autoSort, string callbackLabel)
        {
            EditorGUI.BeginChangeCheck();

            using (ObjectPool.Disposable.AcquireContent(out var label, callbackLabel))
            {
                if (index < context.Callbacks.Count)
                {
                    var callback = context.Callbacks.GetElement(index);
                    area.height = EditorGUI.GetPropertyHeight(callback, false);
                    EditorGUI.BeginProperty(area, GUIContent.none, callback);

                    // UnityEvents ignore the proper indentation which makes them look terrible in a list.
                    // So we force the area to be indented.
                    var indentedArea = EditorGUI.IndentedRect(area);
                    var indentLevel  = EditorGUI.indentLevel;
                    EditorGUI.indentLevel = 0;

                    EditorGUI.PropertyField(indentedArea, callback, label, false);

                    EditorGUI.indentLevel = indentLevel;
                    EditorGUI.EndProperty();
                }
                else if (DummySerializableCallback.DoCallbackGUI(ref area, label, context.Callbacks.Property, out var callback))
                {
                    try
                    {
                        Sequence.DisableCompactArrays = true;

                        if (index >= context.Times.Count)
                        {
                            context.Times.Property.InsertArrayElementAtIndex(index);
                            context.Times.Count++;
                            context.Times.GetElement(index).floatValue = float.NaN;
                            context.Times.Property.serializedObject.ApplyModifiedProperties();
                        }

                        context.Callbacks.Property.ForEachTarget((callbacksProperty) =>
                        {
                            var accessor     = callbacksProperty.GetAccessor();
                            var oldCallbacks = (Array)accessor.GetValue(callbacksProperty.serializedObject.targetObject);

                            Array newCallbacks;
                            if (oldCallbacks == null)
                            {
                                var elementType = accessor.GetFieldElementType(callbacksProperty);
                                newCallbacks    = Array.CreateInstance(elementType, 1);
                            }
                            else
                            {
                                var elementType = oldCallbacks.GetType().GetElementType();
                                newCallbacks    = Array.CreateInstance(elementType, index + 1);
                                Array.Copy(oldCallbacks, newCallbacks, oldCallbacks.Length);
                            }

                            newCallbacks.SetValue(callback, index);
                            accessor.SetValue(callbacksProperty, newCallbacks);
                        });

                        context.Callbacks.Property.OnPropertyChanged();
                        context.Callbacks.Refresh();
                    }
                    finally
                    {
                        Sequence.DisableCompactArrays = false;
                    }
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                if (index < context.Callbacks.Count)
                {
                    var events = context.Sequence?.InitializedEvents;
                    if (events != null)
                    {
                        var animancerEvent = index < events.Count ? events[index] : events.endEvent;
                        if (AnimancerEvent.IsNullOrDummy(animancerEvent.callback))
                        {
                            context.Callbacks.Property.serializedObject.ApplyModifiedProperties();
                            var property = context.Callbacks.GetElement(index);
                            var callback = property.GetValue();
                            var invoker  = Sequence.GetInvoker(callback);
                            if (index < events.Count)
                            {
                                events.SetCallback(index, invoker);
                            }
                            else
                            {
                                events.OnEnd = invoker;
                            }
                        }
                    }
                }
            }

            AnimancerGUI.NextVerticalArea(ref area);
        }
Esempio n. 16
0
        /************************************************************************************************************************/

        /// <summary>Draws the GUI for the `events`.</summary>
        public void Draw(ref Rect area, Sequence events, GUIContent label)
        {
            if (events == null)
            {
                return;
            }

            area.height = AnimancerGUI.LineHeight;

            var headerArea = area;

            const string LogLabel = "Log";

            if (float.IsNaN(_LogButtonWidth))
            {
                _LogButtonWidth = EditorStyles.miniButton.CalculateWidth(LogLabel);
            }
            var logArea = AnimancerGUI.StealFromRight(ref headerArea, _LogButtonWidth);

            if (GUI.Button(logArea, LogLabel, EditorStyles.miniButton))
            {
                Debug.Log(events.DeepToString());
            }

            _IsExpanded = EditorGUI.Foldout(headerArea, _IsExpanded, GUIContent.none, true);
            using (ObjectPool.Disposable.AcquireContent(out var summary, GetSummary(events)))
                EditorGUI.LabelField(headerArea, label, summary);

            AnimancerGUI.NextVerticalArea(ref area);

            if (!_IsExpanded)
            {
                return;
            }

            var enabled = GUI.enabled;

            GUI.enabled = false;

            EditorGUI.indentLevel++;

            for (int i = 0; i < events.Count; i++)
            {
                var name = events.GetName(i);
                if (string.IsNullOrEmpty(name))
                {
                    if (_EventNumberCache == null)
                    {
                        _EventNumberCache = new ConversionCache <int, string>((index) => $"Event {index}");
                    }

                    name = _EventNumberCache.Convert(i);
                }

                Draw(ref area, name, events[i]);
            }

            Draw(ref area, "End Event", events.endEvent);

            EditorGUI.indentLevel--;

            GUI.enabled = enabled;
        }
        /************************************************************************************************************************/

        /// <summary>Draws the time field for the event at the specified `index`.</summary>
        public static void DoNameGUI(ref Rect area, Context context, int index, string nameLabel)
        {
            if (nameLabel == null)
            {
                return;
            }

            EditorGUI.BeginChangeCheck();
            string name;

            area.height = AnimancerGUI.LineHeight;
            var fieldArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            using (ObjectPool.Disposable.AcquireContent(out var label, nameLabel,
                                                        "An optional name which can be used to identify the event in code." +
                                                        " Leaving all names blank is recommended if you are not using them."))
            {
                fieldArea = EditorGUI.PrefixLabel(fieldArea, label);
            }

            var indentLevel = EditorGUI.indentLevel;

            EditorGUI.indentLevel = 0;

            if (index < context.Names.Count)
            {
                var nameProperty = context.Names.GetElement(index);

                EditorGUI.BeginProperty(fieldArea, GUIContent.none, nameProperty);
                name = nameProperty.stringValue = DoEventNameTextField(fieldArea, context, nameProperty.stringValue);
                EditorGUI.EndProperty();
            }
            else
            {
                EditorGUI.BeginChangeCheck();

                EditorGUI.BeginProperty(fieldArea, GUIContent.none, context.Names.Property);
                name = DoEventNameTextField(fieldArea, context, "");
                EditorGUI.EndProperty();

                if (EditorGUI.EndChangeCheck() && !string.IsNullOrEmpty(name))
                {
                    context.Names.Count++;
                    if (context.Names.Count < index + 1)
                    {
                        var nextProperty = context.Names.GetElement(context.Names.Count - 1);
                        nextProperty.stringValue = "";
                        context.Names.Count      = index + 1;
                    }

                    var nameProperty = context.Names.GetElement(index);
                    nameProperty.stringValue = name;
                }
            }

            EditorGUI.indentLevel = indentLevel;

            if (EditorGUI.EndChangeCheck())
            {
                var events = context.Sequence?.InitializedEvents;
                if (events != null)
                {
                    events.SetName(index, name);
                }
            }
        }
Esempio n. 18
0
        /// <summary>Draws the time field for the event at the specified `index`.</summary>
        public static void DoEventTimeGUI(ref Rect area, Context context, int index, bool autoSort, out string callbackLabel)
        {
            EditorGUI.BeginChangeCheck();

            area.height = AnimancerGUI.LineHeight;
            var timeArea = area;

            AnimancerGUI.NextVerticalArea(ref area);

            GUIContent timeLabel;
            float      defaultTime;
            bool       isEndEvent;

            GetEventLabels(index, context, out timeLabel, out callbackLabel, out defaultTime, out isEndEvent);
            var length = context.TransitionContext.MaximumDuration;

            float normalizedTime;

            if (index < context.TimeCount)
            {
                var timeProperty = context.GetTime(index);

                var wasEditingTextField = EditorGUIUtility.editingTextField;
                if (!wasEditingTextField)
                {
                    _PreviousTime = float.NaN;
                }

                EditorGUI.BeginChangeCheck();

                timeLabel      = EditorGUI.BeginProperty(area, timeLabel, timeProperty);
                normalizedTime = AnimancerGUI.DoOptionalTimeField(
                    ref timeArea, timeLabel, timeProperty.floatValue, true, length, defaultTime);
                EditorGUI.EndProperty();

                var isEditingTextField = EditorGUIUtility.editingTextField;
                if (EditorGUI.EndChangeCheck() || (wasEditingTextField && !isEditingTextField))
                {
                    if (isEndEvent)
                    {
                        timeProperty.floatValue = normalizedTime;
                    }
                    else if (float.IsNaN(normalizedTime))
                    {
                        RemoveEvent(context, index);
                        AnimancerGUI.Deselect();
                    }
                    else if (!autoSort && isEditingTextField)
                    {
                        _PreviousTime = normalizedTime;
                    }
                    else
                    {
                        if (!float.IsNaN(_PreviousTime))
                        {
                            if (Event.current.keyCode != KeyCode.Escape)
                            {
                                normalizedTime = _PreviousTime;
                                AnimancerGUI.Deselect();
                            }

                            _PreviousTime = float.NaN;
                        }

                        WrapEventTime(context, ref normalizedTime);

                        timeProperty.floatValue = normalizedTime;

                        if (autoSort)
                        {
                            SortEvents(context);
                        }
                    }

                    GUI.changed = true;
                }
            }
            else// Dummy End Event.
            {
                Debug.Assert(index == 0, "This is assumed to be a dummy end event, which should only be at index 0");
                EditorGUI.BeginChangeCheck();

                EditorGUI.BeginProperty(timeArea, GUIContent.none, context.Times);
                normalizedTime = AnimancerGUI.DoOptionalTimeField(
                    ref timeArea, timeLabel, float.NaN, true, length, defaultTime, true);
                EditorGUI.EndProperty();

                if (EditorGUI.EndChangeCheck() && !float.IsNaN(normalizedTime))
                {
                    context.TimeCount = 1;
                    var timeProperty = context.GetTime(0);
                    timeProperty.floatValue = normalizedTime;
                }
            }

            if (EditorGUI.EndChangeCheck())
            {
                TransitionPreviewWindow.SetPreviewNormalizedTime(normalizedTime);

                if (Event.current.type != EventType.Layout)
                {
                    GUIUtility.ExitGUI();
                }
            }
        }
Esempio n. 19
0
        /************************************************************************************************************************/

        /// <summary>Draws the GUI fields for the event at the specified `index`.</summary>
        public static void DoEventGUI(ref Rect area, Context context, int index, bool autoSort, bool showCallback)
        {
            string callbackLabel;

            DoEventTimeGUI(ref area, context, index, autoSort, out callbackLabel);

            if (showCallback)
            {
                var label = AnimancerGUI.TempContent(callbackLabel);

                if (index < context.CallbackCount)
                {
                    var callback = context.GetCallback(index);
                    area.height = EditorGUI.GetPropertyHeight(callback, false);
                    EditorGUI.BeginProperty(area, GUIContent.none, callback);

                    // UnityEvents ignore the proper indentation which makes them look terrible in a list.
                    // So we force the area to be indented.
                    var indentedArea = EditorGUI.IndentedRect(area);
                    var indentLevel  = EditorGUI.indentLevel;
                    EditorGUI.indentLevel = 0;

                    EditorGUI.PropertyField(indentedArea, callback, label, false);

                    EditorGUI.indentLevel = indentLevel;
                    EditorGUI.EndProperty();
                }
                else
                {
                    var    length = context.TransitionContext.MaximumDuration;
                    object callback;
                    if (DummySerializableCallback.DoCallbackGUI(ref area, label, context.Callbacks, out callback))
                    {
                        context.Callbacks.RecordUndo();

                        context.Callbacks.ForEachTarget((callbacksProperty) =>
                        {
                            var accessor     = callbacksProperty.GetAccessor();
                            var oldCallbacks = (Array)accessor.GetValue(callbacksProperty.serializedObject.targetObject);

                            Array newCallbacks;
                            if (oldCallbacks == null)
                            {
                                var elementType = accessor.FieldType.GetElementType();
                                newCallbacks    = Array.CreateInstance(elementType, 1);
                            }
                            else
                            {
                                var elementType = oldCallbacks.GetType().GetElementType();
                                newCallbacks    = Array.CreateInstance(elementType, index + 1);
                                Array.Copy(oldCallbacks, newCallbacks, oldCallbacks.Length);
                            }

                            newCallbacks.SetValue(callback, index);
                            accessor.SetValue(callbacksProperty, newCallbacks);
                        });

                        context.Callbacks.OnPropertyChanged();
                        context.CallbackCount = index + 1;

                        if (index >= context.TimeCount)
                        {
                            context.Times.InsertArrayElementAtIndex(index);
                            context.TimeCount++;
                            context.GetTime(index).floatValue = float.NaN;
                        }
                    }
                }

                AnimancerGUI.NextVerticalArea(ref area);
            }
        }