2022-01-12 10:06:03 +03:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using UnityEngine ;
using UnityEngine.Playables ;
using UnityEngine.Timeline ;
namespace UnityEditor.Timeline
{
class TimelineClipGUI : TimelineItemGUI , IClipCurveEditorOwner , ISnappable , IAttractable
{
EditorClip m_EditorItem ;
Rect m_ClipCenterSection ;
readonly List < Rect > m_LoopRects = new List < Rect > ( ) ;
ClipDrawData m_ClipDrawData ;
Rect m_MixOutRect = new Rect ( ) ;
Rect m_MixInRect = new Rect ( ) ;
int m_MinLoopIndex = 1 ;
// clip dirty detection
int m_LastDirtyIndex = Int32 . MinValue ;
bool m_ClipViewDirty = true ;
bool supportResize { get ; }
public ClipCurveEditor clipCurveEditor { get ; set ; }
public TimelineClipGUI previousClip { get ; set ; }
public TimelineClipGUI nextClip { get ; set ; }
static readonly float k_MinMixWidth = 2 ;
static readonly float k_MaxHandleWidth = 10f ;
static readonly float k_MinHandleWidth = 1f ;
bool? m_ShowDrillIcon ;
ClipEditor m_ClipEditor ;
static List < PlayableDirector > s_TempSubDirectors = new List < PlayableDirector > ( ) ;
static readonly IconData k_DiggableClipIcon = new IconData ( DirectorStyles . LoadIcon ( "TimelineDigIn" ) ) ;
string name
{
get
{
if ( string . IsNullOrEmpty ( clip . displayName ) )
return "(Empty)" ;
return clip . displayName ;
}
}
2022-01-12 10:39:15 +03:00
public bool inlineCurvesSelected = > SelectionManager . IsCurveEditorFocused ( this ) ;
2022-01-12 10:06:03 +03:00
public Rect mixOutRect
{
get
{
var percent = clip . mixOutPercentage ;
var x = Mathf . Round ( treeViewRect . width * ( 1 - percent ) ) ;
var width = Mathf . Round ( treeViewRect . width * percent ) ;
m_MixOutRect . Set ( x , 0.0f , width , treeViewRect . height ) ;
return m_MixOutRect ;
}
}
public Rect mixInRect
{
get
{
var width = Mathf . Round ( treeViewRect . width * clip . mixInPercentage ) ;
m_MixInRect . Set ( 0.0f , 0.0f , width , treeViewRect . height ) ;
return m_MixInRect ;
}
}
public ClipBlends GetClipBlends ( )
{
var _mixInRect = mixInRect ;
var _mixOutRect = mixOutRect ;
var blendInKind = BlendKind . None ;
if ( _mixInRect . width > k_MinMixWidth & & clip . hasBlendIn )
blendInKind = BlendKind . Mix ;
else if ( _mixInRect . width > k_MinMixWidth )
blendInKind = BlendKind . Ease ;
var blendOutKind = BlendKind . None ;
if ( _mixOutRect . width > k_MinMixWidth & & clip . hasBlendOut )
blendOutKind = BlendKind . Mix ;
else if ( _mixOutRect . width > k_MinMixWidth )
blendOutKind = BlendKind . Ease ;
return new ClipBlends ( blendInKind , _mixInRect , blendOutKind , _mixOutRect ) ;
}
public override double start
{
get { return clip . start ; }
}
public override double end
{
get { return clip . end ; }
}
public bool supportsLooping
{
get { return clip . SupportsLooping ( ) ; }
}
// for the inline curve editor, only show loops if we recorded the asset
bool IClipCurveEditorOwner . showLoops
{
get { return clip . SupportsLooping ( ) & & ( clip . asset is AnimationPlayableAsset ) ; }
}
TrackAsset IClipCurveEditorOwner . owner
{
get { return clip . parentTrack ; }
}
public bool supportsSubTimelines
{
get { return m_ClipEditor . supportsSubTimelines ; }
}
public int minLoopIndex
{
get { return m_MinLoopIndex ; }
}
public Rect clippedRect { get ; private set ; }
public override void Select ( )
{
zOrder = zOrderProvider . Next ( ) ;
SelectionManager . Add ( clip ) ;
2022-01-12 10:39:15 +03:00
if ( clipCurveEditor ! = null & & SelectionManager . Count ( ) = = 1 )
SelectionManager . SelectInlineCurveEditor ( this ) ;
2022-01-12 10:06:03 +03:00
}
public override bool IsSelected ( )
{
return SelectionManager . Contains ( clip ) ;
}
public override void Deselect ( )
{
SelectionManager . Remove ( clip ) ;
2022-01-12 10:39:15 +03:00
if ( inlineCurvesSelected )
SelectionManager . SelectInlineCurveEditor ( null ) ;
}
public override bool CanSelect ( )
{
ClipBlends clipBlends = GetClipBlends ( ) ;
//clips that do not overlap are always selectable
if ( clipBlends . inKind ! = BlendKind . Mix & & clipBlends . outKind ! = BlendKind . Mix )
return true ;
Vector2 mousePos = Event . current . mousePosition - rect . position ;
return m_ClipCenterSection . Contains ( mousePos ) | | IsPointLocatedInClipBlend ( mousePos , clipBlends ) ;
}
static bool IsPointLocatedInClipBlend ( Vector2 pt , ClipBlends blends )
{
if ( blends . inRect . Contains ( pt ) )
return Sign ( pt , blends . inRect . min , blends . inRect . max ) < 0 ;
if ( blends . outRect . Contains ( pt ) )
return Sign ( pt , blends . outRect . min , blends . outRect . max ) > = 0 ;
return false ;
}
static float Sign ( Vector2 point , Vector2 linePoint1 , Vector2 linePoint2 )
{
return ( point . x - linePoint2 . x ) * ( linePoint1 . y - linePoint2 . y ) - ( linePoint1 . x - linePoint2 . x ) * ( point . y - linePoint2 . y ) ;
2022-01-12 10:06:03 +03:00
}
public override ITimelineItem item
{
get { return ItemsUtils . ToItem ( clip ) ; }
}
IZOrderProvider zOrderProvider { get ; }
public TimelineClipHandle leftHandle { get ; }
public TimelineClipHandle rightHandle { get ; }
public TimelineClipGUI ( TimelineClip clip , IRowGUI parent , IZOrderProvider provider ) : base ( parent )
{
zOrderProvider = provider ;
zOrder = provider . Next ( ) ;
m_EditorItem = EditorClipFactory . GetEditorClip ( clip ) ;
m_ClipEditor = CustomTimelineEditorCache . GetClipEditor ( clip ) ;
supportResize = true ;
leftHandle = new TimelineClipHandle ( this , TrimEdge . Start ) ;
rightHandle = new TimelineClipHandle ( this , TrimEdge . End ) ;
ItemToItemGui . Add ( clip , this ) ;
}
void CreateInlineCurveEditor ( WindowState state )
{
if ( clipCurveEditor ! = null )
return ;
var animationClip = clip . animationClip ;
if ( animationClip ! = null & & animationClip . empty )
animationClip = null ;
// prune out clips coming from FBX
if ( animationClip ! = null & & ! clip . recordable )
return ; // don't show, even if there are curves
if ( animationClip = = null & & ! clip . HasAnyAnimatableParameters ( ) )
return ; // nothing to show
state . AddEndFrameDelegate ( ( istate , currentEvent ) = >
{
clipCurveEditor = new ClipCurveEditor ( CurveDataSource . Create ( this ) , TimelineWindow . instance , clip . parentTrack ) ;
return true ;
} ) ;
}
public TimelineClip clip
{
get { return m_EditorItem . clip ; }
}
// Draw the actual clip. Defers to the track drawer for customization
void UpdateDrawData ( WindowState state , Rect drawRect , string title , bool selected , bool previousClipSelected , float rectXOffset )
{
m_ClipDrawData . clip = clip ;
m_ClipDrawData . targetRect = drawRect ;
m_ClipDrawData . clipCenterSection = m_ClipCenterSection ;
m_ClipDrawData . unclippedRect = treeViewRect ;
m_ClipDrawData . title = title ;
m_ClipDrawData . selected = selected ;
m_ClipDrawData . inlineCurvesSelected = inlineCurvesSelected ;
m_ClipDrawData . previousClip = previousClip ! = null ? previousClip . clip : null ;
m_ClipDrawData . previousClipSelected = previousClipSelected ;
Vector3 shownAreaTime = state . timeAreaShownRange ;
m_ClipDrawData . localVisibleStartTime = clip . ToLocalTimeUnbound ( Math . Max ( clip . start , shownAreaTime . x ) ) ;
m_ClipDrawData . localVisibleEndTime = clip . ToLocalTimeUnbound ( Math . Min ( clip . end , shownAreaTime . y ) ) ;
m_ClipDrawData . clippedRect = new Rect ( clippedRect . x - rectXOffset , 0.0f , clippedRect . width , clippedRect . height ) ;
m_ClipDrawData . minLoopIndex = minLoopIndex ;
m_ClipDrawData . loopRects = m_LoopRects ;
m_ClipDrawData . supportsLooping = supportsLooping ;
m_ClipDrawData . clipBlends = GetClipBlends ( ) ;
m_ClipDrawData . clipEditor = m_ClipEditor ;
m_ClipDrawData . ClipDrawOptions = UpdateClipDrawOptions ( m_ClipEditor , clip ) ;
UpdateClipIcons ( state ) ;
}
void UpdateClipIcons ( WindowState state )
{
// Pass 1 - gather size
int required = 0 ;
bool requiresDigIn = ShowDrillIcon ( state . editSequence . director ) ;
if ( requiresDigIn )
required + + ;
var icons = m_ClipDrawData . ClipDrawOptions . icons ;
foreach ( var icon in icons )
{
if ( icon ! = null )
required + + ;
}
// Pass 2 - copy icon data
if ( required = = 0 )
{
m_ClipDrawData . rightIcons = null ;
return ;
}
if ( m_ClipDrawData . rightIcons = = null | | m_ClipDrawData . rightIcons . Length ! = required )
m_ClipDrawData . rightIcons = new IconData [ required ] ;
int index = 0 ;
if ( requiresDigIn )
m_ClipDrawData . rightIcons [ index + + ] = k_DiggableClipIcon ;
foreach ( var icon in icons )
{
if ( icon ! = null )
m_ClipDrawData . rightIcons [ index + + ] = new IconData ( icon ) ;
}
}
static ClipDrawOptions UpdateClipDrawOptions ( ClipEditor clipEditor , TimelineClip clip )
{
try
{
return clipEditor . GetClipOptions ( clip ) ;
}
catch ( Exception e )
{
Debug . LogException ( e ) ;
}
return CustomTimelineEditorCache . GetDefaultClipEditor ( ) . GetClipOptions ( clip ) ;
}
static void DrawClip ( ClipDrawData drawData )
{
ClipDrawer . DrawDefaultClip ( drawData ) ;
if ( drawData . clip . asset is AnimationPlayableAsset )
{
var state = TimelineWindow . instance . state ;
if ( state . recording & & state . IsArmedForRecord ( drawData . clip . parentTrack ) )
{
ClipDrawer . DrawAnimationRecordBorder ( drawData ) ;
ClipDrawer . DrawRecordProhibited ( drawData ) ;
}
}
}
public void DrawGhostClip ( Rect targetRect )
{
DrawSimpleClip ( targetRect , ClipBorder . Selection ( ) , new Color ( 1.0f , 1.0f , 1.0f , 0.5f ) ) ;
}
public void DrawInvalidClip ( Rect targetRect )
{
DrawSimpleClip ( targetRect , ClipBorder . Selection ( ) , DirectorStyles . Instance . customSkin . colorInvalidClipOverlay ) ;
}
void DrawSimpleClip ( Rect targetRect , ClipBorder border , Color overlay )
{
var drawOptions = UpdateClipDrawOptions ( CustomTimelineEditorCache . GetClipEditor ( clip ) , clip ) ;
ClipDrawer . DrawSimpleClip ( clip , targetRect , border , overlay , drawOptions ) ;
}
void DrawInto ( Rect drawRect , WindowState state )
{
if ( Event . current . type ! = EventType . Repaint )
return ;
// create the inline curve editor if not already created
CreateInlineCurveEditor ( state ) ;
// @todo optimization, most of the calculations (rect, offsets, colors, etc.) could be cached
// and rebuilt when the hash of the clip changes.
if ( isInvalid )
{
DrawInvalidClip ( treeViewRect ) ;
return ;
}
GUI . BeginClip ( drawRect ) ;
var originRect = new Rect ( 0.0f , 0.0f , drawRect . width , drawRect . height ) ;
string clipLabel = name ;
var selected = SelectionManager . Contains ( clip ) ;
var previousClipSelected = previousClip ! = null & & SelectionManager . Contains ( previousClip . clip ) ;
if ( selected & & 1.0 ! = clip . timeScale )
clipLabel + = " " + clip . timeScale . ToString ( "F2" ) + "x" ;
UpdateDrawData ( state , originRect , clipLabel , selected , previousClipSelected , drawRect . x ) ;
DrawClip ( m_ClipDrawData ) ;
GUI . EndClip ( ) ;
if ( clip . parentTrack ! = null & & ! clip . parentTrack . lockedInHierarchy )
{
if ( selected & & supportResize )
{
var cursorRect = rect ;
cursorRect . xMin + = leftHandle . boundingRect . width ;
cursorRect . xMax - = rightHandle . boundingRect . width ;
EditorGUIUtility . AddCursorRect ( cursorRect , MouseCursor . MoveArrow ) ;
}
if ( supportResize )
{
var handleWidth = Mathf . Clamp ( drawRect . width * 0.3f , k_MinHandleWidth , k_MaxHandleWidth ) ;
leftHandle . Draw ( drawRect , handleWidth , state ) ;
rightHandle . Draw ( drawRect , handleWidth , state ) ;
}
}
}
void CalculateClipRectangle ( Rect trackRect , WindowState state )
{
if ( m_ClipViewDirty )
{
var clipRect = RectToTimeline ( trackRect , state ) ;
treeViewRect = clipRect ;
// calculate clipped rect
clipRect . xMin = Mathf . Max ( clipRect . xMin , trackRect . xMin ) ;
clipRect . xMax = Mathf . Min ( clipRect . xMax , trackRect . xMax ) ;
if ( clipRect . width > 0 & & clipRect . width < 2 )
{
clipRect . width = 5.0f ;
}
clippedRect = clipRect ;
}
}
void AddToSpacePartitioner ( WindowState state )
{
if ( Event . current . type = = EventType . Repaint & & ! parent . locked )
state . spacePartitioner . AddBounds ( this , rect ) ;
}
void CalculateBlendRect ( )
{
m_ClipCenterSection = treeViewRect ;
m_ClipCenterSection . x = 0 ;
m_ClipCenterSection . y = 0 ;
m_ClipCenterSection . xMin = Mathf . Round ( treeViewRect . width * clip . mixInPercentage ) ;
m_ClipCenterSection . width = Mathf . Round ( treeViewRect . width ) ;
m_ClipCenterSection . xMax - = Mathf . Round ( mixOutRect . width + treeViewRect . width * clip . mixInPercentage ) ;
}
// Entry point to the Clip Drawing...
public override void Draw ( Rect trackRect , bool trackRectChanged , WindowState state )
{
// if the clip has changed, fire the appropriate callback
DetectClipChanged ( trackRectChanged ) ;
// update the clip projected rectangle on the timeline
CalculateClipRectangle ( trackRect , state ) ;
AddToSpacePartitioner ( state ) ;
// update the blend rects (when clip overlaps with others)
CalculateBlendRect ( ) ;
// update the loop rects (when clip loops)
CalculateLoopRects ( trackRect , state ) ;
DrawExtrapolation ( trackRect , treeViewRect ) ;
DrawInto ( treeViewRect , state ) ;
ResetClipChanged ( ) ;
}
void DetectClipChanged ( bool trackRectChanged )
{
if ( Event . current . type = = EventType . Layout )
{
if ( clip . DirtyIndex ! = m_LastDirtyIndex )
{
m_ClipViewDirty = true ;
try
{
m_ClipEditor . OnClipChanged ( clip ) ;
}
catch ( Exception e )
{
Debug . LogException ( e ) ;
}
m_LastDirtyIndex = clip . DirtyIndex ;
}
m_ClipViewDirty | = trackRectChanged ;
}
}
void ResetClipChanged ( )
{
if ( Event . current . type = = EventType . Repaint )
m_ClipViewDirty = false ;
}
GUIStyle GetExtrapolationIcon ( TimelineClip . ClipExtrapolation mode )
{
GUIStyle extrapolationIcon = null ;
switch ( mode )
{
case TimelineClip . ClipExtrapolation . None : return null ;
case TimelineClip . ClipExtrapolation . Hold : extrapolationIcon = m_Styles . extrapolationHold ; break ;
case TimelineClip . ClipExtrapolation . Loop : extrapolationIcon = m_Styles . extrapolationLoop ; break ;
case TimelineClip . ClipExtrapolation . PingPong : extrapolationIcon = m_Styles . extrapolationPingPong ; break ;
case TimelineClip . ClipExtrapolation . Continue : extrapolationIcon = m_Styles . extrapolationContinue ; break ;
}
return extrapolationIcon ;
}
Rect GetPreExtrapolationBounds ( Rect trackRect , Rect clipRect , GUIStyle icon )
{
float x = clipRect . xMin - ( icon . fixedWidth + 10.0f ) ;
float y = trackRect . yMin + ( trackRect . height - icon . fixedHeight ) / 2.0f ;
if ( previousClip ! = null )
{
float distance = Mathf . Abs ( treeViewRect . xMin - previousClip . treeViewRect . xMax ) ;
if ( distance < icon . fixedWidth )
return new Rect ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
if ( distance < icon . fixedWidth + 20.0f )
{
float delta = ( distance - icon . fixedWidth ) / 2.0f ;
x = clipRect . xMin - ( icon . fixedWidth + delta ) ;
}
}
return new Rect ( x , y , icon . fixedWidth , icon . fixedHeight ) ;
}
Rect GetPostExtrapolationBounds ( Rect trackRect , Rect clipRect , GUIStyle icon )
{
float x = clipRect . xMax + 10.0f ;
float y = trackRect . yMin + ( trackRect . height - icon . fixedHeight ) / 2.0f ;
if ( nextClip ! = null )
{
float distance = Mathf . Abs ( nextClip . treeViewRect . xMin - treeViewRect . xMax ) ;
if ( distance < icon . fixedWidth )
return new Rect ( 0.0f , 0.0f , 0.0f , 0.0f ) ;
if ( distance < icon . fixedWidth + 20.0f )
{
float delta = ( distance - icon . fixedWidth ) / 2.0f ;
x = clipRect . xMax + delta ;
}
}
return new Rect ( x , y , icon . fixedWidth , icon . fixedHeight ) ;
}
static void DrawExtrapolationIcon ( Rect rect , GUIStyle icon )
{
GUI . Label ( rect , GUIContent . none , icon ) ;
}
void DrawExtrapolation ( Rect trackRect , Rect clipRect )
{
if ( clip . hasPreExtrapolation )
{
GUIStyle icon = GetExtrapolationIcon ( clip . preExtrapolationMode ) ;
if ( icon ! = null )
{
Rect iconBounds = GetPreExtrapolationBounds ( trackRect , clipRect , icon ) ;
if ( iconBounds . width > 1 & & iconBounds . height > 1 )
DrawExtrapolationIcon ( iconBounds , icon ) ;
}
}
if ( clip . hasPostExtrapolation )
{
GUIStyle icon = GetExtrapolationIcon ( clip . postExtrapolationMode ) ;
if ( icon ! = null )
{
Rect iconBounds = GetPostExtrapolationBounds ( trackRect , clipRect , icon ) ;
if ( iconBounds . width > 1 & & iconBounds . height > 1 )
DrawExtrapolationIcon ( iconBounds , icon ) ;
}
}
}
static Rect ProjectRectOnTimeline ( Rect rect , Rect trackRect , WindowState state )
{
Rect newRect = rect ;
// transform clipRect into pixel-space
newRect . x * = state . timeAreaScale . x ;
newRect . width * = state . timeAreaScale . x ;
newRect . x + = state . timeAreaTranslation . x + trackRect . xMin ;
// adjust clipRect height and vertical centering
const int clipPadding = 2 ;
newRect . y = trackRect . y + clipPadding ;
newRect . height = trackRect . height - ( 2 * clipPadding ) ;
return newRect ;
}
void CalculateLoopRects ( Rect trackRect , WindowState state )
{
if ( ! m_ClipViewDirty )
return ;
m_LoopRects . Clear ( ) ;
if ( clip . duration < WindowState . kTimeEpsilon )
return ;
var times = TimelineHelpers . GetLoopTimes ( clip ) ;
var loopDuration = TimelineHelpers . GetLoopDuration ( clip ) ;
m_MinLoopIndex = - 1 ;
// we have a hold, no need to compute all loops
if ( ! supportsLooping )
{
if ( times . Length > 1 )
{
var t = times [ 1 ] ;
float loopTime = ( float ) ( clip . duration - t ) ;
m_LoopRects . Add ( ProjectRectOnTimeline ( new Rect ( ( float ) ( t + clip . start ) , 0 , loopTime , 0 ) , trackRect , state ) ) ;
}
return ;
}
var range = state . timeAreaShownRange ;
var visibleStartTime = range . x - clip . start ;
var visibleEndTime = range . y - clip . start ;
for ( int i = 1 ; i < times . Length ; i + + )
{
var t = times [ i ] ;
// don't draw off screen loops
if ( t > visibleEndTime )
break ;
float loopTime = Mathf . Min ( ( float ) ( clip . duration - t ) , ( float ) loopDuration ) ;
var loopEnd = t + loopTime ;
if ( loopEnd < visibleStartTime )
continue ;
m_LoopRects . Add ( ProjectRectOnTimeline ( new Rect ( ( float ) ( t + clip . start ) , 0 , loopTime , 0 ) , trackRect , state ) ) ;
if ( m_MinLoopIndex = = - 1 )
m_MinLoopIndex = i ;
}
}
public override Rect RectToTimeline ( Rect trackRect , WindowState state )
{
var offsetFromTimeSpaceToPixelSpace = state . timeAreaTranslation . x + trackRect . xMin ;
var start = ( float ) ( DiscreteTime ) clip . start ;
var end = ( float ) ( DiscreteTime ) clip . end ;
return Rect . MinMaxRect (
Mathf . Round ( start * state . timeAreaScale . x + offsetFromTimeSpaceToPixelSpace ) , Mathf . Round ( trackRect . yMin ) ,
Mathf . Round ( end * state . timeAreaScale . x + offsetFromTimeSpaceToPixelSpace ) , Mathf . Round ( trackRect . yMax )
) ;
}
public IEnumerable < Edge > SnappableEdgesFor ( IAttractable attractable , ManipulateEdges manipulateEdges )
{
var edges = new List < Edge > ( ) ;
bool canAddEdges = ! parent . muted ;
if ( canAddEdges )
{
// Hack: Trim Start in Ripple mode should not have any snap point added
if ( EditMode . editType = = EditMode . EditType . Ripple & & manipulateEdges = = ManipulateEdges . Left )
return edges ;
if ( attractable ! = this )
{
if ( EditMode . editType = = EditMode . EditType . Ripple )
{
bool skip = false ;
// Hack: Since Trim End and Move in Ripple mode causes other snap point to move on the same track (which is not supported), disable snapping for this special cases...
// TODO Find a proper way to have different snap edges for each edit mode.
if ( manipulateEdges = = ManipulateEdges . Right )
{
var otherClipGUI = attractable as TimelineClipGUI ;
skip = otherClipGUI ! = null & & otherClipGUI . parent = = parent ;
}
else if ( manipulateEdges = = ManipulateEdges . Both )
{
var moveHandler = attractable as MoveItemHandler ;
skip = moveHandler ! = null & & moveHandler . movingItems . Any ( clips = > clips . targetTrack = = clip . parentTrack & & clip . start > = clips . start ) ;
}
if ( skip )
return edges ;
}
AddEdge ( edges , clip . start ) ;
AddEdge ( edges , clip . end ) ;
}
else
{
if ( manipulateEdges = = ManipulateEdges . Right )
{
var d = TimelineHelpers . GetClipAssetEndTime ( clip ) ;
if ( d < double . MaxValue )
{
if ( clip . SupportsLooping ( ) )
{
var l = TimelineHelpers . GetLoopDuration ( clip ) ;
var shownTime = TimelineWindow . instance . state . timeAreaShownRange ;
do
{
AddEdge ( edges , d , false ) ;
d + = l ;
}
while ( d < shownTime . y ) ;
}
else
{
AddEdge ( edges , d , false ) ;
}
}
}
if ( manipulateEdges = = ManipulateEdges . Left )
{
var clipInfo = AnimationClipCurveCache . Instance . GetCurveInfo ( clip . animationClip ) ;
if ( clipInfo ! = null & & clipInfo . keyTimes . Any ( ) )
AddEdge ( edges , clip . FromLocalTimeUnbound ( clipInfo . keyTimes . Min ( ) ) , false ) ;
}
}
}
return edges ;
}
public bool ShouldSnapTo ( ISnappable snappable )
{
return true ;
}
bool ShowDrillIcon ( PlayableDirector resolver )
{
if ( ! m_ShowDrillIcon . HasValue | | TimelineWindow . instance . hierarchyChangedThisFrame )
{
var nestable = m_ClipEditor . supportsSubTimelines ;
m_ShowDrillIcon = nestable & & resolver ! = null ;
if ( m_ShowDrillIcon . Value )
{
s_TempSubDirectors . Clear ( ) ;
try
{
m_ClipEditor . GetSubTimelines ( clip , resolver , s_TempSubDirectors ) ;
}
catch ( Exception e )
{
Debug . LogException ( e ) ;
}
m_ShowDrillIcon & = s_TempSubDirectors . Count > 0 ;
}
}
return m_ShowDrillIcon . Value ;
}
static void AddEdge ( List < Edge > edges , double time , bool showEdgeHint = true )
{
var shownTime = TimelineWindow . instance . state . timeAreaShownRange ;
if ( time > = shownTime . x & & time < = shownTime . y )
edges . Add ( new Edge ( time , showEdgeHint ) ) ;
}
2022-01-12 10:39:15 +03:00
public void SelectCurves ( )
{
SelectionManager . SelectOnly ( clip ) ;
SelectionManager . SelectInlineCurveEditor ( this ) ;
}
public void ValidateCurvesSelection ( )
{
if ( ! IsSelected ( ) ) //if clip is not selected, deselect the inline curve
SelectionManager . SelectInlineCurveEditor ( null ) ;
}
2022-01-12 10:06:03 +03:00
}
}