/* * @author Valentin Simonov / http://va.lent.in/ */ using System; using System.Collections; using System.Collections.Generic; using TouchScript.Utils; using TouchScript.Utils.Attributes; using TouchScript.Pointers; using UnityEngine; using UnityEngine.Profiling; namespace TouchScript.Gestures { /// /// Gesture which recognizes a point cluster which didn't move for specified time since it appeared. /// [AddComponentMenu("TouchScript/Gestures/Long Press Gesture")] [HelpURL("http://touchscript.github.io/docs/html/T_TouchScript_Gestures_LongPressGesture.htm")] public class LongPressGesture : Gesture { #region Constants /// /// Message name when gesture is recognized /// public const string LONG_PRESS_MESSAGE = "OnLongPress"; #endregion #region Events /// /// Occurs when gesture is recognized. /// public event EventHandler LongPressed { add { longPressedInvoker += value; } remove { longPressedInvoker -= value; } } // Needed to overcome iOS AOT limitations private EventHandler longPressedInvoker; /// /// Unity event, occurs when gesture is recognized. /// public GestureEvent OnLongPress = new GestureEvent(); #endregion #region Public properties /// /// Gets or sets total time in seconds required to hold pointers still. /// /// Time in seconds. public float TimeToPress { get { return timeToPress; } set { timeToPress = value; } } /// /// Gets or sets maximum distance in cm pointers can move before gesture fails. /// /// Distance in cm. public float DistanceLimit { get { return distanceLimit; } set { distanceLimit = value; distanceLimitInPixelsSquared = Mathf.Pow(distanceLimit * touchManager.DotsPerCentimeter, 2); } } #endregion #region Private variables [SerializeField] private float timeToPress = 1; [SerializeField] [NullToggle(NullFloatValue = float.PositiveInfinity)] private float distanceLimit = float.PositiveInfinity; private float distanceLimitInPixelsSquared; private Vector2 totalMovement; private CustomSampler gestureSampler; #endregion #region Unity methods /// protected override void Awake() { base.Awake(); gestureSampler = CustomSampler.Create("[TouchScript] Long Press Gesture"); } /// protected override void OnEnable() { base.OnEnable(); distanceLimitInPixelsSquared = Mathf.Pow(distanceLimit * touchManager.DotsPerCentimeter, 2); } [ContextMenu("Basic Editor")] private void switchToBasicEditor() { basicEditor = true; } #endregion #region Gesture callbacks /// protected override void pointersPressed(IList pointers) { gestureSampler.Begin(); base.pointersPressed(pointers); if (pointersNumState == PointersNumState.PassedMaxThreshold || pointersNumState == PointersNumState.PassedMinMaxThreshold) { setState(GestureState.Failed); } else if (pointersNumState == PointersNumState.PassedMinThreshold) { setState(GestureState.Possible); StartCoroutine("wait"); } gestureSampler.End(); } /// protected override void pointersUpdated(IList pointers) { gestureSampler.Begin(); base.pointersUpdated(pointers); if (distanceLimit < float.PositiveInfinity) { totalMovement += ScreenPosition - PreviousScreenPosition; if (totalMovement.sqrMagnitude > distanceLimitInPixelsSquared) setState(GestureState.Failed); } gestureSampler.End(); } /// protected override void pointersReleased(IList pointers) { gestureSampler.Begin(); base.pointersReleased(pointers); if (pointersNumState == PointersNumState.PassedMinThreshold) { setState(GestureState.Failed); } gestureSampler.End(); } /// protected override void onRecognized() { base.onRecognized(); if (longPressedInvoker != null) longPressedInvoker.InvokeHandleExceptions(this, EventArgs.Empty); if (UseSendMessage && SendMessageTarget != null) SendMessageTarget.SendMessage(LONG_PRESS_MESSAGE, this, SendMessageOptions.DontRequireReceiver); if (UseUnityEvents) OnLongPress.Invoke(this); } /// protected override void reset() { base.reset(); totalMovement = Vector2.zero; StopCoroutine("wait"); } #endregion #region Private functions private IEnumerator wait() { // WaitForSeconds is affected by time scale! var targetTime = Time.unscaledTime + TimeToPress; while (targetTime > Time.unscaledTime) yield return null; if (State == GestureState.Possible) { var data = GetScreenPositionHitData(); if (data.Target == null || !data.Target.IsChildOf(cachedTransform)) setState(GestureState.Failed); else setState(GestureState.Recognized); } } #endregion } }