Editor/GraphicsItems/EditableAltCurve.DragHandle.cs
using Editor;
using System;
namespace AltCurves.GraphicsItems;
public partial class EditableAltCurve : GraphicsItem
{
/// <summary>
/// The draggable, invisible handle that represents a keyframe on the curve
/// The actual visible keyframe position can vary with snapping
/// </summary>
public class DragHandle : GraphicsItem
{
/// <summary>
/// Underlying keyframe that we're positioned for, updated on dragging
/// </summary>
public AltCurve.Keyframe Keyframe
{
get => _keyframe;
set
{
_keyframe = value;
StartDragKeyframe = _keyframe;
Position = _transform.CurveToWidgetPosition( new( _keyframe.Time, _keyframe.Value ) );
Update();
}
}
private AltCurve.Keyframe _keyframe;
/// <summary>
/// The keyframe when we started the last dragging operation
/// </summary>
public AltCurve.Keyframe StartDragKeyframe { get; private set; }
public CurveWidgetTransform Transform
{
get => _transform;
set
{
_transform = value;
Position = _transform.CurveToWidgetPosition( new( Keyframe.Time, Keyframe.Value ) );
Update();
}
}
private CurveWidgetTransform _transform;
/// <summary>
/// Called when we're left-clicked for selection logic
/// Params are index, isShift, isCtrl, isAlt
/// </summary>
public Action<int, bool, bool, bool> OnMouseDown { get; set; } = null;
public Action<int, bool, bool, bool> OnMouseUp { get; set; } = null;
/// <summary>
/// Called during drag operations, after the Keyframe has been updated for our new position
/// Parameter is the index and the pre-drag keyframe.
/// </summary>
public Action<int> OnDragging { get; set; } = null;
/// <summary>
/// Called when releasing the mouse, the drag has completed
/// </summary>
public Action<int> OnDragComplete { get; set; } = null;
private readonly int _index;
private Vector2 _mouseDownPos;
public DragHandle( int index, CurveWidgetTransform transform, AltCurve.Keyframe keyframe, GraphicsItem parent ) : base( parent )
{
_index = index;
_keyframe = keyframe;
StartDragKeyframe = keyframe;
HandlePosition = new( 0.5f );
Cursor = CursorShape.Finger;
Movable = true;
Clip = true;
HoverEvents = true;
Size = new( 14.0f );
_transform = transform;
Position = _transform.CurveToWidgetPosition( new( Keyframe.Time, Keyframe.Value ) );
}
protected override void OnMoved()
{
base.OnMoved();
_keyframe = _keyframe with { Time = _transform.WidgetToCurveX( Position.x ), Value = _transform.WidgetToCurveY( Position.y ) };
OnDragging?.Invoke( _index );
}
protected override void OnMousePressed( GraphicsMouseEvent e )
{
if ( e.LeftMouseButton )
{
StartDragKeyframe = Keyframe;
_mouseDownPos = e.ScreenPosition;
OnMouseDown?.Invoke( _index, e.HasShift, e.HasCtrl, e.HasAlt );
}
// Begin drag
base.OnMousePressed( e );
}
protected override void OnMouseReleased( GraphicsMouseEvent e )
{
base.OnMouseReleased( e );
// Either the user moved us from the starting location and we're completing a drag,
// or they just clicked us normally and the mouse up action should trigger
if ( e.LeftMouseButton )
{
if ( e.ScreenPosition != _mouseDownPos )
{
OnDragComplete?.Invoke( _index );
}
else
{
OnMouseUp?.Invoke( _index, e.HasShift, e.HasCtrl, e.HasAlt );
}
}
}
}
}