Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
7.9 KiB

  1. // UI Draggable Item|UI|80030
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. using UnityEngine.EventSystems;
  6. /// <summary>
  7. /// Event Payload
  8. /// </summary>
  9. /// <param name="target">The target the item is dragged onto.</param>
  10. public struct UIDraggableItemEventArgs
  11. {
  12. public GameObject target;
  13. }
  14. /// <summary>
  15. /// Event Payload
  16. /// </summary>
  17. /// <param name="sender">this object</param>
  18. /// <param name="e"><see cref="UIDraggableItemEventArgs"/></param>
  19. public delegate void UIDraggableItemEventHandler(object sender, UIDraggableItemEventArgs e);
  20. /// <summary>
  21. /// Denotes a Unity UI Element as being draggable on the UI Canvas.
  22. /// </summary>
  23. /// <remarks>
  24. /// > If a UI Draggable item is set to `Restrict To Drop Zone = true` then the UI Draggable item must be a child of an element that has the VRTK_UIDropZone script applied to it to ensure it starts in a valid drop zone.
  25. ///
  26. /// **Script Usage:**
  27. /// * Place the `VRTK_UIDraggableItem` script on the Unity UI element that is to be dragged.
  28. /// </remarks>
  29. /// <example>
  30. /// `VRTK/Examples/034_Controls_InteractingWithUnityUI` demonstrates a collection of UI elements that are draggable
  31. /// </example>
  32. [RequireComponent(typeof(CanvasGroup))]
  33. [AddComponentMenu("VRTK/Scripts/UI/VRTK_UIDraggableItem")]
  34. public class VRTK_UIDraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
  35. {
  36. [Tooltip("If checked then the UI element can only be dropped in valid a VRTK_UIDropZone object and must start as a child of a VRTK_UIDropZone object. If unchecked then the UI element can be dropped anywhere on the canvas.")]
  37. public bool restrictToDropZone = false;
  38. [Tooltip("If checked then the UI element can only be dropped on the original parent canvas. If unchecked the UI element can be dropped on any valid VRTK_UICanvas.")]
  39. public bool restrictToOriginalCanvas = false;
  40. [Tooltip("The offset to bring the UI element forward when it is being dragged.")]
  41. public float forwardOffset = 0.1f;
  42. /// <summary>
  43. /// The current valid drop zone the dragged element is hovering over.
  44. /// </summary>
  45. [HideInInspector]
  46. public GameObject validDropZone;
  47. /// <summary>
  48. /// Emitted when the draggable item is successfully dropped.
  49. /// </summary>
  50. public event UIDraggableItemEventHandler DraggableItemDropped;
  51. /// <summary>
  52. /// Emitted when the draggable item is reset.
  53. /// </summary>
  54. public event UIDraggableItemEventHandler DraggableItemReset;
  55. protected RectTransform dragTransform;
  56. protected Vector3 startPosition;
  57. protected Quaternion startRotation;
  58. protected GameObject startDropZone;
  59. protected Transform startParent;
  60. protected Canvas startCanvas;
  61. protected CanvasGroup canvasGroup;
  62. public virtual void OnDraggableItemDropped(UIDraggableItemEventArgs e)
  63. {
  64. if (DraggableItemDropped != null)
  65. {
  66. DraggableItemDropped(this, e);
  67. }
  68. }
  69. public virtual void OnDraggableItemReset(UIDraggableItemEventArgs e)
  70. {
  71. if (DraggableItemReset != null)
  72. {
  73. DraggableItemReset(this, e);
  74. }
  75. }
  76. public virtual void OnBeginDrag(PointerEventData eventData)
  77. {
  78. startPosition = transform.position;
  79. startRotation = transform.rotation;
  80. startParent = transform.parent;
  81. startCanvas = GetComponentInParent<Canvas>();
  82. canvasGroup.blocksRaycasts = false;
  83. if (restrictToDropZone)
  84. {
  85. startDropZone = GetComponentInParent<VRTK_UIDropZone>().gameObject;
  86. validDropZone = startDropZone;
  87. }
  88. SetDragPosition(eventData);
  89. VRTK_UIPointer pointer = GetPointer(eventData);
  90. if (pointer != null)
  91. {
  92. pointer.OnUIPointerElementDragStart(pointer.SetUIPointerEvent(pointer.pointerEventData.pointerPressRaycast, gameObject));
  93. }
  94. }
  95. public virtual void OnDrag(PointerEventData eventData)
  96. {
  97. SetDragPosition(eventData);
  98. }
  99. public virtual void OnEndDrag(PointerEventData eventData)
  100. {
  101. canvasGroup.blocksRaycasts = true;
  102. dragTransform = null;
  103. transform.position += (transform.forward * forwardOffset);
  104. bool validDragEnd = true;
  105. if (restrictToDropZone)
  106. {
  107. if (validDropZone != null && validDropZone != startDropZone)
  108. {
  109. transform.SetParent(validDropZone.transform);
  110. }
  111. else
  112. {
  113. ResetElement();
  114. validDragEnd = false;
  115. }
  116. }
  117. Canvas destinationCanvas = (eventData.pointerEnter != null ? eventData.pointerEnter.GetComponentInParent<Canvas>() : null);
  118. if (restrictToOriginalCanvas)
  119. {
  120. if (destinationCanvas != null && destinationCanvas != startCanvas)
  121. {
  122. ResetElement();
  123. validDragEnd = false;
  124. }
  125. }
  126. if (destinationCanvas == null)
  127. {
  128. //We've been dropped off of a canvas
  129. ResetElement();
  130. validDragEnd = false;
  131. }
  132. if (validDragEnd)
  133. {
  134. VRTK_UIPointer pointer = GetPointer(eventData);
  135. if (pointer != null)
  136. {
  137. pointer.OnUIPointerElementDragEnd(pointer.SetUIPointerEvent(pointer.pointerEventData.pointerPressRaycast, gameObject));
  138. }
  139. OnDraggableItemDropped(SetEventPayload(validDropZone));
  140. }
  141. validDropZone = null;
  142. startParent = null;
  143. startCanvas = null;
  144. }
  145. protected virtual void OnEnable()
  146. {
  147. canvasGroup = GetComponent<CanvasGroup>();
  148. if (restrictToDropZone && GetComponentInParent<VRTK_UIDropZone>() == null)
  149. {
  150. enabled = false;
  151. VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_UIDraggableItem", "VRTK_UIDropZone", "the parent", " if `freeDrop = false`"));
  152. }
  153. }
  154. protected virtual VRTK_UIPointer GetPointer(PointerEventData eventData)
  155. {
  156. GameObject controller = VRTK_DeviceFinder.GetControllerByIndex((uint)eventData.pointerId, false);
  157. return (controller != null ? controller.GetComponent<VRTK_UIPointer>() : null);
  158. }
  159. protected virtual void SetDragPosition(PointerEventData eventData)
  160. {
  161. if (eventData.pointerEnter != null && eventData.pointerEnter.transform as RectTransform != null)
  162. {
  163. dragTransform = eventData.pointerEnter.transform as RectTransform;
  164. }
  165. Vector3 pointerPosition;
  166. if (dragTransform != null && RectTransformUtility.ScreenPointToWorldPointInRectangle(dragTransform, eventData.position, eventData.pressEventCamera, out pointerPosition))
  167. {
  168. transform.position = pointerPosition - (transform.forward * forwardOffset);
  169. transform.rotation = dragTransform.rotation;
  170. }
  171. }
  172. protected virtual void ResetElement()
  173. {
  174. transform.position = startPosition;
  175. transform.rotation = startRotation;
  176. transform.SetParent(startParent);
  177. OnDraggableItemReset(SetEventPayload(startParent.gameObject));
  178. }
  179. protected virtual UIDraggableItemEventArgs SetEventPayload(GameObject target)
  180. {
  181. UIDraggableItemEventArgs e;
  182. e.target = target;
  183. return e;
  184. }
  185. }
  186. }