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.
 
 
 

209 lines
7.9 KiB

// UI Draggable Item|UI|80030
namespace VRTK
{
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// Event Payload
/// </summary>
/// <param name="target">The target the item is dragged onto.</param>
public struct UIDraggableItemEventArgs
{
public GameObject target;
}
/// <summary>
/// Event Payload
/// </summary>
/// <param name="sender">this object</param>
/// <param name="e"><see cref="UIDraggableItemEventArgs"/></param>
public delegate void UIDraggableItemEventHandler(object sender, UIDraggableItemEventArgs e);
/// <summary>
/// Denotes a Unity UI Element as being draggable on the UI Canvas.
/// </summary>
/// <remarks>
/// > 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.
///
/// **Script Usage:**
/// * Place the `VRTK_UIDraggableItem` script on the Unity UI element that is to be dragged.
/// </remarks>
/// <example>
/// `VRTK/Examples/034_Controls_InteractingWithUnityUI` demonstrates a collection of UI elements that are draggable
/// </example>
[RequireComponent(typeof(CanvasGroup))]
[AddComponentMenu("VRTK/Scripts/UI/VRTK_UIDraggableItem")]
public class VRTK_UIDraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
[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.")]
public bool restrictToDropZone = false;
[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.")]
public bool restrictToOriginalCanvas = false;
[Tooltip("The offset to bring the UI element forward when it is being dragged.")]
public float forwardOffset = 0.1f;
/// <summary>
/// The current valid drop zone the dragged element is hovering over.
/// </summary>
[HideInInspector]
public GameObject validDropZone;
/// <summary>
/// Emitted when the draggable item is successfully dropped.
/// </summary>
public event UIDraggableItemEventHandler DraggableItemDropped;
/// <summary>
/// Emitted when the draggable item is reset.
/// </summary>
public event UIDraggableItemEventHandler DraggableItemReset;
protected RectTransform dragTransform;
protected Vector3 startPosition;
protected Quaternion startRotation;
protected GameObject startDropZone;
protected Transform startParent;
protected Canvas startCanvas;
protected CanvasGroup canvasGroup;
public virtual void OnDraggableItemDropped(UIDraggableItemEventArgs e)
{
if (DraggableItemDropped != null)
{
DraggableItemDropped(this, e);
}
}
public virtual void OnDraggableItemReset(UIDraggableItemEventArgs e)
{
if (DraggableItemReset != null)
{
DraggableItemReset(this, e);
}
}
public virtual void OnBeginDrag(PointerEventData eventData)
{
startPosition = transform.position;
startRotation = transform.rotation;
startParent = transform.parent;
startCanvas = GetComponentInParent<Canvas>();
canvasGroup.blocksRaycasts = false;
if (restrictToDropZone)
{
startDropZone = GetComponentInParent<VRTK_UIDropZone>().gameObject;
validDropZone = startDropZone;
}
SetDragPosition(eventData);
VRTK_UIPointer pointer = GetPointer(eventData);
if (pointer != null)
{
pointer.OnUIPointerElementDragStart(pointer.SetUIPointerEvent(pointer.pointerEventData.pointerPressRaycast, gameObject));
}
}
public virtual void OnDrag(PointerEventData eventData)
{
SetDragPosition(eventData);
}
public virtual void OnEndDrag(PointerEventData eventData)
{
canvasGroup.blocksRaycasts = true;
dragTransform = null;
transform.position += (transform.forward * forwardOffset);
bool validDragEnd = true;
if (restrictToDropZone)
{
if (validDropZone != null && validDropZone != startDropZone)
{
transform.SetParent(validDropZone.transform);
}
else
{
ResetElement();
validDragEnd = false;
}
}
Canvas destinationCanvas = (eventData.pointerEnter != null ? eventData.pointerEnter.GetComponentInParent<Canvas>() : null);
if (restrictToOriginalCanvas)
{
if (destinationCanvas != null && destinationCanvas != startCanvas)
{
ResetElement();
validDragEnd = false;
}
}
if (destinationCanvas == null)
{
//We've been dropped off of a canvas
ResetElement();
validDragEnd = false;
}
if (validDragEnd)
{
VRTK_UIPointer pointer = GetPointer(eventData);
if (pointer != null)
{
pointer.OnUIPointerElementDragEnd(pointer.SetUIPointerEvent(pointer.pointerEventData.pointerPressRaycast, gameObject));
}
OnDraggableItemDropped(SetEventPayload(validDropZone));
}
validDropZone = null;
startParent = null;
startCanvas = null;
}
protected virtual void OnEnable()
{
canvasGroup = GetComponent<CanvasGroup>();
if (restrictToDropZone && GetComponentInParent<VRTK_UIDropZone>() == null)
{
enabled = false;
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_UIDraggableItem", "VRTK_UIDropZone", "the parent", " if `freeDrop = false`"));
}
}
protected virtual VRTK_UIPointer GetPointer(PointerEventData eventData)
{
GameObject controller = VRTK_DeviceFinder.GetControllerByIndex((uint)eventData.pointerId, false);
return (controller != null ? controller.GetComponent<VRTK_UIPointer>() : null);
}
protected virtual void SetDragPosition(PointerEventData eventData)
{
if (eventData.pointerEnter != null && eventData.pointerEnter.transform as RectTransform != null)
{
dragTransform = eventData.pointerEnter.transform as RectTransform;
}
Vector3 pointerPosition;
if (dragTransform != null && RectTransformUtility.ScreenPointToWorldPointInRectangle(dragTransform, eventData.position, eventData.pressEventCamera, out pointerPosition))
{
transform.position = pointerPosition - (transform.forward * forwardOffset);
transform.rotation = dragTransform.rotation;
}
}
protected virtual void ResetElement()
{
transform.position = startPosition;
transform.rotation = startRotation;
transform.SetParent(startParent);
OnDraggableItemReset(SetEventPayload(startParent.gameObject));
}
protected virtual UIDraggableItemEventArgs SetEventPayload(GameObject target)
{
UIDraggableItemEventArgs e;
e.target = target;
return e;
}
}
}