SCSlider3D.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. using SC.XR.Unity.Module_InputSystem;
  2. using System;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. using UnityEngine.EventSystems;
  6. using UnityEngine.UI;
  7. namespace SC.XR.Unity
  8. {
  9. [AddComponentMenu("UI/SCSlider", 33)]
  10. public class SCSlider3D : MonoBehaviour, IDragHandler, IInitializePotentialDragHandler, IPointerDownHandler, IPointerUpHandler
  11. {
  12. public enum Direction
  13. {
  14. LeftToRight,
  15. RightToLeft,
  16. BottomToTop,
  17. TopToBottom,
  18. }
  19. [Serializable]
  20. public class SliderEvent : UnityEvent<float> { }
  21. [Space]
  22. [SerializeField]
  23. private float m_MinValue = 0;
  24. public float minValue { get { return m_MinValue; } set { if (SCSetPropertyUtility.SetStruct(ref m_MinValue, value)) { Set(m_Value); UpdateVisuals(); } } }
  25. [SerializeField]
  26. private float m_MaxValue = 1;
  27. public float maxValue { get { return m_MaxValue; } set { if (SCSetPropertyUtility.SetStruct(ref m_MaxValue, value)) { Set(m_Value); UpdateVisuals(); } } }
  28. [SerializeField]
  29. private bool m_WholeNumbers = false;
  30. public bool wholeNumbers { get { return m_WholeNumbers; } set { if (SCSetPropertyUtility.SetStruct(ref m_WholeNumbers, value)) { Set(m_Value); UpdateVisuals(); } } }
  31. [SerializeField]
  32. protected float m_Value;
  33. public virtual float value
  34. {
  35. get
  36. {
  37. if (wholeNumbers)
  38. return Mathf.Round(m_Value);
  39. return m_Value;
  40. }
  41. set
  42. {
  43. Set(value);
  44. }
  45. }
  46. public float normalizedValue
  47. {
  48. get
  49. {
  50. if (Mathf.Approximately(minValue, maxValue))
  51. return 0;
  52. return Mathf.InverseLerp(minValue, maxValue, value);
  53. }
  54. set
  55. {
  56. this.value = Mathf.Lerp(minValue, maxValue, value);
  57. }
  58. }
  59. [Space]
  60. // Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
  61. [SerializeField]
  62. private SliderEvent m_OnValueChanged = new SliderEvent();
  63. public SliderEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
  64. [SerializeField]
  65. private UnityEvent m_OnPointerDown = new UnityEvent();
  66. public UnityEvent onPointerDown { get { return m_OnPointerDown; } set { m_OnPointerDown = value; } }
  67. [SerializeField]
  68. private UnityEvent m_OnPointerUp = new UnityEvent();
  69. public UnityEvent onPointerUp { get { return m_OnPointerUp; } set { m_OnPointerUp = value; } }
  70. private DrivenRectTransformTracker m_Tracker;
  71. public BoxCollider handler;
  72. public BoxCollider handlerContainer;
  73. public Vector3 SliderStartWorldPosition
  74. {
  75. get
  76. {
  77. if (handlerContainer != null)
  78. {
  79. return handlerContainer.transform.position - handlerContainer.transform.TransformVector(Vector3.right * handlerContainer.size[0] / 2f);
  80. }
  81. return Vector3.zero;
  82. }
  83. }
  84. public Vector3 SliderEndWorldPosition
  85. {
  86. get
  87. {
  88. if (handlerContainer != null)
  89. {
  90. return handlerContainer.transform.position + handlerContainer.transform.TransformVector(Vector3.right * handlerContainer.size[0] / 2f);
  91. }
  92. return Vector3.zero;
  93. }
  94. }
  95. protected SCSlider3D()
  96. { }
  97. public virtual void Rebuild(CanvasUpdate executing)
  98. {
  99. #if UNITY_EDITOR
  100. if (executing == CanvasUpdate.Prelayout)
  101. onValueChanged.Invoke(value);
  102. #endif
  103. }
  104. public virtual void LayoutComplete()
  105. { }
  106. public virtual void GraphicUpdateComplete()
  107. { }
  108. protected virtual void OnEnable()
  109. {
  110. Set(m_Value, false);
  111. // Update rects since they need to be initialized correctly.
  112. UpdateVisuals();
  113. }
  114. protected virtual void OnDisable()
  115. {
  116. m_Tracker.Clear();
  117. }
  118. float ClampValue(float input)
  119. {
  120. float newValue = Mathf.Clamp(input, minValue, maxValue);
  121. if (wholeNumbers)
  122. newValue = Mathf.Round(newValue);
  123. return newValue;
  124. }
  125. // Set the valueUpdate the visible Image.
  126. void Set(float input)
  127. {
  128. Set(input, true);
  129. }
  130. protected virtual void Set(float input, bool sendCallback)
  131. {
  132. // Clamp the input
  133. float newValue = ClampValue(input);
  134. // If the stepped value doesn't match the last one, it's time to update
  135. if (m_Value == newValue)
  136. return;
  137. m_Value = newValue;
  138. UpdateVisuals();
  139. if (sendCallback)
  140. {
  141. UISystemProfilerApi.AddMarker("Slider.value", this);
  142. m_OnValueChanged.Invoke(newValue);
  143. }
  144. }
  145. #if UNITY_EDITOR
  146. protected void OnValidate()
  147. {
  148. if (wholeNumbers)
  149. {
  150. m_MinValue = Mathf.Round(m_MinValue);
  151. m_MaxValue = Mathf.Round(m_MaxValue);
  152. }
  153. //Onvalidate is called before OnEnabled. We need to make sure not to touch any other objects before OnEnable is run.
  154. Set(m_Value, false);
  155. // Update rects since other things might affect them even if value didn't change.
  156. UpdateVisuals();
  157. }
  158. #endif // if UNITY_EDITOR
  159. // Force-update the slider. Useful if you've changed the properties and want it to update visually.
  160. private void UpdateVisuals()
  161. {
  162. Vector3 handlerPosition = SliderStartWorldPosition + (SliderEndWorldPosition - SliderStartWorldPosition) * normalizedValue;
  163. if (handler != null)
  164. {
  165. handler.transform.position = handlerPosition;
  166. }
  167. }
  168. // Update the slider's position based on the mouse.
  169. void UpdateDrag(PointerEventData eventData, Camera cam, bool isDownClick = false)
  170. {
  171. Transform clickTransform = handlerContainer.transform;
  172. Vector2 localPositionInPlane;
  173. if (!SCTransformUtility.ScreenPointToLocalPointInPlane(clickTransform, eventData.position, cam, out localPositionInPlane))
  174. return;
  175. Vector2 colliderPosition = new Vector2(handlerContainer.size.x / 2f, handlerContainer.size.y / 2f) ;
  176. localPositionInPlane += colliderPosition;
  177. float val = Mathf.Clamp01(localPositionInPlane.x / handlerContainer.size.x);
  178. Debug.Log("localPositionInPlane.x:" + localPositionInPlane.x + " handlerContainer.bounds.size.x:" + handlerContainer.size.x);
  179. normalizedValue = val;
  180. return;
  181. }
  182. public void OnPointerDown(PointerEventData eventData)
  183. {
  184. m_OnPointerDown?.Invoke();
  185. //SCPointEventData scPointEventData = eventData as SCPointEventData;
  186. Camera eventCamera = eventData.pressEventCamera;
  187. //pointerDownWorldPosition = scPointEventData.dragAuchorPosition;
  188. //startSliderValue = normalizedValue;
  189. //worldToCameraMatrixCache = eventCamera.worldToCameraMatrix;
  190. //projectionMatrixCache = eventCamera.projectionMatrix;
  191. if (CheckIsClickCollider(handler, eventData))
  192. {
  193. //do nothing
  194. }
  195. else
  196. {
  197. UpdateDrag(eventData, eventCamera, true);
  198. }
  199. }
  200. public void OnPointerUp(PointerEventData eventData)
  201. {
  202. m_OnPointerUp?.Invoke();
  203. }
  204. public virtual void OnDrag(PointerEventData eventData)
  205. {
  206. UpdateDrag(eventData, eventData.pressEventCamera);
  207. }
  208. public virtual void OnInitializePotentialDrag(PointerEventData eventData)
  209. {
  210. eventData.useDragThreshold = false;
  211. }
  212. private bool CheckIsClickCollider(Collider collider, PointerEventData eventData)
  213. {
  214. Ray ray = new Ray();
  215. float distance = 0f;
  216. ComputeRayAndDistance(eventData, ref ray, ref distance);
  217. RaycastHit hitResult;
  218. if (collider.Raycast(ray, out hitResult, distance))
  219. {
  220. return true;
  221. }
  222. return false;
  223. }
  224. private void ComputeRayAndDistance(PointerEventData eventData, ref Ray ray, ref float distanceToClipPlane)
  225. {
  226. if (eventData.pressEventCamera == null)
  227. {
  228. Debug.LogError("pressEventCamera do not exist");
  229. return;
  230. }
  231. Camera eventCamera = eventData.pressEventCamera;
  232. Vector2 screenPosition = eventData.position;
  233. ray = eventCamera.ScreenPointToRay(screenPosition);
  234. // compensate far plane distance - see MouseEvents.cs
  235. float projectionDirection = ray.direction.z;
  236. distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection)
  237. ? Mathf.Infinity
  238. : Mathf.Abs((eventCamera.farClipPlane - eventCamera.nearClipPlane) / projectionDirection);
  239. }
  240. }
  241. }