You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
12 KiB
353 lines
12 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
|
|
namespace UnityEditor.Timeline
|
|
{
|
|
class ClipInspectorCurveEditor
|
|
{
|
|
CurveEditor m_CurveEditor;
|
|
CurveWrapper[] m_CurveWrappers;
|
|
|
|
const float k_HeaderHeight = 30;
|
|
const float k_PresetHeight = 30;
|
|
|
|
Action<AnimationCurve, EditorCurveBinding> m_CurveUpdatedCallback;
|
|
GUIContent m_TextContent = new GUIContent();
|
|
|
|
GUIStyle m_LabelStyle;
|
|
GUIStyle m_LegendStyle;
|
|
|
|
// Track time. controls the position of the track head
|
|
public static readonly double kDisableTrackTime = double.NaN;
|
|
double m_trackTime = kDisableTrackTime;
|
|
public double trackTime { get { return m_trackTime; } set { m_trackTime = value; } }
|
|
|
|
public string headerString { get; set; }
|
|
|
|
public ClipInspectorCurveEditor()
|
|
{
|
|
var curveEditorSettings = new CurveEditorSettings
|
|
{
|
|
allowDeleteLastKeyInCurve = false,
|
|
allowDraggingCurvesAndRegions = true,
|
|
hTickLabelOffset = 0.1f,
|
|
showAxisLabels = true,
|
|
useFocusColors = false,
|
|
wrapColor = new EditorGUIUtility.SkinnedColor(Color.black),
|
|
hSlider = false,
|
|
hRangeMin = 0.0f,
|
|
vRangeMin = 0.0F,
|
|
vRangeMax = 1.0f,
|
|
hRangeMax = 1.0F,
|
|
vSlider = false,
|
|
hRangeLocked = false,
|
|
vRangeLocked = false,
|
|
undoRedoSelection = true,
|
|
|
|
|
|
hTickStyle = new TickStyle
|
|
{
|
|
tickColor = new EditorGUIUtility.SkinnedColor(new Color(0.0f, 0.0f, 0.0f, 0.2f)),
|
|
distLabel = 30,
|
|
stubs = false,
|
|
centerLabel = true
|
|
},
|
|
|
|
vTickStyle = new TickStyle
|
|
{
|
|
tickColor = new EditorGUIUtility.SkinnedColor(new Color(1.0f, 0.0f, 0.0f, 0.2f)),
|
|
distLabel = 20,
|
|
stubs = false,
|
|
centerLabel = true
|
|
}
|
|
};
|
|
|
|
m_CurveEditor = new CurveEditor(new Rect(0, 0, 1000, 100), new CurveWrapper[0], true)
|
|
{
|
|
settings = curveEditorSettings,
|
|
ignoreScrollWheelUntilClicked = true
|
|
};
|
|
}
|
|
|
|
internal bool InitStyles()
|
|
{
|
|
if (EditorStyles.s_Current == null)
|
|
return false;
|
|
|
|
if (m_LabelStyle == null)
|
|
{
|
|
m_LabelStyle = new GUIStyle(EditorStyles.whiteLargeLabel);
|
|
m_LegendStyle = new GUIStyle(EditorStyles.miniBoldLabel);
|
|
|
|
m_LabelStyle.alignment = TextAnchor.MiddleCenter;
|
|
m_LegendStyle.alignment = TextAnchor.MiddleCenter;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
internal void OnGUI(Rect clientRect, CurvePresetLibrary presets)
|
|
{
|
|
const float presetPad = 30.0f;
|
|
|
|
if (!InitStyles())
|
|
return;
|
|
|
|
if (m_CurveWrappers == null || m_CurveWrappers.Length == 0)
|
|
return;
|
|
|
|
// regions
|
|
var headerRect = new Rect(clientRect.x, clientRect.y, clientRect.width, k_HeaderHeight);
|
|
var curveRect = new Rect(clientRect.x, clientRect.y + headerRect.height, clientRect.width, clientRect.height - k_HeaderHeight - k_PresetHeight);
|
|
var presetRect = new Rect(clientRect.x + presetPad, clientRect.y + curveRect.height + k_HeaderHeight, clientRect.width - presetPad, k_PresetHeight);
|
|
|
|
GUI.Box(headerRect, headerString, m_LabelStyle);
|
|
|
|
//Case 1201474 : Force to update only when Repaint event is called as the new rect provided on other event create a wrong curve editor computation.
|
|
if (Event.current.type == EventType.Repaint)
|
|
{
|
|
m_CurveEditor.rect = curveRect;
|
|
m_CurveEditor.shownAreaInsideMargins = new Rect(0, 0, 1, 1);
|
|
}
|
|
m_CurveEditor.animationCurves = m_CurveWrappers;
|
|
UpdateSelectionColors();
|
|
|
|
DrawTrackHead(curveRect);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
m_CurveEditor.OnGUI();
|
|
DrawPresets(presetRect, presets);
|
|
|
|
bool hasChanged = EditorGUI.EndChangeCheck();
|
|
|
|
if (presets == null)
|
|
DrawLegend(presetRect);
|
|
|
|
if (hasChanged)
|
|
ProcessUpdates();
|
|
|
|
ConsumeMouseEvents(clientRect);
|
|
}
|
|
|
|
static void ConsumeMouseEvents(Rect rect)
|
|
{
|
|
var isMouseEvent = Event.current.type == EventType.MouseUp || Event.current.type == EventType.MouseDown;
|
|
if (isMouseEvent && rect.Contains(Event.current.mousePosition))
|
|
Event.current.Use();
|
|
}
|
|
|
|
void DrawPresets(Rect position, PresetLibrary curveLibrary)
|
|
{
|
|
if (curveLibrary == null || curveLibrary.Count() == 0)
|
|
return;
|
|
|
|
const int maxNumPresets = 9;
|
|
int numPresets = curveLibrary.Count();
|
|
int showNumPresets = Mathf.Min(numPresets, maxNumPresets);
|
|
|
|
const float swatchWidth = 30;
|
|
const float swatchHeight = 15;
|
|
const float spaceBetweenSwatches = 10;
|
|
float presetButtonsWidth = showNumPresets * swatchWidth + (showNumPresets - 1) * spaceBetweenSwatches;
|
|
float flexWidth = (position.width - presetButtonsWidth) * 0.5f;
|
|
|
|
// Preset swatch area
|
|
float curY = (position.height - swatchHeight) * 0.5f;
|
|
float curX = 3.0f;
|
|
if (flexWidth > 0)
|
|
curX = flexWidth;
|
|
|
|
GUI.BeginGroup(position);
|
|
|
|
for (int i = 0; i < showNumPresets; i++)
|
|
{
|
|
if (i > 0)
|
|
curX += spaceBetweenSwatches;
|
|
|
|
var swatchRect = new Rect(curX, curY, swatchWidth, swatchHeight);
|
|
m_TextContent.tooltip = curveLibrary.GetName(i);
|
|
if (GUI.Button(swatchRect, m_TextContent, GUIStyle.none))
|
|
{
|
|
// if there is only 1, no need to specify
|
|
IEnumerable<CurveWrapper> wrappers = m_CurveWrappers;
|
|
if (m_CurveWrappers.Length > 1)
|
|
wrappers = m_CurveWrappers.Where(x => x.selected == CurveWrapper.SelectionMode.Selected);
|
|
|
|
foreach (var wrapper in wrappers)
|
|
{
|
|
var presetCurve = (AnimationCurve)curveLibrary.GetPreset(i);
|
|
wrapper.curve.keys = (Keyframe[])presetCurve.keys.Clone();
|
|
wrapper.changed = true;
|
|
}
|
|
|
|
// case 1259902 - flushes internal selection caches preventing index out of range exceptions
|
|
m_CurveEditor.SelectNone();
|
|
foreach (var wrapper in wrappers)
|
|
wrapper.selected = CurveWrapper.SelectionMode.Selected;
|
|
}
|
|
|
|
if (Event.current.type == EventType.Repaint)
|
|
curveLibrary.Draw(swatchRect, i);
|
|
|
|
curX += swatchWidth;
|
|
}
|
|
|
|
GUI.EndGroup();
|
|
}
|
|
|
|
// draw a line representing where in the current clip we are
|
|
void DrawTrackHead(Rect clientRect)
|
|
{
|
|
DirectorStyles styles = TimelineWindow.styles;
|
|
if (styles == null)
|
|
return;
|
|
|
|
if (!double.IsNaN(m_trackTime))
|
|
{
|
|
float x = m_CurveEditor.TimeToPixel((float)m_trackTime, clientRect);
|
|
x = Mathf.Clamp(x, clientRect.xMin, clientRect.xMax);
|
|
var p1 = new Vector2(x, clientRect.yMin);
|
|
var p2 = new Vector2(x, clientRect.yMax);
|
|
Graphics.DrawLine(p1, p2, DirectorStyles.Instance.customSkin.colorPlayhead);
|
|
}
|
|
}
|
|
|
|
// Draws a legend for the displayed curves
|
|
void DrawLegend(Rect r)
|
|
{
|
|
if (m_CurveWrappers == null || m_CurveWrappers.Length == 0)
|
|
return;
|
|
|
|
Color c = GUI.color;
|
|
float boxWidth = r.width / m_CurveWrappers.Length;
|
|
for (int i = 0; i < m_CurveWrappers.Length; i++)
|
|
{
|
|
CurveWrapper cw = m_CurveWrappers[i];
|
|
if (cw != null)
|
|
{
|
|
var pos = new Rect(r.x + i * boxWidth, r.y, boxWidth, r.height);
|
|
var textColor = cw.color;
|
|
textColor.a = 1;
|
|
GUI.color = textColor;
|
|
string name = LabelName(cw.binding.propertyName);
|
|
EditorGUI.LabelField(pos, name, m_LegendStyle);
|
|
}
|
|
}
|
|
GUI.color = c;
|
|
}
|
|
|
|
// Helper for making label name appropriately small
|
|
static char[] s_LabelMarkers = { '_' };
|
|
|
|
static string LabelName(string propertyName)
|
|
{
|
|
propertyName = AnimationWindowUtility.GetPropertyDisplayName(propertyName);
|
|
int index = propertyName.LastIndexOfAny(s_LabelMarkers);
|
|
if (index >= 0)
|
|
propertyName = propertyName.Substring(index);
|
|
return propertyName;
|
|
}
|
|
|
|
public void SetCurve(AnimationCurve curve)
|
|
{
|
|
if (m_CurveWrappers == null || m_CurveWrappers.Length != 1)
|
|
{
|
|
m_CurveWrappers = new CurveWrapper[1];
|
|
var cw = new CurveWrapper
|
|
{
|
|
renderer = new NormalCurveRenderer(curve),
|
|
readOnly = false,
|
|
color = EditorGUI.kCurveColor,
|
|
id = 0xFEED,
|
|
hidden = false,
|
|
regionId = -1
|
|
};
|
|
|
|
cw.renderer.SetWrap(WrapMode.Clamp, WrapMode.Clamp);
|
|
cw.renderer.SetCustomRange(0, 1);
|
|
m_CurveWrappers[0] = cw;
|
|
|
|
UpdateSelectionColors();
|
|
m_CurveEditor.animationCurves = m_CurveWrappers;
|
|
}
|
|
else
|
|
{
|
|
m_CurveWrappers[0].renderer = new NormalCurveRenderer(curve);
|
|
}
|
|
}
|
|
|
|
internal void SetUpdateCurveCallback(Action<AnimationCurve, EditorCurveBinding> callback)
|
|
{
|
|
m_CurveUpdatedCallback = callback;
|
|
}
|
|
|
|
void ProcessUpdates()
|
|
{
|
|
foreach (var cw in m_CurveWrappers)
|
|
{
|
|
if (cw.changed)
|
|
{
|
|
cw.changed = false;
|
|
|
|
if (m_CurveUpdatedCallback != null)
|
|
m_CurveUpdatedCallback(cw.curve, cw.binding);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetSelected(AnimationCurve curve)
|
|
{
|
|
m_CurveEditor.SelectNone();
|
|
if (m_CurveWrappers != null && m_CurveWrappers.Length > 0)
|
|
{
|
|
if (m_CurveWrappers[0].renderer.GetCurve() == curve)
|
|
{
|
|
m_CurveWrappers[0].selected = CurveWrapper.SelectionMode.Selected;
|
|
m_CurveEditor.AddSelection(new CurveSelection(m_CurveWrappers[0].id, 0));
|
|
}
|
|
}
|
|
UpdateSelectionColors();
|
|
}
|
|
|
|
void UpdateSelectionColors()
|
|
{
|
|
if (m_CurveWrappers == null)
|
|
return;
|
|
|
|
// manually manage selection colors
|
|
foreach (var cw in m_CurveWrappers)
|
|
{
|
|
Color c = cw.color;
|
|
if (cw.readOnly)
|
|
c.a = 0.75f;
|
|
else if (cw.selected != CurveWrapper.SelectionMode.None)
|
|
c.a = 1.0f;
|
|
else
|
|
c.a = 0.5f;
|
|
cw.color = c;
|
|
}
|
|
}
|
|
|
|
public static void CurveField(GUIContent title, SerializedProperty property, Action<SerializedProperty> onClick)
|
|
{
|
|
Rect controlRect = EditorGUILayout.GetControlRect(GUILayout.MinWidth(20));
|
|
EditorGUI.BeginProperty(controlRect, title, property);
|
|
DrawCurve(controlRect, property, onClick, EditorGUI.kCurveColor, EditorGUI.kCurveBGColor);
|
|
EditorGUI.EndProperty();
|
|
}
|
|
|
|
static Rect DrawCurve(Rect controlRect, SerializedProperty property, Action<SerializedProperty> onClick, Color fgColor, Color bgColor)
|
|
{
|
|
if (GUI.Button(controlRect, GUIContent.none))
|
|
{
|
|
if (onClick != null)
|
|
onClick(property);
|
|
}
|
|
EditorGUIUtility.DrawCurveSwatch(controlRect, null, property, fgColor, bgColor);
|
|
return controlRect;
|
|
}
|
|
}
|
|
}
|
|
|