summaryrefslogtreecommitdiff
path: root/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs')
-rw-r--r--Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs422
1 files changed, 422 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs
new file mode 100644
index 0000000..c280305
--- /dev/null
+++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/UIControls/Scrollbar.cs
@@ -0,0 +1,422 @@
+using System;
+using System.Collections;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+
+namespace UnityEngine.UI
+{
+ [AddComponentMenu("UI/Scrollbar", 34)]
+ [RequireComponent(typeof(RectTransform))]
+ public class Scrollbar
+ : Selectable
+ , IBeginDragHandler
+ , IDragHandler
+ , IInitializePotentialDragHandler
+ , ICanvasElement
+ {
+ public enum Direction
+ {
+ LeftToRight,
+ RightToLeft,
+ BottomToTop,
+ TopToBottom,
+ }
+
+ [Serializable]
+ public class ScrollEvent : UnityEvent<float> {}
+
+ [SerializeField]
+ private RectTransform m_HandleRect;
+ public RectTransform handleRect { get { return m_HandleRect; } set { if (SetPropertyUtility.SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
+
+ // Direction of movement.
+ [SerializeField]
+ private Direction m_Direction = Direction.LeftToRight;
+ public Direction direction { get { return m_Direction; } set { if (SetPropertyUtility.SetStruct(ref m_Direction, value)) UpdateVisuals(); } }
+
+ protected Scrollbar()
+ {}
+
+ // Scroll bar's current value in 0 to 1 range.
+ [Range(0f, 1f)]
+ [SerializeField]
+ private float m_Value;
+ public float value
+ {
+ get
+ {
+ float val = m_Value;
+ if (m_NumberOfSteps > 1)
+ val = Mathf.Round(val * (m_NumberOfSteps - 1)) / (m_NumberOfSteps - 1);
+ return val;
+ }
+ set
+ {
+ Set(value);
+ }
+ }
+
+ // Scroll bar's current size in 0 to 1 range.
+ [Range(0f, 1f)]
+ [SerializeField]
+ private float m_Size = 0.2f;
+ public float size { get { return m_Size; } set { if (SetPropertyUtility.SetStruct(ref m_Size, Mathf.Clamp01(value))) UpdateVisuals(); } }
+
+ // Number of steps the scroll bar should be divided into. For example 5 means possible values of 0, 0.25, 0.5, 0.75, and 1.0.
+ [Range(0, 11)]
+ [SerializeField]
+ private int m_NumberOfSteps = 0;
+ public int numberOfSteps { get { return m_NumberOfSteps; } set { if (SetPropertyUtility.SetStruct(ref m_NumberOfSteps, value)) { Set(m_Value); UpdateVisuals(); } } }
+
+ [Space(6)]
+
+ // Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
+ [SerializeField]
+ private ScrollEvent m_OnValueChanged = new ScrollEvent();
+ public ScrollEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
+
+ // Private fields
+
+ private RectTransform m_ContainerRect;
+
+ // The offset from handle position to mouse down position
+ private Vector2 m_Offset = Vector2.zero;
+
+ // Size of each step.
+ float stepSize { get { return (m_NumberOfSteps > 1) ? 1f / (m_NumberOfSteps - 1) : 0.1f; } }
+
+ private DrivenRectTransformTracker m_Tracker;
+ private Coroutine m_PointerDownRepeat;
+ private bool isPointerDownAndNotDragging = false;
+
+#if UNITY_EDITOR
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+
+ m_Size = Mathf.Clamp01(m_Size);
+
+ //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
+ if (IsActive())
+ {
+ UpdateCachedReferences();
+ Set(m_Value, false);
+ // Update rects since other things might affect them even if value didn't change.
+ UpdateVisuals();
+ }
+
+ var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
+ if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
+ CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
+ }
+
+#endif // if UNITY_EDITOR
+
+ public virtual void Rebuild(CanvasUpdate executing)
+ {
+#if UNITY_EDITOR
+ if (executing == CanvasUpdate.Prelayout)
+ onValueChanged.Invoke(value);
+#endif
+ }
+
+ public virtual void LayoutComplete()
+ {}
+
+ public virtual void GraphicUpdateComplete()
+ {}
+
+ protected override void OnEnable()
+ {
+ base.OnEnable();
+ UpdateCachedReferences();
+ Set(m_Value, false);
+ // Update rects since they need to be initialized correctly.
+ UpdateVisuals();
+ }
+
+ protected override void OnDisable()
+ {
+ m_Tracker.Clear();
+ base.OnDisable();
+ }
+
+ void UpdateCachedReferences()
+ {
+ if (m_HandleRect && m_HandleRect.parent != null)
+ m_ContainerRect = m_HandleRect.parent.GetComponent<RectTransform>();
+ else
+ m_ContainerRect = null;
+ }
+
+ // Update the visible Image.
+ void Set(float input)
+ {
+ Set(input, true);
+ }
+
+ void Set(float input, bool sendCallback)
+ {
+ float currentValue = m_Value;
+ // Clamp the input
+ m_Value = Mathf.Clamp01(input);
+
+ // If the stepped value doesn't match the last one, it's time to update
+ if (currentValue == value)
+ return;
+
+ UpdateVisuals();
+ if (sendCallback)
+ {
+ UISystemProfilerApi.AddMarker("Scrollbar.value", this);
+ m_OnValueChanged.Invoke(value);
+ }
+ }
+
+ protected override void OnRectTransformDimensionsChange()
+ {
+ base.OnRectTransformDimensionsChange();
+
+ //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
+ if (!IsActive())
+ return;
+
+ UpdateVisuals();
+ }
+
+ enum Axis
+ {
+ Horizontal = 0,
+ Vertical = 1
+ }
+
+ Axis axis { get { return (m_Direction == Direction.LeftToRight || m_Direction == Direction.RightToLeft) ? Axis.Horizontal : Axis.Vertical; } }
+ bool reverseValue { get { return m_Direction == Direction.RightToLeft || m_Direction == Direction.TopToBottom; } }
+
+ // Force-update the scroll bar. Useful if you've changed the properties and want it to update visually.
+ private void UpdateVisuals()
+ {
+#if UNITY_EDITOR
+ if (!Application.isPlaying)
+ UpdateCachedReferences();
+#endif
+ m_Tracker.Clear();
+
+ if (m_ContainerRect != null)
+ {
+ m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
+ Vector2 anchorMin = Vector2.zero;
+ Vector2 anchorMax = Vector2.one;
+
+ float movement = value * (1 - size);
+ if (reverseValue)
+ {
+ anchorMin[(int)axis] = 1 - movement - size;
+ anchorMax[(int)axis] = 1 - movement;
+ }
+ else
+ {
+ anchorMin[(int)axis] = movement;
+ anchorMax[(int)axis] = movement + size;
+ }
+
+ m_HandleRect.anchorMin = anchorMin;
+ m_HandleRect.anchorMax = anchorMax;
+ }
+ }
+
+ // Update the scroll bar's position based on the mouse.
+ void UpdateDrag(PointerEventData eventData)
+ {
+ if (eventData.button != PointerEventData.InputButton.Left)
+ return;
+
+ if (m_ContainerRect == null)
+ return;
+
+ Vector2 localCursor;
+ if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(m_ContainerRect, eventData.position, eventData.pressEventCamera, out localCursor))
+ return;
+
+ Vector2 handleCenterRelativeToContainerCorner = localCursor - m_Offset - m_ContainerRect.rect.position;
+ Vector2 handleCorner = handleCenterRelativeToContainerCorner - (m_HandleRect.rect.size - m_HandleRect.sizeDelta) * 0.5f;
+
+ float parentSize = axis == 0 ? m_ContainerRect.rect.width : m_ContainerRect.rect.height;
+ float remainingSize = parentSize * (1 - size);
+ if (remainingSize <= 0)
+ return;
+
+ switch (m_Direction)
+ {
+ case Direction.LeftToRight:
+ Set(handleCorner.x / remainingSize);
+ break;
+ case Direction.RightToLeft:
+ Set(1f - (handleCorner.x / remainingSize));
+ break;
+ case Direction.BottomToTop:
+ Set(handleCorner.y / remainingSize);
+ break;
+ case Direction.TopToBottom:
+ Set(1f - (handleCorner.y / remainingSize));
+ break;
+ }
+ }
+
+ private bool MayDrag(PointerEventData eventData)
+ {
+ return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
+ }
+
+ public virtual void OnBeginDrag(PointerEventData eventData)
+ {
+ isPointerDownAndNotDragging = false;
+
+ if (!MayDrag(eventData))
+ return;
+
+ if (m_ContainerRect == null)
+ return;
+
+ m_Offset = Vector2.zero;
+ if (RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
+ {
+ Vector2 localMousePos;
+ if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
+ m_Offset = localMousePos - m_HandleRect.rect.center;
+ }
+ }
+
+ public virtual void OnDrag(PointerEventData eventData)
+ {
+ if (!MayDrag(eventData))
+ return;
+
+ if (m_ContainerRect != null)
+ UpdateDrag(eventData);
+ }
+
+ public override void OnPointerDown(PointerEventData eventData)
+ {
+ if (!MayDrag(eventData))
+ return;
+
+ base.OnPointerDown(eventData);
+ isPointerDownAndNotDragging = true;
+ m_PointerDownRepeat = StartCoroutine(ClickRepeat(eventData));
+ }
+
+ protected IEnumerator ClickRepeat(PointerEventData eventData)
+ {
+ while (isPointerDownAndNotDragging)
+ {
+ if (!RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
+ {
+ Vector2 localMousePos;
+ if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
+ {
+ var axisCoordinate = axis == 0 ? localMousePos.x : localMousePos.y;
+ if (axisCoordinate < 0)
+ value -= size;
+ else
+ value += size;
+ }
+ }
+ yield return new WaitForEndOfFrame();
+ }
+ StopCoroutine(m_PointerDownRepeat);
+ }
+
+ public override void OnPointerUp(PointerEventData eventData)
+ {
+ base.OnPointerUp(eventData);
+ isPointerDownAndNotDragging = false;
+ }
+
+ public override void OnMove(AxisEventData eventData)
+ {
+ if (!IsActive() || !IsInteractable())
+ {
+ base.OnMove(eventData);
+ return;
+ }
+
+ switch (eventData.moveDir)
+ {
+ case MoveDirection.Left:
+ if (axis == Axis.Horizontal && FindSelectableOnLeft() == null)
+ Set(reverseValue ? value + stepSize : value - stepSize);
+ else
+ base.OnMove(eventData);
+ break;
+ case MoveDirection.Right:
+ if (axis == Axis.Horizontal && FindSelectableOnRight() == null)
+ Set(reverseValue ? value - stepSize : value + stepSize);
+ else
+ base.OnMove(eventData);
+ break;
+ case MoveDirection.Up:
+ if (axis == Axis.Vertical && FindSelectableOnUp() == null)
+ Set(reverseValue ? value - stepSize : value + stepSize);
+ else
+ base.OnMove(eventData);
+ break;
+ case MoveDirection.Down:
+ if (axis == Axis.Vertical && FindSelectableOnDown() == null)
+ Set(reverseValue ? value + stepSize : value - stepSize);
+ else
+ base.OnMove(eventData);
+ break;
+ }
+ }
+
+ public override Selectable FindSelectableOnLeft()
+ {
+ if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
+ return null;
+ return base.FindSelectableOnLeft();
+ }
+
+ public override Selectable FindSelectableOnRight()
+ {
+ if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
+ return null;
+ return base.FindSelectableOnRight();
+ }
+
+ public override Selectable FindSelectableOnUp()
+ {
+ if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
+ return null;
+ return base.FindSelectableOnUp();
+ }
+
+ public override Selectable FindSelectableOnDown()
+ {
+ if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
+ return null;
+ return base.FindSelectableOnDown();
+ }
+
+ public virtual void OnInitializePotentialDrag(PointerEventData eventData)
+ {
+ eventData.useDragThreshold = false;
+ }
+
+ public void SetDirection(Direction direction, bool includeRectLayouts)
+ {
+ Axis oldAxis = axis;
+ bool oldReverse = reverseValue;
+ this.direction = direction;
+
+ if (!includeRectLayouts)
+ return;
+
+ if (axis != oldAxis)
+ RectTransformUtility.FlipLayoutAxes(transform as RectTransform, true, true);
+
+ if (reverseValue != oldReverse)
+ RectTransformUtility.FlipLayoutOnAxis(transform as RectTransform, (int)axis, true, true);
+ }
+ }
+}