using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.U2D.Animation.SpriteLibraryEditor
{
///
/// Manipulator that allows dragging from a container component.
///
internal class Dragger : PointerManipulator
{
///
/// The threshold in pixels after which a drag will start.
///
public float dragThreshold { get; set; } = 8f;
///
/// Whether the drag is currently active.
///
public bool isActive { get; private set; }
///
/// Delegate that will be called when a drag should be accepted during .
///
///
/// If this delegate is not set (or set to null), the drag will be accepted by default.
///
public Func acceptStartDrag { get; set; }
///
/// Delegate that will be called when a drag should be accepted when the dragger wants to become
/// active during .
///
///
/// If this delegate is not set (or set to null), the drag will be accepted by default.
///
public Func acceptDrag { get; set; }
int m_PointerId = -1;
Vector3 m_StartPosition;
event Action onDragStarted;
event Action onDragging;
event Action onDragEnded;
event Action onDragCanceled;
///
/// Creates a new instance.
///
/// The event that will be fired when a drag starts.
/// The event that will be fired when a drag is in progress.
/// The event that will be fired when a drag ends.
/// The event that will be fired when a drag is cancelled.
public Dragger(Action dragStarted, Action dragging,
Action dragEnded, Action dragCanceled)
{
onDragStarted = dragStarted;
onDragging = dragging;
onDragEnded = dragEnded;
onDragCanceled = dragCanceled;
}
///
protected override void RegisterCallbacksOnTarget()
{
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
target.RegisterCallback(OnPointerDown);
target.RegisterCallback(OnPointerMove);
target.RegisterCallback(OnPointerUp);
target.RegisterCallback(OnPointerCancel);
target.RegisterCallback(OnPointerCaptureOut);
target.RegisterCallback(OnKeyDown);
}
///
protected override void UnregisterCallbacksFromTarget()
{
activators.Clear();
target.UnregisterCallback(OnPointerDown);
target.UnregisterCallback(OnPointerMove);
target.UnregisterCallback(OnPointerUp);
target.UnregisterCallback(OnPointerCancel);
target.UnregisterCallback(OnPointerCaptureOut);
target.UnregisterCallback(OnKeyDown);
}
void OnPointerDown(PointerDownEvent evt)
{
isActive = false;
m_PointerId = -1;
if (CanStartManipulation(evt) && (acceptStartDrag == null || acceptStartDrag.Invoke(evt.position)))
{
m_StartPosition = evt.position;
m_PointerId = evt.pointerId;
}
}
void OnPointerMove(PointerMoveEvent evt)
{
if (m_PointerId != evt.pointerId)
return;
if (m_PointerId != -1)
{
if (!isActive)
{
var delta = evt.position - m_StartPosition;
if (delta.sqrMagnitude > dragThreshold * dragThreshold && (acceptDrag == null || acceptDrag.Invoke()))
{
if (!target.HasPointerCapture(evt.pointerId))
{
target.CapturePointer(evt.pointerId);
#if !UNITY_2023_1_OR_NEWER
if (evt.pointerId == PointerId.mousePointerId)
target.CaptureMouse();
#endif
}
isActive = true;
onDragStarted?.Invoke(evt);
}
}
else
{
if (!target.HasPointerCapture(evt.pointerId))
{
target.CapturePointer(evt.pointerId);
#if !UNITY_2023_1_OR_NEWER
if (evt.pointerId == PointerId.mousePointerId)
target.CaptureMouse();
#endif
}
onDragging?.Invoke(evt);
}
}
}
void OnPointerUp(PointerUpEvent evt)
{
if (m_PointerId != evt.pointerId)
return;
if (target.HasPointerCapture(evt.pointerId))
target.ReleasePointer(evt.pointerId);
if (isActive)
onDragEnded?.Invoke(evt);
isActive = false;
m_PointerId = -1;
}
void OnPointerCancel(PointerCancelEvent evt)
{
if (evt.pointerId == m_PointerId)
Cancel();
}
void OnPointerCaptureOut(PointerCaptureOutEvent evt)
{
if (evt.pointerId == m_PointerId)
Cancel();
}
void OnKeyDown(KeyDownEvent evt)
{
if (m_PointerId == -1)
return;
if (evt.keyCode == KeyCode.Escape)
{
evt.StopImmediatePropagation();
Cancel();
}
}
///
/// Cancels the drag.
///
public void Cancel()
{
if (target.HasPointerCapture(m_PointerId))
target.ReleasePointer(m_PointerId);
if (isActive)
{
isActive = false;
onDragCanceled?.Invoke();
}
m_PointerId = -1;
}
}
}