@@ -94,6 +94,34 @@ public Selection(SerializedProperty curve, int keyframeIndex, Keyframe? keyframe
9494 this . keyframe = keyframe ;
9595 }
9696 }
97+
98+ internal struct MenuAction
99+ {
100+ internal SerializedProperty curve ;
101+ internal int index ;
102+ internal Vector3 position ;
103+
104+ internal MenuAction ( SerializedProperty curve )
105+ {
106+ this . curve = curve ;
107+ this . index = - 1 ;
108+ this . position = Vector3 . zero ;
109+ }
110+
111+ internal MenuAction ( SerializedProperty curve , int index )
112+ {
113+ this . curve = curve ;
114+ this . index = index ;
115+ this . position = Vector3 . zero ;
116+ }
117+
118+ internal MenuAction ( SerializedProperty curve , Vector3 position )
119+ {
120+ this . curve = curve ;
121+ this . index = - 1 ;
122+ this . position = position ;
123+ }
124+ }
97125 #endregion
98126
99127 #region Fields & properties
@@ -201,7 +229,8 @@ public void SetKeyframe(SerializedProperty curve, int keyframeIndex, Keyframe ke
201229
202230 public bool OnGUI ( Rect rect )
203231 {
204- m_Dirty = false ;
232+ if ( Event . current . type == EventType . Repaint )
233+ m_Dirty = false ;
205234
206235 GUI . BeginClip ( rect ) ;
207236 {
@@ -392,14 +421,34 @@ void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state)
392421 EditMoveTangent ( animCurve , keys , k , m_TangentEditMode , e . shift || ! ( alreadyBroken || e . control ) ) ;
393422 }
394423
395- // Keyframe selection
424+ // Keyframe selection & context menu
396425 if ( e . type == EventType . mouseDown && rect . Contains ( e . mousePosition ) )
397426 {
398427 if ( hitRect . Contains ( e . mousePosition ) )
399428 {
400- SelectKeyframe ( curve , k ) ;
401- m_EditMode = EditMode . Moving ;
402- e . Use ( ) ;
429+ if ( e . button == 0 )
430+ {
431+ SelectKeyframe ( curve , k ) ;
432+ m_EditMode = EditMode . Moving ;
433+ e . Use ( ) ;
434+ }
435+ else if ( e . button == 1 )
436+ {
437+ // Keyframe context menu
438+ var menu = new GenericMenu ( ) ;
439+ menu . AddItem ( new GUIContent ( "Delete Key" ) , false , ( x ) =>
440+ {
441+ var action = ( MenuAction ) x ;
442+ var curveValue = action . curve . animationCurveValue ;
443+ action . curve . serializedObject . Update ( ) ;
444+ RemoveKeyframe ( curveValue , action . index ) ;
445+ m_SelectedKeyframeIndex = - 1 ;
446+ SaveCurve ( action . curve , curveValue ) ;
447+ action . curve . serializedObject . ApplyModifiedProperties ( ) ;
448+ } , new MenuAction ( curve , k ) ) ;
449+ menu . ShowAsContext ( ) ;
450+ e . Use ( ) ;
451+ }
403452 }
404453 }
405454
@@ -455,6 +504,7 @@ void OnGeneralUI(Rect rect)
455504 GUI . FocusControl ( null ) ;
456505 m_SelectedCurve = null ;
457506 m_SelectedKeyframeIndex = - 1 ;
507+ bool used = false ;
458508
459509 var hit = CanvasToCurve ( e . mousePosition ) ;
460510 float curvePickValue = CurveToCanvas ( hit ) . y ;
@@ -478,18 +528,35 @@ void OnGeneralUI(Rect rect)
478528 {
479529 m_SelectedCurve = prop ;
480530
481- // Create a keyframe on double-click on this curve
482- if ( e . clickCount == 2 )
531+ if ( e . clickCount == 2 && e . button == 0 )
483532 {
533+ // Create a keyframe on double-click on this curve
484534 EditCreateKeyframe ( animCurve , hit , true , state . zeroKeyConstantValue ) ;
485535 SaveCurve ( prop , animCurve ) ;
486536 }
537+ else if ( e . button == 1 )
538+ {
539+ // Curve context menu
540+ var menu = new GenericMenu ( ) ;
541+ menu . AddItem ( new GUIContent ( "Add Key" ) , false , ( x ) =>
542+ {
543+ var action = ( MenuAction ) x ;
544+ var curveValue = action . curve . animationCurveValue ;
545+ action . curve . serializedObject . Update ( ) ;
546+ EditCreateKeyframe ( curveValue , hit , true , 0f ) ;
547+ SaveCurve ( action . curve , curveValue ) ;
548+ action . curve . serializedObject . ApplyModifiedProperties ( ) ;
549+ } , new MenuAction ( prop , hit ) ) ;
550+ menu . ShowAsContext ( ) ;
551+ e . Use ( ) ;
552+ used = true ;
553+ }
487554 }
488555 }
489556
490- // Create a keyframe on every curve on double-click
491- if ( e . clickCount == 2 && m_SelectedCurve == null )
557+ if ( e . clickCount == 2 && e . button == 0 && m_SelectedCurve == null )
492558 {
559+ // Create a keyframe on every curve on double-click
493560 foreach ( var curve in m_Curves )
494561 {
495562 if ( ! curve . Value . editable || ! curve . Value . visible )
@@ -502,6 +569,14 @@ void OnGeneralUI(Rect rect)
502569 SaveCurve ( prop , animCurve ) ;
503570 }
504571 }
572+ else if ( ! used && e . button == 1 )
573+ {
574+ // Global context menu
575+ var menu = new GenericMenu ( ) ;
576+ menu . AddItem ( new GUIContent ( "Add Key At Position" ) , false , ( ) => ContextMenuAddKey ( hit , false ) ) ;
577+ menu . AddItem ( new GUIContent ( "Add Key On Curves" ) , false , ( ) => ContextMenuAddKey ( hit , true ) ) ;
578+ menu . ShowAsContext ( ) ;
579+ }
505580
506581 e . Use ( ) ;
507582 }
@@ -547,6 +622,35 @@ void SelectKeyframe(SerializedProperty curve, int keyframeIndex)
547622 Invalidate ( ) ;
548623 }
549624
625+ void ContextMenuAddKey ( Vector3 hit , bool createOnCurve )
626+ {
627+ SerializedObject serializedObject = null ;
628+
629+ foreach ( var curve in m_Curves )
630+ {
631+ if ( ! curve . Value . editable || ! curve . Value . visible )
632+ continue ;
633+
634+ var prop = curve . Key ;
635+ var state = curve . Value ;
636+
637+ if ( serializedObject == null )
638+ {
639+ serializedObject = prop . serializedObject ;
640+ serializedObject . Update ( ) ;
641+ }
642+
643+ var animCurve = prop . animationCurveValue ;
644+ EditCreateKeyframe ( animCurve , hit , createOnCurve , state . zeroKeyConstantValue ) ;
645+ SaveCurve ( prop , animCurve ) ;
646+ }
647+
648+ if ( serializedObject != null )
649+ serializedObject . ApplyModifiedProperties ( ) ;
650+
651+ Invalidate ( ) ;
652+ }
653+
550654 void EditCreateKeyframe ( AnimationCurve curve , Vector3 position , bool createOnCurve , float zeroKeyConstantValue )
551655 {
552656 float tangent = EvaluateTangent ( curve , position . x ) ;
0 commit comments