Esempio n. 1
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);
        }
        /// <summary>
        /// Draws the details of the <see cref="EventSequenceDrawer.Context.Callbacks"/>.
        /// </summary>
        public void DoEventsGUI(EventSequenceDrawer.Context context, out float addEventNormalizedTime)
        {
            addEventNormalizedTime = float.NaN;
            var currentGUIEvent = Event.current;

            EventControlIDs.Clear();
            var selectedEventControlID = -1;

            var baseControlID = GUIUtility.GetControlID(EventHash - 1, FocusType.Passive);

            for (int i = 0; i < EventTimes.Count; i++)
            {
                var controlID = GUIUtility.GetControlID(EventHash + i, FocusType.Keyboard);
                EventControlIDs.Add(controlID);
                if (context.SelectedEvent == i)
                {
                    selectedEventControlID = controlID;
                }
            }

            EventControlIDs.Add(baseControlID);

            switch (currentGUIEvent.type)
            {
            case EventType.Repaint:
                RepaintEventsGUI(context);
                break;

            case EventType.MouseDown:
                if (_Area.Contains(currentGUIEvent.mousePosition))
                {
                    OnMouseDown(currentGUIEvent, context, out addEventNormalizedTime);
                }
                break;

            case EventType.MouseDrag:
                if (GUIUtility.hotControl == baseControlID)
                {
                    SetPreviewTime(currentGUIEvent);
                    GUIUtility.ExitGUI();
                }
                break;

            case EventType.KeyUp:
                if (GUIUtility.keyboardControl == selectedEventControlID &&
                    (currentGUIEvent.keyCode == KeyCode.Delete || currentGUIEvent.keyCode == KeyCode.Backspace))
                {
                    EventSequenceDrawer.RemoveEvent(context, context.SelectedEvent);
                    GUIUtility.ExitGUI();
                }
                break;
            }
        }
Esempio n. 3
0
        /// <summary>Returns a cached <see cref="EventSequenceDrawer"/> for the `events`.</summary>
        /// <remarks>
        /// The cache uses a <see cref="ConditionalWeakTable{TKey, TValue}"/> so it doesn't prevent the `events`
        /// from being garbage collected.
        /// </remarks>
        public static EventSequenceDrawer Get(Sequence events)
        {
            if (events == null)
            {
                return(null);
            }

            if (!SequenceToDrawer.TryGetValue(events, out var drawer))
            {
                SequenceToDrawer.Add(events, drawer = new EventSequenceDrawer());
            }

            return(drawer);
        }
        /************************************************************************************************************************/

        /// <summary>
        /// Calculates the number of vertical pixels the `property` will occupy when it is drawn.
        /// </summary>
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            using (var context = Context.Get(property))
            {
                var height = AnimancerGUI.LineHeight;

                var count = Math.Max(1, context.Times.Count);
                for (int i = 0; i < count; i++)
                {
                    height += CalculateEventHeight(context, i) * GetVisibility(context, i).faded;
                }

                var events = context.Sequence?.InitializedEvents;
                if (events != null)
                {
                    height += EventSequenceDrawer.Get(events).CalculateHeight(events) + AnimancerGUI.StandardSpacing;
                }

                return(height);
            }
        }
Esempio n. 5
0
        /************************************************************************************************************************/

        private void ShowContextMenu(Event currentGUIEvent, EventSequenceDrawer.Context context)
        {
            context = context.Copy();
            var time             = SecondsToNormalized(PixelsToSeconds(currentGUIEvent.mousePosition.x));
            var hasSelectedEvent = context.SelectedEvent >= 0;

            var menu = new GenericMenu();

            AddContextFunction(menu, context, "Add Event (Double Click)", true,
                               () => EventSequenceDrawer.AddEvent(context, time));

            AddContextFunction(menu, context, "Remove Event (Delete)", hasSelectedEvent,
                               () => EventSequenceDrawer.RemoveEvent(context, context.SelectedEvent));

            const string NudgePrefix = "Nudge Event Time/";

            AddContextFunction(menu, context, NudgePrefix + "Left 1 Pixel (Left Arrow)", hasSelectedEvent,
                               () => NudgeEventTime(context, -1));
            AddContextFunction(menu, context, NudgePrefix + "Left 10 Pixels (Shift + Left Arrow)", hasSelectedEvent,
                               () => NudgeEventTime(context, -10));
            AddContextFunction(menu, context, NudgePrefix + "Right 1 Pixel (Right Arrow)", hasSelectedEvent,
                               () => NudgeEventTime(context, 1));
            AddContextFunction(menu, context, NudgePrefix + "Right 10 Pixels (Shift + Right Arrow)", hasSelectedEvent,
                               () => NudgeEventTime(context, 10));

            var canRoundTime = hasSelectedEvent;

            if (canRoundTime)
            {
                time         = context.Times.GetElement(context.SelectedEvent).floatValue;
                canRoundTime = TryRoundValue(ref time);
            }

            AddContextFunction(menu, context, $"Round Event Time to {time}x (Space)", canRoundTime,
                               () => RoundEventTime(context));

            menu.ShowAsContext();
        }
        /************************************************************************************************************************/

        /// <summary>Draws the GUI for the `property`.</summary>
        public override void OnGUI(Rect area, SerializedProperty property, GUIContent label)
        {
            using (var context = Context.Get(property))
            {
                DoHeaderGUI(ref area, label, context);

                if (!property.hasMultipleDifferentValues)
                {
                    EditorGUI.indentLevel++;
                    DoAllEventsGUI(ref area, context);
                    EditorGUI.indentLevel--;
                }

                var sequence = context.Sequence?.InitializedEvents;
                if (sequence != null)
                {
                    using (ObjectPool.Disposable.AcquireContent(out label, "Runtime Events",
                                                                $"The runtime {nameof(AnimancerEvent)}.{nameof(Sequence)} created from the serialized data above"))
                    {
                        EventSequenceDrawer.Get(sequence).Draw(ref area, sequence, label);
                    }
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Draws the details of the <see cref="EventSequenceDrawer.Context.Callbacks"/>.
        /// </summary>
        public void DoEventsGUI(EventSequenceDrawer.Context context, out float addEventNormalizedTime)
        {
            addEventNormalizedTime = float.NaN;
            var currentGUIEvent = Event.current;

            EventControlIDs.Clear();
            var selectedEventControlID = -1;

            var baseControlID = GUIUtility.GetControlID(EventHash - 1, FocusType.Passive);

            for (int i = 0; i < EventTimes.Count; i++)
            {
                var controlID = GUIUtility.GetControlID(EventHash + i, FocusType.Keyboard);
                EventControlIDs.Add(controlID);
                if (context.SelectedEvent == i)
                {
                    selectedEventControlID = controlID;
                }
            }

            EventControlIDs.Add(baseControlID);

            switch (currentGUIEvent.type)
            {
            case EventType.Repaint:
                RepaintEventsGUI(context);
                break;

            case EventType.MouseDown:
                if (_Area.Contains(currentGUIEvent.mousePosition))
                {
                    OnMouseDown(currentGUIEvent, context, out addEventNormalizedTime);
                }
                break;

            case EventType.MouseUp:
                if (currentGUIEvent.button == 1 &&
                    _Area.Contains(currentGUIEvent.mousePosition))
                {
                    ShowContextMenu(currentGUIEvent, context);
                    currentGUIEvent.Use();
                }
                break;

            case EventType.MouseDrag:
                if (_Duration <= 0)
                {
                    break;
                }

                var hotControl = GUIUtility.hotControl;
                if (hotControl == baseControlID)
                {
                    SetPreviewTime(currentGUIEvent);
                    GUIUtility.ExitGUI();
                }
                else
                {
                    for (int i = 0; i < EventTimes.Count; i++)
                    {
                        if (hotControl == EventControlIDs[i])
                        {
                            if (context.Times.Count < 1)
                            {
                                context.Times.Count = 1;
                            }
                            var timeProperty = context.Times.GetElement(i);
                            var seconds      = PixelsToSeconds(currentGUIEvent.mousePosition.x);
                            timeProperty.floatValue = seconds / _Duration;
                            timeProperty.serializedObject.ApplyModifiedProperties();
                            GUIUtility.hotControl = EventControlIDs[context.SelectedEvent];
                            GUI.changed           = true;

                            SetPreviewTime(currentGUIEvent);
                            GUIUtility.ExitGUI();
                        }
                    }
                }
                break;

            case EventType.KeyUp:
                if (GUIUtility.keyboardControl != selectedEventControlID)
                {
                    break;
                }

                var exitGUI = false;

                switch (currentGUIEvent.keyCode)
                {
                case KeyCode.Delete:
                case KeyCode.Backspace:
                    EventSequenceDrawer.RemoveEvent(context, context.SelectedEvent);
                    exitGUI = true;
                    break;

                case KeyCode.LeftArrow: NudgeEventTime(context, Event.current.shift ? -10 : -1); break;

                case KeyCode.RightArrow: NudgeEventTime(context, Event.current.shift ? 10 : 1); break;

                case KeyCode.Space: RoundEventTime(context); break;

                default: return;        // Don't call Use.
                }

                currentGUIEvent.Use();
                GUI.changed = true;

                if (exitGUI)
                {
                    GUIUtility.ExitGUI();
                }
                break;
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Draws the details of the <see cref="EventSequenceDrawer.Context.Callbacks"/>.
        /// </summary>
        public void DoEventsGUI(EventSequenceDrawer.Context context, out float addEventNormalizedTime)
        {
            addEventNormalizedTime = float.NaN;
            var currentGUIEvent = Event.current;

            EventControlIDs.Clear();
            var selectedEventControlID = -1;

            var baseControlID = GUIUtility.GetControlID(EventHash - 1, FocusType.Passive);

            for (int i = 0; i < EventTimes.Count; i++)
            {
                var controlID = GUIUtility.GetControlID(EventHash + i, FocusType.Keyboard);
                EventControlIDs.Add(controlID);
                if (context.SelectedEvent == i)
                {
                    selectedEventControlID = controlID;
                }
            }

            EventControlIDs.Add(baseControlID);

            switch (currentGUIEvent.type)
            {
            case EventType.Repaint:
                RepaintEventsGUI(context);
                break;

            case EventType.MouseDown:
                if (_Area.Contains(currentGUIEvent.mousePosition))
                {
                    OnMouseDown(currentGUIEvent, context, out addEventNormalizedTime);
                }
                break;

            case EventType.MouseDrag:
                if (GUIUtility.hotControl == baseControlID)
                {
                    SetPreviewTime(currentGUIEvent);
                    GUIUtility.ExitGUI();
                }
                break;

            case EventType.KeyUp:
                if (GUIUtility.keyboardControl != selectedEventControlID)
                {
                    break;
                }

                var exitGUI = false;

                switch (currentGUIEvent.keyCode)
                {
                case KeyCode.Delete:
                case KeyCode.Backspace:
                    EventSequenceDrawer.RemoveEvent(context, context.SelectedEvent);
                    exitGUI = true;
                    break;

                case KeyCode.LeftArrow: NudgeEventTime(context, false); break;

                case KeyCode.RightArrow: NudgeEventTime(context, true); break;

                case KeyCode.Space: RoundEventTime(context); break;

                default: return;        // Don't call Use.
                }

                currentGUIEvent.Use();
                GUI.changed = true;

                if (exitGUI)
                {
                    GUIUtility.ExitGUI();
                }
                break;
            }
        }