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

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;
}
}
}