namespace UIWidgets { using System; using System.Collections; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; /// /// Scroll buttons. /// [RequireComponent(typeof(ScrollRect))] public class ScrollButtons : MonoBehaviour { /// /// Is the ScrollButtons eligible for interaction? /// [SerializeField] public bool Interactable = true; /// /// ScrollRect. /// protected ScrollRect scrollRect; /// /// ScrollRect. /// public ScrollRect ScrollRect { get { if (scrollRect == null) { scrollRect = GetComponent(); } return scrollRect; } } /// /// Left scroll button. /// [SerializeField] protected RectTransform scrollButtonLeft; /// /// Gets or sets the left scroll button. /// /// The scroll button left. public RectTransform ScrollButtonLeft { get { return scrollButtonLeft; } set { scrollButtonLeft = SetScrollButton(scrollButtonLeft, value, ScrollOnHoldLeft, ScrollOnClickLeft); } } /// /// Right scroll button. /// [SerializeField] protected RectTransform scrollButtonRight; /// /// Gets or sets the right scroll button. /// /// The scroll button right. public RectTransform ScrollButtonRight { get { return scrollButtonRight; } set { scrollButtonRight = SetScrollButton(scrollButtonRight, value, ScrollOnHoldRight, ScrollOnClickRight); } } /// /// Top scroll button. /// [SerializeField] protected RectTransform scrollButtonTop; /// /// Gets or sets the top scroll button. /// /// The scroll button top. public RectTransform ScrollButtonTop { get { return scrollButtonTop; } set { scrollButtonTop = SetScrollButton(scrollButtonTop, value, ScrollOnHoldTop, ScrollOnClickTop); } } /// /// Bottom scroll button. /// [SerializeField] protected RectTransform scrollButtonBottom; /// /// Gets or sets the bottom scroll button. /// /// The scroll button bottom. public RectTransform ScrollButtonBottom { get { return scrollButtonBottom; } set { scrollButtonBottom = SetScrollButton(scrollButtonBottom, value, ScrollOnHoldBottom, ScrollOnClickBottom); } } /// /// Scroll sensitivity rate on click. /// Scroll on click on ScrollRect.scrollSensitivity * Rate /// [SerializeField] public float ScrollSensitivityRateOnClick = 10f; /// /// Scroll sensitivity rate on hold. /// Scroll during hold on ScrollRect.scrollSensitivity * Rate per 1 second /// [SerializeField] public float ScrollSensitivityRateHold = 50f; /// /// Animate scroll on click or scroll immediately? /// [SerializeField] [Tooltip("Animate scroll on click or scroll immediately?")] public bool Animate = true; /// /// Animation curve on click. /// [SerializeField] protected AnimationCurve curve = AnimationCurve.EaseInOut(0f, 0f, 0.2f, 1f); /// /// The length of the animation. /// protected float AnimationLength; /// /// Curve for click animation. /// /// The curve. public AnimationCurve Curve { get { return curve; } set { curve = value; AnimationLength = curve[curve.length - 1].time; } } /// /// Use unscaled time. /// [SerializeField] public bool UnscaledTime; /// /// Current animation coroutine. /// protected IEnumerator CurrentCoroutine; /// /// Animation start time. /// protected float AnimationStartTime; /// /// ScrollRect start position. /// protected Vector3 StartPosition; bool isInited; /// /// Start this instance. /// public virtual void Start() { Init(); } /// /// Init this instance. /// public virtual void Init() { if (isInited) { return; } Curve = curve; scrollButtonLeft = SetScrollButton(scrollButtonLeft, scrollButtonLeft, ScrollOnHoldLeft, ScrollOnClickLeft); scrollButtonRight = SetScrollButton(scrollButtonRight, scrollButtonRight, ScrollOnHoldRight, ScrollOnClickRight); scrollButtonTop = SetScrollButton(scrollButtonTop, scrollButtonTop, ScrollOnHoldTop, ScrollOnClickTop); scrollButtonBottom = SetScrollButton(scrollButtonBottom, scrollButtonBottom, ScrollOnHoldBottom, ScrollOnClickBottom); isInited = true; } /// /// Scroll on hold left button. /// protected virtual void ScrollOnHoldLeft() { ScrolOnHold(ScrollButtonType.Left); } /// /// Scroll on hold right button. /// protected virtual void ScrollOnHoldRight() { ScrolOnHold(ScrollButtonType.Right); } /// /// Scroll on hold top button. /// protected virtual void ScrollOnHoldTop() { ScrolOnHold(ScrollButtonType.Top); } /// /// Scroll on hold bottom button. /// protected virtual void ScrollOnHoldBottom() { ScrolOnHold(ScrollButtonType.Bottom); } /// /// Scroll on hold. /// /// Type. public void ScrolOnHold(ScrollButtonType type) { if (!Interactable) { return; } AnimationStop(); AnimationStartTime = UtilitiesTime.GetTime(UnscaledTime); StartPosition = ScrollRect.content.localPosition; ScrollRect.StopMovement(); CurrentCoroutine = AnimationHold(type); StartCoroutine(CurrentCoroutine); } /// /// Stop animation. /// protected virtual void AnimationStop() { if (CurrentCoroutine != null) { StopCoroutine(CurrentCoroutine); } } /// /// Sets the scroll button. /// /// Old button. /// New button. /// Action on pointer down. /// Action on pointer click. /// Returns new button. protected virtual RectTransform SetScrollButton(RectTransform oldButton, RectTransform newButton, UnityAction downAction, UnityAction clickAction) { if (oldButton != null) { Utilities.GetOrAddComponent(oldButton).OnDown.RemoveListener(downAction); Utilities.GetOrAddComponent(oldButton).OnUp.RemoveListener(AnimationStop); Utilities.GetOrAddComponent(oldButton).OnClick.RemoveListener(clickAction); } if (newButton != null) { Utilities.GetOrAddComponent(newButton).OnDown.AddListener(downAction); Utilities.GetOrAddComponent(newButton).OnUp.AddListener(AnimationStop); Utilities.GetOrAddComponent(newButton).OnClick.AddListener(clickAction); } return newButton; } /// /// Scroll on click left. /// public void ScrollOnClickLeft() { ScrollOnClick(ScrollButtonType.Left); } /// /// Scroll on click right. /// public void ScrollOnClickRight() { ScrollOnClick(ScrollButtonType.Right); } /// /// Scroll on click top. /// public void ScrollOnClickTop() { ScrollOnClick(ScrollButtonType.Top); } /// /// Scroll on click bottom. /// public void ScrollOnClickBottom() { ScrollOnClick(ScrollButtonType.Bottom); } /// /// Scroll on click. /// /// Type. public void ScrollOnClick(ScrollButtonType type) { if (!Interactable) { return; } AnimationStop(); if ((AnimationStartTime + AnimationLength) < UtilitiesTime.GetTime(UnscaledTime)) { return; } ScrollRect.StopMovement(); var start = ScrollRect.content.localPosition; var end = ScrollOnClick(type, start, ScrollRect.scrollSensitivity * ScrollSensitivityRateOnClick); if (Animate) { CurrentCoroutine = AnimationClick(start, end); StartCoroutine(CurrentCoroutine); } else { ScrollRect.content.localPosition = end; ForceUpdateBounds(); } } /// /// Force ScrollRect to update bounds. /// protected void ForceUpdateBounds() { if (ScrollRect.movementType != ScrollRect.MovementType.Unrestricted) { ScrollRect.horizontalNormalizedPosition = Mathf.Clamp(ScrollRect.horizontalNormalizedPosition, 0f, 1f); ScrollRect.verticalNormalizedPosition = Mathf.Clamp(ScrollRect.verticalNormalizedPosition, 0f, 1f); } } /// /// Animation on hold. /// /// Nothing. /// Type. protected virtual IEnumerator AnimationHold(ScrollButtonType type) { do { var delta = UtilitiesTime.GetDeltaTime(UnscaledTime); var step = scrollRect.scrollSensitivity * ScrollSensitivityRateHold * delta; ScrollRect.content.localPosition = ScrollOnClick(type, ScrollRect.content.localPosition, step); ForceUpdateBounds(); yield return null; } while (gameObject.activeSelf); } /// /// Gets the time. /// /// The time. [Obsolete("Use UtilitiesTime.GetTime(UnscaledTime).")] protected virtual float GetTime() { return UtilitiesTime.GetTime(UnscaledTime); } /// /// Animation on click. /// /// Nothing. /// Start scroll position. /// End scroll position. protected virtual IEnumerator AnimationClick(Vector3 start, Vector3 end) { var animation_position = 0f; do { animation_position = UtilitiesTime.GetTime(UnscaledTime) - AnimationStartTime; var pos = Vector3.Lerp(start, end, Curve.Evaluate(animation_position)); ScrollRect.content.localPosition = pos; ForceUpdateBounds(); yield return null; } while (animation_position < AnimationLength); ScrollRect.content.localPosition = end; ForceUpdateBounds(); } /// /// Get scroll. /// /// Type. /// Position. /// Scroll value. /// New position. protected virtual Vector3 ScrollOnClick(ScrollButtonType type, Vector3 position, float value) { switch (type) { case ScrollButtonType.Top: position.y -= value; break; case ScrollButtonType.Bottom: position.y += value; break; case ScrollButtonType.Left: position.x += value; break; case ScrollButtonType.Right: position.x -= value; break; default: throw new NotSupportedException(string.Format("Unknown ScrollButtonType: {0}", EnumHelper.ToString(type))); } return position; } /// /// This function is called when the MonoBehaviour will be destroyed. /// protected virtual void OnDestroy() { ScrollButtonLeft = null; ScrollButtonRight = null; ScrollButtonTop = null; ScrollButtonBottom = null; } } }