123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR && UNITY_IMGUI
- using Animancer.Editor.Previews;
- using System;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEngine;
- namespace Animancer.Editor
- {
- /// <summary>[Editor-Only] Draws a GUI box denoting a period of time.</summary>
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor/TimelineGUI
- ///
- public class TimelineGUI : IDisposable
- {
- /************************************************************************************************************************/
- #region Fields
- /************************************************************************************************************************/
- private static readonly ConversionCache<float, string>
- G2Cache = new(value =>
- {
- if (Math.Abs(value) <= 99)
- return value.ToString("G2");
- else
- return ((int)value).ToString();
- });
- private static Texture _EventIcon;
- /// <summary>The icon used for events.</summary>
- public static Texture EventIcon
- => AnimancerIcons.Load(ref _EventIcon, "Animation.EventMarker");
- private static readonly Color
- FadeHighlightColor = new(0.35f, 0.5f, 1, 0.5f),
- SelectedEventColor = new(0.3f, 0.55f, 0.95f),
- UnselectedEventColor = AnimancerGUI.Grey(0.9f),
- PreviewTimeColor = AnimancerStateDrawerColors.FadeLineColor,
- BaseTimeColor = AnimancerGUI.Grey(0.5f, 0.75f);
- private Rect _Area;
- /// <summary>The pixel area in which this <see cref="TimelineGUI"/> is drawing.</summary>
- public Rect Area => _Area;
- private float _Speed, _Duration, _MinTime, _MaxTime, _StartTime, _EndTime, _FadeInEnd, _FadeOutEnd, _SecondsToPixels;
- private bool _HasEndTime;
- private readonly List<float>
- EventTimes = new();
- /// <summary>The height of the time ticks.</summary>
- public float TickHeight { get; private set; }
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- #region Conversions
- /************************************************************************************************************************/
- /// <summary>Converts a number of seconds to a horizontal pixel position along the ruler.</summary>
- /// <remarks>The value is rounded to the nearest integer.</remarks>
- public float SecondsToPixels(float seconds) => AnimancerUtilities.Round((seconds - _MinTime) * _SecondsToPixels);
- /// <summary>Converts a horizontal pixel position along the ruler to a number of seconds.</summary>
- public float PixelsToSeconds(float pixels) => (pixels / _SecondsToPixels) + _MinTime;
- /// <summary>Converts a number of seconds to a normalized time value.</summary>
- public float SecondsToNormalized(float seconds) => seconds / _Duration;
- /// <summary>Converts a normalized time value to a number of seconds.</summary>
- public float NormalizedToSeconds(float normalized) => normalized * _Duration;
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- private TimelineGUI() { }
- private static readonly TimelineGUI Instance = new();
- /// <summary>The currently drawing <see cref="TimelineGUI"/> (or null if none is drawing).</summary>
- public static TimelineGUI Current { get; private set; }
- /// <summary>Ends the area started by <see cref="BeginGUI"/>.</summary>
- void IDisposable.Dispose()
- {
- Current = null;
- GUI.EndClip();
- }
- /************************************************************************************************************************/
- /// <summary>
- /// Sets the `area` in which the ruler will be drawn and draws a <see cref="GUI.Box(Rect, string)"/> there.
- /// The returned object must have <see cref="IDisposable.Dispose"/> called on it afterwards.
- /// </summary>
- private static IDisposable BeginGUI(Rect area)
- {
- if (Current != null)
- throw new InvalidOperationException($"{nameof(TimelineGUI)} can't be used recursively.");
- if (!EditorGUIUtility.hierarchyMode)
- EditorGUI.indentLevel++;
- area = EditorGUI.IndentedRect(area);
- if (!EditorGUIUtility.hierarchyMode)
- EditorGUI.indentLevel--;
- GUI.Box(area, "");
- GUI.BeginClip(area);
- area.x = area.y = 0;
- Instance._Area = area;
- Instance.TickHeight = Mathf.Ceil(area.height * 0.3f);
- return Current = Instance;
- }
- /************************************************************************************************************************/
- /// <summary>Draws the ruler GUI and handles input events for the specified `context`.</summary>
- public static void DoGUI(Rect area, SerializableEventSequenceDrawer.Context context, out float addEventNormalizedTime)
- {
- using (BeginGUI(area))
- Current.DoGUI(context, out addEventNormalizedTime);
- }
- /************************************************************************************************************************/
- /// <summary>Draws the ruler GUI and handles input events for the specified `context`.</summary>
- private void DoGUI(SerializableEventSequenceDrawer.Context context, out float addEventNormalizedTime)
- {
- if (context.Property.hasMultipleDifferentValues)
- {
- GUI.Label(_Area, "Multi-editing events is not supported");
- addEventNormalizedTime = float.NaN;
- return;
- }
- var transition = context.TransitionContext.Transition;
- _Speed = transition.Speed;
- if (float.IsNaN(_Speed))
- _Speed = 1;
- _Duration = context.TransitionContext.MaximumDuration;
- if (_Duration <= 0)
- _Duration = 1;
- GatherEventTimes(context);
- _StartTime = GetStartTime(transition.NormalizedStartTime, _Speed, _Duration);
- _FadeInEnd = _StartTime + transition.FadeDuration * _Speed;
- _FadeOutEnd = GetFadeOutEnd(_Speed, _EndTime, _Duration);
- _MinTime = Mathf.Min(0, _StartTime);
- _MinTime = Mathf.Min(_MinTime, _FadeOutEnd);
- _MinTime = Mathf.Min(_MinTime, EventTimes[0]);
- _MaxTime = Mathf.Max(_StartTime, _FadeOutEnd);
- if (EventTimes.Count >= 2)
- _MaxTime = Mathf.Max(_MaxTime, EventTimes[^2]);
- if (_MaxTime < _Duration)
- _MaxTime = _Duration;
- _SecondsToPixels = _Area.width / (_MaxTime - _MinTime);
- DoFadeHighlightGUI();
- if (AnimancerUtilities.TryGetWrappedObject(transition, out ITransitionGUI gui))
- gui.OnTimelineBackgroundGUI();
- DoEventsGUI(context, out addEventNormalizedTime);
- DoRulerGUI();
- if (_Speed > 0)
- {
- if (_StartTime >= _EndTime)
- GUI.Label(_Area, "Start Time is not before End Time");
- }
- else if (_Speed < 0)
- {
- if (_StartTime <= _EndTime)
- GUI.Label(_Area, "Start Time is not after End Time");
- }
- gui?.OnTimelineForegroundGUI();
- }
- /************************************************************************************************************************/
- /// <summary>Calculates the start time of the transition (in seconds).</summary>
- public static float GetStartTime(float normalizedStartTime, float speed, float duration)
- {
- if (float.IsNaN(normalizedStartTime))
- {
- return speed < 0 ? duration : 0;
- }
- else
- {
- return normalizedStartTime * duration;
- }
- }
- /// <summary>Calculates the end time of the fade out (in seconds).</summary>
- public static float GetFadeOutEnd(float speed, float endTime, float duration)
- {
- if (speed < 0)
- return endTime > 0 ? 0 : (endTime - AnimancerGraph.DefaultFadeDuration) * -speed;
- else
- return endTime < duration ? duration : endTime + AnimancerGraph.DefaultFadeDuration * speed;
- }
- /************************************************************************************************************************/
- private static readonly Vector3[] QuadVertices = new Vector3[4];
- /// <summary>Draws a polygon describing the start, end, and fade details.</summary>
- private void DoFadeHighlightGUI()
- {
- if (Event.current.type != EventType.Repaint)
- return;
- var color = Handles.color;
- Handles.color = FadeHighlightColor;
- QuadVertices[0] = new(SecondsToPixels(_StartTime), _Area.y);
- QuadVertices[1] = new(SecondsToPixels(_FadeInEnd), _Area.yMax + 1);
- QuadVertices[2] = new(SecondsToPixels(_FadeOutEnd), _Area.yMax + 1);
- QuadVertices[3] = new(SecondsToPixels(_EndTime), _Area.y);
- Handles.DrawAAConvexPolygon(QuadVertices);
- Handles.color = color;
- }
- /************************************************************************************************************************/
- #region Events
- /************************************************************************************************************************/
- private void GatherEventTimes(SerializableEventSequenceDrawer.Context context)
- {
- EventTimes.Clear();
- if (context.Times.Count > 0)
- {
- var depth = context.Times.Property.depth;
- var time = context.Times.GetElement(0);
- while (time.depth > depth)
- {
- EventTimes.Add(time.floatValue * _Duration);
- time.Next(false);
- }
- _EndTime = EventTimes[^1];
- if (!float.IsNaN(_EndTime))
- {
- _HasEndTime = true;
- return;
- }
- }
- _EndTime = AnimancerEvent.Sequence.GetDefaultNormalizedEndTime(_Speed) * _Duration;
- _HasEndTime = false;
- if (EventTimes.Count == 0)
- EventTimes.Add(_EndTime);
- else
- EventTimes[^1] = _EndTime;
- }
- /************************************************************************************************************************/
- private static readonly int EventHash = "Event".GetHashCode();
- private static readonly List<int> EventControlIDs = new();
- /// <summary>Draws the details of the <see cref="SerializableEventSequenceDrawer.Context.Callbacks"/>.</summary>
- private void DoEventsGUI(SerializableEventSequenceDrawer.Context context, out float addEventNormalizedTime)
- {
- addEventNormalizedTime = float.NaN;
- var currentEvent = 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 (currentEvent.type)
- {
- case EventType.Repaint:
- RepaintEventsGUI(context);
- break;
- case EventType.MouseDown:
- OnMouseDown(currentEvent, context, ref addEventNormalizedTime);
- break;
- case EventType.MouseUp:
- OnMouseUp(currentEvent, context);
- break;
- case EventType.MouseDrag:
- if (_Duration <= 0)
- break;
- var hotControl = GUIUtility.hotControl;
- if (hotControl == baseControlID)
- {
- SetPreviewTime(context, currentEvent);
- 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 seconds = PixelsToSeconds(currentEvent.mousePosition.x);
- if (currentEvent.control)
- SnapToFrameRate(context, ref seconds);
- var timeProperty = context.Times.GetElement(i);
- var normalizedTime = seconds / _Duration;
- timeProperty.floatValue = normalizedTime;
- SerializableEventSequenceDrawer.SyncEventTimeChange(context, i, normalizedTime);
- timeProperty.serializedObject.ApplyModifiedProperties();
- timeProperty.serializedObject.Update();
- GUIUtility.hotControl = EventControlIDs[context.SelectedEvent];
- GUI.changed = true;
- SetPreviewTime(context, currentEvent);
- GUIUtility.ExitGUI();
- }
- }
- }
- break;
- case EventType.KeyUp:
- if (GUIUtility.keyboardControl != selectedEventControlID)
- break;
- var exitGUI = false;
- switch (currentEvent.keyCode)
- {
- case KeyCode.Delete:
- case KeyCode.Backspace:
- SerializableEventSequenceDrawer.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.
- }
- GUI.changed = true;
- currentEvent.Use();
- if (exitGUI)
- GUIUtility.ExitGUI();
- break;
- }
- }
- /************************************************************************************************************************/
- /// <summary>Snaps the `seconds` value to the nearest multiple of the <see cref="AnimationClip.frameRate"/>.</summary>
- public void SnapToFrameRate(SerializableEventSequenceDrawer.Context context, ref float seconds)
- {
- if (AnimancerUtilities.TryGetFrameRate(context.TransitionContext.Transition, out var frameRate))
- {
- seconds = AnimancerUtilities.Round(seconds, 1f / frameRate);
- }
- }
- /************************************************************************************************************************/
- private void RepaintEventsGUI(SerializableEventSequenceDrawer.Context context)
- {
- var color = GUI.color;
- for (int i = 0; i < EventTimes.Count; i++)
- {
- var currentColor = color;
- // Read Only: currentColor *= new(0.9f, 0.9f, 0.9f, 0.5f * alpha);
- if (context.SelectedEvent == i)
- {
- currentColor *= SelectedEventColor;
- }
- else
- {
- currentColor *= UnselectedEventColor;
- }
- if (i == EventTimes.Count - 1 && !_HasEndTime)
- currentColor.a *= 0.65f;
- GUI.color = currentColor;
- var area = GetEventIconArea(i);
- GUI.DrawTexture(area, EventIcon);
- }
- GUI.color = color;
- }
- /************************************************************************************************************************/
- private void OnMouseDown(Event currentEvent, SerializableEventSequenceDrawer.Context context, ref float addEventNormalizedTime)
- {
- if (!_Area.Contains(currentEvent.mousePosition))
- return;
- var selectedEventControlID = 0;
- var selectedEvent = -1;
- for (int i = 0; i < EventControlIDs.Count; i++)
- {
- var area = i < EventTimes.Count ? GetEventIconArea(i) : _Area;
- if (area.Contains(currentEvent.mousePosition))
- {
- selectedEventControlID = EventControlIDs[i];
- selectedEvent = i;
- break;
- }
- }
- if (selectedEvent < 0 || selectedEvent >= EventTimes.Count)
- {
- SetPreviewTime(context, currentEvent);
- selectedEvent = -1;
- }
- if (currentEvent.type == EventType.MouseDown &&
- currentEvent.clickCount == 2)
- {
- addEventNormalizedTime = PixelsToSeconds(currentEvent.mousePosition.x);
- addEventNormalizedTime = SecondsToNormalized(addEventNormalizedTime);
- }
- context.SelectedEvent = selectedEvent;
- GUIUtility.keyboardControl = selectedEventControlID;
- currentEvent.Use(selectedEventControlID);
- }
- /************************************************************************************************************************/
- private void OnMouseUp(Event currentEvent, SerializableEventSequenceDrawer.Context context)
- {
- if (currentEvent.button == 1 &&
- _Area.Contains(currentEvent.mousePosition))
- {
- currentEvent.Use(0);
- ShowContextMenu(currentEvent, context);
- }
- }
- /************************************************************************************************************************/
- private void ShowContextMenu(Event currentEvent, SerializableEventSequenceDrawer.Context context)
- {
- context = context.Copy();
- var time = SecondsToNormalized(PixelsToSeconds(currentEvent.mousePosition.x));
- var hasSelectedEvent = context.SelectedEvent >= 0;
- var menu = new GenericMenu();
- AddContextFunction(menu, context, "Add Event (Double Click)", true,
- () => SerializableEventSequenceDrawer.AddEvent(context, time));
- AddContextFunction(menu, context, "Remove Event (Delete)", hasSelectedEvent,
- () => SerializableEventSequenceDrawer.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();
- }
- /************************************************************************************************************************/
- private static void AddContextFunction(
- GenericMenu menu, SerializableEventSequenceDrawer.Context context, string label, bool enabled, Action function)
- {
- menu.AddFunction(label, enabled, () =>
- {
- using (context.SetAsCurrent())
- {
- function();
- GUI.changed = true;
- }
- });
- }
- /************************************************************************************************************************/
- private void SetPreviewTime(SerializableEventSequenceDrawer.Context context, Event currentEvent)
- {
- if (_Duration > 0)
- {
- var seconds = PixelsToSeconds(currentEvent.mousePosition.x);
- if (currentEvent.control)
- SnapToFrameRate(context, ref seconds);
- TransitionPreviewWindow.PreviewNormalizedTime = seconds / _Duration;
- }
- }
- /************************************************************************************************************************/
- private Rect GetEventIconArea(int index)
- {
- var width = EventIcon.width;
- var x = SecondsToPixels(EventTimes[index]) - width * 0.5f;
- x = Mathf.Clamp(x, 0, _Area.width - width);
- return new(x, _Area.y, width, EventIcon.height);
- }
- /************************************************************************************************************************/
- private void NudgeEventTime(SerializableEventSequenceDrawer.Context context, float offsetPixels)
- {
- var index = context.SelectedEvent;
- var time = context.Times.GetElement(index);
- var value = time.floatValue;
- value = NormalizedToSeconds(value);
- value = SecondsToPixels(value);
- value += offsetPixels;
- value = PixelsToSeconds(value);
- value = SecondsToNormalized(value);
- time.floatValue = value;
- SerializableEventSequenceDrawer.SyncEventTimeChange(context, index, value);
- }
- /************************************************************************************************************************/
- private static void RoundEventTime(SerializableEventSequenceDrawer.Context context)
- {
- var index = context.SelectedEvent;
- var time = context.Times.GetElement(index);
- var value = time.floatValue;
- if (TryRoundValue(ref value))
- {
- time.floatValue = value;
- SerializableEventSequenceDrawer.SyncEventTimeChange(context, index, value);
- }
- }
- private static bool TryRoundValue(ref float value)
- {
- var format = System.Globalization.NumberFormatInfo.InvariantInfo;
- var text = value.ToString(format);
- var dot = text.IndexOf('.');
- if (dot < 0)
- return false;
- Round:
- var newValue = (float)Math.Round(value, text.Length - dot - 2, MidpointRounding.AwayFromZero);
- if (newValue == value)
- {
- dot--;
- if (dot > 0)
- goto Round;
- }
- if (value != newValue)
- {
- value = newValue;
- return true;
- }
- else return false;
- }
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- #region Ticks
- /************************************************************************************************************************/
- private static readonly List<float> TickTimes = new();
- /// <summary>Draws ticks and labels for important times throughout the area.</summary>
- private void DoRulerGUI()
- {
- if (Event.current.type != EventType.Repaint)
- return;
- var area = new Rect(SecondsToPixels(0), _Area.yMax - TickHeight, 0, TickHeight)
- {
- xMax = SecondsToPixels(_Duration)
- };
- EditorGUI.DrawRect(area, BaseTimeColor);
- TickTimes.Clear();
- TickTimes.Add(0);
- TickTimes.Add(_StartTime);
- TickTimes.Add(_FadeInEnd);
- TickTimes.Add(_Duration);
- TickTimes.AddRange(EventTimes);
- TickTimes.Sort();
- var previousTime = float.NaN;
- area.x = float.NegativeInfinity;
- for (int i = 0; i < TickTimes.Count; i++)
- {
- var time = TickTimes[i];
- if (previousTime != time)
- {
- previousTime = time;
- DoRulerLabelGUI(ref area, time);
- }
- }
- DrawPreviewTime();
- }
- /************************************************************************************************************************/
- private void DrawPreviewTime()
- {
- var state = TransitionPreviewWindow.GetCurrentState();
- if (state == null)
- return;
- var normalizedTime = TransitionPreviewWindow.PreviewNormalizedTime;
- DrawPreviewTime(normalizedTime, alpha: 1);
- // Looping states show faded indicators at every other multiple of the loop.
- if (!state.IsLooping)
- return;
- // Make sure the area is actually wide enough for it to not just be a solid bar.
- if ((int)SecondsToPixels(0) > (int)SecondsToPixels(_Duration) - 4)
- return;
- // Go back to the first visible increment.
- while (normalizedTime * _Duration >= _MinTime + _Duration)
- normalizedTime -= 1;
- // Draw every visible increment from there on.
- while (normalizedTime * _Duration <= _MaxTime)
- {
- DrawPreviewTime(normalizedTime, alpha: 0.2f);
- normalizedTime += 1;
- }
- }
- private void DrawPreviewTime(float normalizedTime, float alpha)
- {
- var time = NormalizedToSeconds(normalizedTime);
- var x = SecondsToPixels(time);
- if (x >= 0 && x <= _Area.width)
- {
- var color = PreviewTimeColor;
- color.a = alpha;
- EditorGUI.DrawRect(new(x - 1, _Area.y, 2, _Area.height), color);
- }
- }
- /************************************************************************************************************************/
- private static GUIStyle _RulerLabelStyle;
- private static ConversionCache<string, float> _TimeLabelWidthCache;
- private void DoRulerLabelGUI(ref Rect previousArea, float time)
- {
- _RulerLabelStyle ??= new(GUI.skin.label)
- {
- padding = new(),
- contentOffset = new(0, -2),
- alignment = TextAnchor.UpperLeft,
- fontSize = Mathf.CeilToInt(AnimancerGUI.LineHeight * 0.6f),
- };
- var text = G2Cache.Convert(time);
- _TimeLabelWidthCache ??= ConversionCache.CreateWidthCache(_RulerLabelStyle);
- var area = new Rect(
- SecondsToPixels(time),
- _Area.y,
- _TimeLabelWidthCache.Convert(text),
- _Area.height);
- if (area.x > _Area.x)
- {
- var tickY = _Area.yMax - TickHeight;
- EditorGUI.DrawRect(new(area.x, tickY, 1, TickHeight), AnimancerGUI.TextColor);
- }
- if (area.xMax > _Area.xMax)
- area.x = _Area.xMax - area.width;
- if (area.x < 0)
- area.x = 0;
- if (area.x > previousArea.xMax + 2)
- {
- GUI.Label(area, text, _RulerLabelStyle);
- previousArea = area;
- }
- }
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- }
- }
- #endif
|