211 lines
7.8 KiB
C#
211 lines
7.8 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
|
|
|
|
#if UNITY_EDITOR && UNITY_IMGUI
|
|
|
|
using System;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using static Animancer.Editor.AnimancerGUI;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace Animancer.Editor.Previews
|
|
{
|
|
/// <summary>[Editor-Only]
|
|
/// An interactive preview which displays the internal details of an <see cref="AnimancerComponent"/>.
|
|
/// </summary>
|
|
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.Previews/AnimancerComponentPreview
|
|
[CustomPreview(typeof(AnimancerComponent))]
|
|
public class AnimancerComponentPreview : ObjectPreview
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
private static readonly GUIContent
|
|
Title = new(nameof(Animancer));
|
|
|
|
/// <inheritdoc/>
|
|
public override GUIContent GetPreviewTitle()
|
|
=> Title;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
[NonSerialized] private IAnimancerComponent _Animancer;
|
|
[NonSerialized] private UnityEditor.Editor _Editor;
|
|
|
|
/// <summary>The drawer for the <see cref="IAnimancerComponent.Graph"/>.</summary>
|
|
private readonly AnimancerGraphDrawer
|
|
GraphDrawer = new();
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override void Initialize(Object[] targets)
|
|
{
|
|
_Animancer = targets.Length == 1
|
|
? targets[0] as IAnimancerComponent
|
|
: null;
|
|
|
|
_Editor = UnityEditor.Editor.CreateEditor(targets);
|
|
|
|
base.Initialize(targets);
|
|
|
|
EditorApplication.update += Update;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override void Cleanup()
|
|
{
|
|
EditorApplication.update -= Update;
|
|
|
|
Object.DestroyImmediate(_Editor);
|
|
|
|
base.Cleanup();
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override bool HasPreviewGUI()
|
|
=> !_Animancer.IsNullOrDestroyed()
|
|
&& _Animancer.IsGraphInitialized;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
private static GUIStyle _ToolbarButtonStyle;
|
|
|
|
/// <inheritdoc/>
|
|
public override void OnPreviewSettings()
|
|
{
|
|
base.OnPreviewSettings();
|
|
|
|
_ToolbarButtonStyle ??= new(EditorStyles.toolbarButton)
|
|
{
|
|
padding = new(),
|
|
};
|
|
|
|
var graph = _Animancer.Graph;
|
|
|
|
if (!graph.IsGraphPlaying)
|
|
{
|
|
var stepArea = GUILayoutUtility.GetRect(LineHeight * 1.5f, LineHeight);
|
|
AnimancerGraphControls.DoFrameStepButton(stepArea, graph, _ToolbarButtonStyle);
|
|
}
|
|
|
|
var area = GUILayoutUtility.GetRect(LineHeight * 1.5f, LineHeight);
|
|
AnimancerGraphControls.DoPlayPauseToggle(area, graph, _ToolbarButtonStyle);
|
|
|
|
area = GUILayoutUtility.GetRect(LineHeight * 2f, LineHeight);
|
|
AnimancerGraphSpeedSlider.Instance.Graph = graph;
|
|
AnimancerGraphSpeedSlider.Instance.DoToggleGUI(area, _ToolbarButtonStyle);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
[NonSerialized]
|
|
private static GUIStyle _PaddingStyle;
|
|
|
|
[NonSerialized]
|
|
private Rect _Area;
|
|
|
|
[SerializeField]
|
|
private Vector2 _ScrollPosition;
|
|
|
|
/// <inheritdoc/>
|
|
public override void OnInteractivePreviewGUI(Rect area, GUIStyle background)
|
|
{
|
|
_PaddingStyle ??= new()
|
|
{
|
|
padding = new((int)StandardSpacing, (int)StandardSpacing, (int)StandardSpacing, (int)StandardSpacing),
|
|
};
|
|
|
|
// The area isn't properly set during Layout events so remember it after each Repaint.
|
|
|
|
if (area.y == 0)
|
|
area.y = EditorStyles.toolbar.fixedHeight + 1;
|
|
|
|
if (Event.current.type == EventType.Repaint)
|
|
_Area = area;
|
|
|
|
// Draw the graph.
|
|
|
|
var labelWidth = EditorGUIUtility.labelWidth;
|
|
EditorGUIUtility.labelWidth += IndentSize;
|
|
|
|
GUILayout.BeginArea(_Area);
|
|
_ScrollPosition = GUILayout.BeginScrollView(_ScrollPosition, _PaddingStyle);
|
|
|
|
GraphDrawer.DoGUI(_Animancer);
|
|
|
|
GUILayout.EndScrollView();
|
|
GUILayout.EndArea();
|
|
|
|
EditorGUIUtility.labelWidth = labelWidth;
|
|
|
|
_LastRepaintTime = EditorApplication.timeSinceStartup;
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
[NonSerialized]
|
|
private double _LastRepaintTime = double.NegativeInfinity;
|
|
|
|
/// <summary>Repaints the preview if necessary.</summary>
|
|
private void Update()
|
|
{
|
|
if (!HasPreviewGUI() ||
|
|
!UnityEditorInternal.InternalEditorUtility.isApplicationActive)
|
|
return;
|
|
|
|
var targetDeltaTime = 1f / AnimancerComponentPreviewSettings.RepaintRate;
|
|
var nextRepaintTime = _LastRepaintTime + targetDeltaTime;
|
|
|
|
if (EditorApplication.timeSinceStartup > nextRepaintTime)
|
|
_Editor.Repaint();
|
|
|
|
// This seems to be the least hacky way to repaint only the Inspector window.
|
|
// Ideally an interactive preview would have a way to repaint itself.
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#region Settings
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>[Editor-Only] Settings for <see cref="AnimancerComponentPreview"/>.</summary>
|
|
/// https://kybernetik.com.au/animancer/api/Animancer.Editor.Previews/AnimancerComponentPreviewSettings
|
|
[Serializable, InternalSerializableType]
|
|
public class AnimancerComponentPreviewSettings : AnimancerSettingsGroup
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
public override string DisplayName
|
|
=> "Live Inspector";
|
|
|
|
/// <inheritdoc/>
|
|
public override int Index
|
|
=> 1;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
[SerializeField, Range(1, 100)]
|
|
[Tooltip("The target frame rate of repaint commands (FPS)")]
|
|
private float _RepaintRate = 30;
|
|
|
|
/// <summary>The target frame rate of repaint commands (FPS).</summary>
|
|
public static float RepaintRate
|
|
=> AnimancerSettingsGroup<AnimancerComponentPreviewSettings>.Instance._RepaintRate;
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
#endregion
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
#endif
|