namespace UIWidgets { using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; /// /// ScrollRect events. /// [AddComponentMenu("UI/New UI Widgets/Helpers/ScrollRect Events")] [RequireComponent(typeof(ScrollRect))] public class ScrollRectEvents : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { /// /// Pull thresholds. /// [Serializable] public struct PullThreshold : IEquatable { /// /// Up. /// public float Up; /// /// Down. /// public float Down; /// /// Left. /// public float Left; /// /// Right. /// public float Right; /// /// Initializes a new instance of the struct. /// /// Up. /// Down. /// Left. /// Right. public PullThreshold(float up = 50f, float down = 50f, float left = 50f, float right = 50f) { Up = up; Down = down; Left = left; Right = right; } /// /// Determines whether the specified object is equal to the current object. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. public override bool Equals(object obj) { if (obj is PullThreshold) { return Equals((PullThreshold)obj); } return false; } /// /// Determines whether the specified object is equal to the current object. /// /// The object to compare with the current object. /// true if the specified object is equal to the current object; otherwise, false. public bool Equals(PullThreshold other) { return Up == other.Up && Down == other.Down && Left == other.Left && Right == other.Right; } /// /// Hash function. /// /// A hash code for the current object. public override int GetHashCode() { return Up.GetHashCode() ^ Down.GetHashCode() ^ Left.GetHashCode() ^ Right.GetHashCode(); } /// /// Compare specified instances. /// /// Left instance. /// Right instances. /// true if the instances are equal; otherwise, false. public static bool operator ==(PullThreshold left, PullThreshold right) { return left.Equals(right); } /// /// Compare specified instances. /// /// Left instance. /// Right instances. /// true if the instances are now equal; otherwise, false. public static bool operator !=(PullThreshold left, PullThreshold right) { return !left.Equals(right); } } /// /// Pull directions. /// public enum PullDirection { /// /// None. /// None = 0, /// /// Up. /// Up = 1, /// /// Down. /// Down = 2, /// /// Left. /// Left = 3, /// /// Right. /// Right = 4, } /// /// Pull event. /// [Serializable] public class PullEvent : UnityEvent { } /// /// Pull event. /// [Serializable] public class PullingEvent : UnityEvent { } /// /// The required pull distance to raise events. /// [SerializeField] [Obsolete("Replaced with Thresholds.")] [HideInInspector] public float RequiredMovement = 50f; /// /// Thresholds. /// [SerializeField] public PullThreshold Thresholds; /// /// OnPulling event. /// [SerializeField] public PullingEvent OnPulling = new PullingEvent(); /// /// OnPull event. /// [SerializeField] public PullEvent OnPull = new PullEvent(); /// /// Event raised when drag distance is equal or more than RequiredMovement. /// [SerializeField] public PullEvent OnPullAllowed = new PullEvent(); /// /// Event raised when drag distance is less than RequiredMovement after OnPullValid was called. /// [SerializeField] public PullEvent OnPullCancel = new PullEvent(); /// /// OnPullUp event. /// [SerializeField] public UnityEvent OnPullUp = new UnityEvent(); /// /// OnPullDown event. /// [SerializeField] public UnityEvent OnPullDown = new UnityEvent(); /// /// OnPullLeft event. /// [SerializeField] public UnityEvent OnPullLeft = new UnityEvent(); /// /// OnPullRight event. /// [SerializeField] public UnityEvent OnPullRight = new UnityEvent(); ScrollRect scrollRect; /// /// Gets the ScrollRect. /// /// ScrollRect. public ScrollRect ScrollRect { get { if (scrollRect == null) { scrollRect = GetComponent(); } return scrollRect; } } PullDirection pullDirection = PullDirection.None; bool isPullValid; /// /// Called by a BaseInputModule before a drag is started. /// /// Event data. public virtual void OnBeginDrag(PointerEventData eventData) { ResetDrag(); } /// /// Called by a BaseInputModule when a drag is ended. /// /// Event data. public virtual void OnEndDrag(PointerEventData eventData) { if (isPullValid) { OnPull.Invoke(pullDirection); switch (pullDirection) { case PullDirection.Up: OnPullUp.Invoke(); break; case PullDirection.Down: OnPullDown.Invoke(); break; case PullDirection.Left: OnPullLeft.Invoke(); break; case PullDirection.Right: OnPullRight.Invoke(); break; case PullDirection.None: break; default: Debug.LogWarning(string.Format("Unsupported pull direction: {0}", EnumHelper.ToString(pullDirection))); break; } } ResetDrag(); } /// /// Resets the drag values. /// protected virtual void ResetDrag() { pullDirection = PullDirection.None; isPullValid = false; } /// /// Pull distance. /// public float PullDistance { get; protected set; } /// /// When dragging is occurring this will be called every time the cursor is moved. /// /// Event data. public virtual void OnDrag(PointerEventData eventData) { var size = (ScrollRect.transform as RectTransform).rect.size; var max_x = Mathf.Max(0f, ScrollRect.content.rect.width - size.x); var max_y = Mathf.Max(0f, ScrollRect.content.rect.height - size.y); var valid_distance = false; if (ScrollRect.content.anchoredPosition.y < 0f) { PullDistance = -ScrollRect.content.anchoredPosition.y; valid_distance = PullDistance >= Thresholds.Up; pullDirection = PullDirection.Up; } else if (ScrollRect.content.anchoredPosition.y > max_y) { PullDistance = ScrollRect.content.anchoredPosition.y - max_y; valid_distance = PullDistance >= Thresholds.Down; pullDirection = PullDirection.Down; } else if (ScrollRect.content.anchoredPosition.x < 0f) { PullDistance = -ScrollRect.content.anchoredPosition.x; valid_distance = PullDistance >= Thresholds.Left; pullDirection = PullDirection.Left; } else if (ScrollRect.content.anchoredPosition.x > max_x) { PullDistance = ScrollRect.content.anchoredPosition.x - max_x; valid_distance = PullDistance >= Thresholds.Right; pullDirection = PullDirection.Right; } else { PullDistance = 0f; } OnPulling.Invoke(this, pullDirection); if (valid_distance) { if (!isPullValid) { OnPullAllowed.Invoke(pullDirection); isPullValid = true; } } else { if (isPullValid) { OnPullCancel.Invoke(pullDirection); isPullValid = false; pullDirection = PullDirection.None; } } } [SerializeField] [HideInInspector] int version = 0; #if UNITY_EDITOR /// /// Validate this instance. /// protected virtual void OnValidate() { Upgrade(); } #endif /// /// Upgrade this instance. /// protected virtual void Upgrade() { if (version == 0) { #pragma warning disable 0618 Thresholds = new PullThreshold(RequiredMovement, RequiredMovement, RequiredMovement, RequiredMovement); #pragma warning restore 0618 version = 1; } } } }