/************************************************************************************************************************/ private void DoPreviewButtonGUI(ref Rect area, SerializedProperty property, bool wasPreviewing) { if (property.serializedObject.targetObjects.Length != 1 || !TransitionPreviewWindow.CanBePreviewed(property)) { return; } var buttonArea = AnimancerGUI.StealFromRight(ref area, area.height + AnimancerGUI.StandardSpacing * 2, AnimancerGUI.StandardSpacing); var content = AnimancerGUI.TempContent("", "Preview this transition"); content.image = TransitionPreviewWindow.Icon; var style = ObjectPool.GetCachedResult(() => new GUIStyle(AnimancerGUI.MiniButton) { #if UNITY_2019_3_OR_NEWER padding = new RectOffset(0, 0, 0, 1), #else padding = new RectOffset(), #endif fixedWidth = 0, fixedHeight = 0, }); var isPrevewing = GUI.Toggle(buttonArea, wasPreviewing, content, style); if (wasPreviewing != isPrevewing) { TransitionPreviewWindow.Open(property, isPrevewing); } content.image = null; }
/************************************************************************************************************************/ /// <summary>Draws the root `property` GUI and calls <see cref="DoChildPropertyGUI"/> for each of its children.</summary> public override void OnGUI(Rect area, SerializedProperty property, GUIContent label) { InitializeMode(property); // Highlight the whole area if this transition is currently being previewed. var isPreviewing = TransitionPreviewWindow.IsPreviewing(property); if (isPreviewing) { var highlightArea = area; highlightArea.xMin -= AnimancerGUI.IndentSize; EditorGUI.DrawRect(highlightArea, new Color(0.35f, 0.5f, 1, 0.2f)); } var headerArea = area; if (property.propertyType == SerializedPropertyType.ManagedReference) { DoPreviewButtonGUI(ref headerArea, property, isPreviewing); } using (new TypeSelectionButton(headerArea, property, true)) { DoPropertyGUI(area, property, label, isPreviewing); } }
/************************************************************************************************************************/ /// <summary>Draws a small button using the <see cref="TransitionPreviewWindow.Icon"/>.</summary> private static void DoPreviewButtonGUI(ref Rect area, SerializedProperty property, bool isPreviewing) { if (property.serializedObject.targetObjects.Length != 1 || !TransitionPreviewWindow.CanBePreviewed(property)) { return; } var enabled = GUI.enabled; var currentEvent = Event.current; if (currentEvent.button == 1)// Ignore Right Clicks on the Preview Button. { switch (currentEvent.type) { case EventType.MouseDown: case EventType.MouseUp: case EventType.ContextClick: GUI.enabled = false; break; } } var tooltip = isPreviewing ? TransitionPreviewWindow.Inspector.CloseTooltip : "Preview this transition"; if (DoPreviewButtonGUI(ref area, isPreviewing, tooltip)) { TransitionPreviewWindow.OpenOrClose(property); } GUI.enabled = enabled; }
/************************************************************************************************************************/ private void SetPreviewTime(Event currentGUIEvent) { if (_Duration > 0) { var seconds = PixelsToSeconds(currentGUIEvent.mousePosition.x); TransitionPreviewWindow.SetPreviewNormalizedTime(seconds / _Duration); } }
/************************************************************************************************************************/ private void DoPreviewButtonGUI(ref Rect area, SerializedProperty property, bool wasPreviewing) { if (property.serializedObject.targetObjects.Length != 1 || !TransitionPreviewWindow.CanBePreviewed(property)) { return; } var buttonArea = AnimancerGUI.StealFromRight(ref area, area.height + AnimancerGUI.StandardSpacing * 2, AnimancerGUI.StandardSpacing); var content = AnimancerGUI.TempContent("", "Preview this transition"); content.image = TransitionPreviewWindow.Icon; EditorGUI.BeginProperty(buttonArea, content, property); var style = ObjectPool.GetCachedResult(() => new GUIStyle(AnimancerGUI.MiniButton) { #if UNITY_2019_3_OR_NEWER padding = new RectOffset(0, 0, 0, 1), #else padding = new RectOffset(), #endif fixedWidth = 0, fixedHeight = 0, }); var enabled = GUI.enabled; var currentEvent = Event.current; if (currentEvent.button == 1)// Ignore Right Clicks on the Preview Button. { switch (currentEvent.type) { case EventType.MouseDown: case EventType.MouseUp: case EventType.ContextClick: GUI.enabled = false; break; } } var isPrevewing = GUI.Toggle(buttonArea, wasPreviewing, content, style); if (wasPreviewing != isPrevewing) { TransitionPreviewWindow.Open(property, isPrevewing); } GUI.enabled = enabled; content.image = null; EditorGUI.EndProperty(); }
/// <summary>Draws a button to add a new event.</summary> public void DoAddEventButtonGUI(Rect area, Context context) { if (!GUI.Button(area, AddEventContent, Styles.AddEventStyle)) { return; } // If the target is currently being previewed, add the event at the currently selected time. var state = TransitionPreviewWindow.GetCurrentState(); var normalizedTime = state != null ? state.NormalizedTime : float.NaN; AddEvent(context, normalizedTime); }
/************************************************************************************************************************/ /// <summary> /// Draws the root `property` GUI and calls <see cref="DoPropertyGUI"/> for each of its children. /// </summary> public override void OnGUI(Rect area, SerializedProperty property, GUIContent label) { InitialiseMode(property); using (TransitionContext.Get(this, property)) { var isPreviewing = TransitionPreviewWindow.IsPreviewingCurrentProperty(); if (isPreviewing) { EditorGUI.DrawRect(area, new Color(0.35f, 0.5f, 1, 0.2f)); } float headerHeight; DoHeaderGUI(area, property, label, isPreviewing, out headerHeight); DoChildPropertiesGUI(area, headerHeight, property); } }
/************************************************************************************************************************/ /// <summary> /// Draws the root `property` GUI and calls <see cref="DoPropertyGUI"/> for each of its children. /// </summary> public override void OnGUI(Rect area, SerializedProperty property, GUIContent label) { InitialiseMode(property); using (TransitionContext.Get(this, property)) { // Highlight the area if this transition is currently being previewed. var isPreviewing = TransitionPreviewWindow.IsPreviewingCurrentProperty(); if (isPreviewing) { var highlightArea = area; highlightArea.xMin -= AnimancerGUI.IndentSize; EditorGUI.DrawRect(highlightArea, new Color(0.35f, 0.5f, 1, 0.2f)); } float headerHeight; DoHeaderGUI(area, property, label, isPreviewing, out headerHeight); DoChildPropertiesGUI(area, headerHeight, property); } }
/// <summary>Draws a button to add a new event or remove the selected one.</summary> public void DoAddRemoveEventButtonGUI(Rect area, Context context) { if (_AddRemoveEventStyle == null) { _AddRemoveEventStyle = new GUIStyle(EditorStyles.miniButton) { fixedHeight = 0, } } ; if (ShowAddButton(context)) { if (_AddEventContent == null) { _AddEventContent = EditorGUIUtility.IconContent("Animation.AddEvent", Strings.ProOnlyTag + "Add event"); } _AddRemoveEventStyle.padding = new RectOffset(-1, 1, 0, 0); if (GUI.Button(area, _AddEventContent, _AddRemoveEventStyle)) { // If the target is currently being previewed, add the event at the currently selected time. var state = TransitionPreviewWindow.GetCurrentState(); var normalizedTime = state != null ? state.NormalizedTime : float.NaN; AddEvent(context, normalizedTime); } } else { _AddRemoveEventStyle.padding = new RectOffset(1, 1, 0, 0); using (ObjectPool.Disposable.AcquireContent(out var content, "X", "Remove selected event")) { if (GUI.Button(area, content, _AddRemoveEventStyle)) { RemoveEvent(context, context.SelectedEvent); } } } }
/************************************************************************************************************************/ 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; } }
/************************************************************************************************************************/ public override void OnInspectorGUI() { GUILayout.Space(AnimancerGUI.StandardSpacing * 2); Target = (TransitionPreviewWindow)target; if (Event.current.type == EventType.MouseDown) { Target.ShowTab(); } _CurrentTab = GUILayout.Toolbar(_CurrentTab, TabNames); _CurrentTab = Mathf.Clamp(_CurrentTab, 0, TabNames.Length - 1); switch (_CurrentTab) { case PreviewTab: DoPreviewInspectorGUI(); break; case SettingsTab: Settings.DoInspectorGUI(); break; default: GUILayout.Label("Tab index is out of bounds"); break; } }
/************************************************************************************************************************/ private void DoPreviewButtonGUI(ref Rect area, SerializedProperty property, bool wasPreviewing) { if (property.serializedObject.targetObjects.Length != 1 || !TransitionPreviewWindow.CanBePreviewed(property)) { return; } var buttonArea = AnimancerGUI.StealFromRight(ref area, area.height + AnimancerGUI.StandardSpacing * 2, AnimancerGUI.StandardSpacing); var content = AnimancerGUI.TempContent("", "Preview this transition"); content.image = TransitionPreviewWindow.Icon; var isPrevewing = GUI.Toggle(buttonArea, wasPreviewing, content, Styles.PreviewButtonStyle); if (wasPreviewing != isPrevewing) { TransitionPreviewWindow.Open(property, isPrevewing); } content.image = null; }
/// <summary> /// Draws ticks and labels for important times throughout the area. /// </summary> public void DoRulerGUI() { if (Event.current.type != EventType.Repaint) { return; } var tickHeight = Mathf.Ceil(_Area.height * TickHeight); var area = new Rect(SecondsToPixels(0), _Area.yMax - tickHeight, 0, tickHeight) { xMax = SecondsToPixels(_Duration) }; #if !UNITY_2019_1_OR_NEWER area.height++; #endif 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); } } var state = TransitionPreviewWindow.GetCurrentState(); if (state != null) { var normalizedTime = TransitionPreviewWindow.PreviewNormalizedTime; DrawPreviewTime(normalizedTime, 1); if (state.IsLooping) { if ((int)SecondsToPixels(0) <= (int)SecondsToPixels(_Duration) + 2) { return; } while (normalizedTime * _Duration >= _MinTime + _Duration) { normalizedTime -= 1; } while (normalizedTime * _Duration <= _MaxTime) { DrawPreviewTime(normalizedTime, 0.25f); normalizedTime += 1; } } } }
/// <summary> /// Draws ticks and labels for important times throughout the area. /// </summary> public void DoRulerGUI() { if (Event.current.type != EventType.Repaint) { return; } var tickHeight = _Area.height * TickHeight; 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); for (int i = 0; i < EventTimes.Count; i++) { TickTimes.Add(EventTimes[i]); } 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); } } var state = TransitionPreviewWindow.GetCurrentState(); if (state != null) { var time = state.Time; DrawPreviewTime(time, 1); if (state.IsLooping) { while (time >= _MinTime + _Duration) { time -= _Duration; } while (time <= _MaxTime) { DrawPreviewTime(time, 0.25f); time += _Duration; } } } }
/// <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(); } } }