438 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Collections.Generic;
 | |
| using System.Text;
 | |
| using UnityEngine.UI;
 | |
| 
 | |
| namespace UnityEngine.EventSystems
 | |
| {
 | |
|     /// <summary>
 | |
|     /// A BaseInputModule for pointer input.
 | |
|     /// </summary>
 | |
|     public abstract class PointerInputModule : BaseInputModule
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// Id of the cached left mouse pointer event.
 | |
|         /// </summary>
 | |
|         public const int kMouseLeftId = -1;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Id of the cached right mouse pointer event.
 | |
|         /// </summary>
 | |
|         public const int kMouseRightId = -2;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Id of the cached middle mouse pointer event.
 | |
|         /// </summary>
 | |
|         public const int kMouseMiddleId = -3;
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Touch id for when simulating touches on a non touch device.
 | |
|         /// </summary>
 | |
|         public const int kFakeTouchesId = -4;
 | |
| 
 | |
|         protected Dictionary<int, PointerEventData> m_PointerData = new Dictionary<int, PointerEventData>();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Search the cache for currently active pointers, return true if found.
 | |
|         /// </summary>
 | |
|         /// <param name="id">Touch ID</param>
 | |
|         /// <param name="data">Found data</param>
 | |
|         /// <param name="create">If not found should it be created</param>
 | |
|         /// <returns>True if pointer is found.</returns>
 | |
|         protected bool GetPointerData(int id, out PointerEventData data, bool create)
 | |
|         {
 | |
|             if (!m_PointerData.TryGetValue(id, out data) && create)
 | |
|             {
 | |
|                 data = new PointerEventData(eventSystem)
 | |
|                 {
 | |
|                     pointerId = id,
 | |
|                 };
 | |
|                 m_PointerData.Add(id, data);
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Remove the PointerEventData from the cache.
 | |
|         /// </summary>
 | |
|         protected void RemovePointerData(PointerEventData data)
 | |
|         {
 | |
|             m_PointerData.Remove(data.pointerId);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Given a touch populate the PointerEventData and return if we are pressed or released.
 | |
|         /// </summary>
 | |
|         /// <param name="input">Touch being processed</param>
 | |
|         /// <param name="pressed">Are we pressed this frame</param>
 | |
|         /// <param name="released">Are we released this frame</param>
 | |
|         /// <returns></returns>
 | |
|         protected PointerEventData GetTouchPointerEventData(Touch input, out bool pressed, out bool released)
 | |
|         {
 | |
|             PointerEventData pointerData;
 | |
|             var created = GetPointerData(input.fingerId, out pointerData, true);
 | |
| 
 | |
|             pointerData.Reset();
 | |
| 
 | |
|             pressed = created || (input.phase == TouchPhase.Began);
 | |
|             released = (input.phase == TouchPhase.Canceled) || (input.phase == TouchPhase.Ended);
 | |
| 
 | |
|             if (created)
 | |
|                 pointerData.position = input.position;
 | |
| 
 | |
|             if (pressed)
 | |
|                 pointerData.delta = Vector2.zero;
 | |
|             else
 | |
|                 pointerData.delta = input.position - pointerData.position;
 | |
| 
 | |
|             pointerData.position = input.position;
 | |
| 
 | |
|             pointerData.button = PointerEventData.InputButton.Left;
 | |
| 
 | |
|             if (input.phase == TouchPhase.Canceled)
 | |
|             {
 | |
|                 pointerData.pointerCurrentRaycast = new RaycastResult();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 eventSystem.RaycastAll(pointerData, m_RaycastResultCache);
 | |
| 
 | |
|                 var raycast = FindFirstRaycast(m_RaycastResultCache);
 | |
|                 pointerData.pointerCurrentRaycast = raycast;
 | |
|                 m_RaycastResultCache.Clear();
 | |
|             }
 | |
| 
 | |
|             pointerData.pressure = input.pressure;
 | |
|             pointerData.altitudeAngle = input.altitudeAngle;
 | |
|             pointerData.azimuthAngle = input.azimuthAngle;
 | |
|             pointerData.radius = Vector2.one * input.radius;
 | |
|             pointerData.radiusVariance = Vector2.one * input.radiusVariance;
 | |
| 
 | |
|             return pointerData;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Copy one PointerEventData to another.
 | |
|         /// </summary>
 | |
|         protected void CopyFromTo(PointerEventData @from, PointerEventData @to)
 | |
|         {
 | |
|             @to.position = @from.position;
 | |
|             @to.delta = @from.delta;
 | |
|             @to.scrollDelta = @from.scrollDelta;
 | |
|             @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
 | |
|             @to.pointerEnter = @from.pointerEnter;
 | |
| 
 | |
|             @to.pressure = @from.pressure;
 | |
|             @to.tangentialPressure = @from.tangentialPressure;
 | |
|             @to.altitudeAngle = @from.altitudeAngle;
 | |
|             @to.azimuthAngle = @from.azimuthAngle;
 | |
|             @to.twist = @from.twist;
 | |
|             @to.radius = @from.radius;
 | |
|             @to.radiusVariance = @from.radiusVariance;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Given a mouse button return the current state for the frame.
 | |
|         /// </summary>
 | |
|         /// <param name="buttonId">Mouse button ID</param>
 | |
|         protected PointerEventData.FramePressState StateForMouseButton(int buttonId)
 | |
|         {
 | |
|             var pressed = input.GetMouseButtonDown(buttonId);
 | |
|             var released = input.GetMouseButtonUp(buttonId);
 | |
|             if (pressed && released)
 | |
|                 return PointerEventData.FramePressState.PressedAndReleased;
 | |
|             if (pressed)
 | |
|                 return PointerEventData.FramePressState.Pressed;
 | |
|             if (released)
 | |
|                 return PointerEventData.FramePressState.Released;
 | |
|             return PointerEventData.FramePressState.NotChanged;
 | |
|         }
 | |
| 
 | |
|         protected class ButtonState
 | |
|         {
 | |
|             private PointerEventData.InputButton m_Button = PointerEventData.InputButton.Left;
 | |
| 
 | |
|             public MouseButtonEventData eventData
 | |
|             {
 | |
|                 get { return m_EventData; }
 | |
|                 set { m_EventData = value; }
 | |
|             }
 | |
| 
 | |
|             public PointerEventData.InputButton button
 | |
|             {
 | |
|                 get { return m_Button; }
 | |
|                 set { m_Button = value; }
 | |
|             }
 | |
| 
 | |
|             private MouseButtonEventData m_EventData;
 | |
|         }
 | |
| 
 | |
|         protected class MouseState
 | |
|         {
 | |
|             private List<ButtonState> m_TrackedButtons = new List<ButtonState>();
 | |
| 
 | |
|             public bool AnyPressesThisFrame()
 | |
|             {
 | |
|                 var trackedButtonsCount = m_TrackedButtons.Count;
 | |
|                 for (int i = 0; i < trackedButtonsCount; i++)
 | |
|                 {
 | |
|                     if (m_TrackedButtons[i].eventData.PressedThisFrame())
 | |
|                         return true;
 | |
|                 }
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             public bool AnyReleasesThisFrame()
 | |
|             {
 | |
|                 var trackedButtonsCount = m_TrackedButtons.Count;
 | |
|                 for (int i = 0; i < trackedButtonsCount; i++)
 | |
|                 {
 | |
|                     if (m_TrackedButtons[i].eventData.ReleasedThisFrame())
 | |
|                         return true;
 | |
|                 }
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             public ButtonState GetButtonState(PointerEventData.InputButton button)
 | |
|             {
 | |
|                 ButtonState tracked = null;
 | |
|                 var trackedButtonsCount = m_TrackedButtons.Count;
 | |
|                 for (int i = 0; i < trackedButtonsCount; i++)
 | |
|                 {
 | |
|                     if (m_TrackedButtons[i].button == button)
 | |
|                     {
 | |
|                         tracked = m_TrackedButtons[i];
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (tracked == null)
 | |
|                 {
 | |
|                     tracked = new ButtonState { button = button, eventData = new MouseButtonEventData() };
 | |
|                     m_TrackedButtons.Add(tracked);
 | |
|                 }
 | |
|                 return tracked;
 | |
|             }
 | |
| 
 | |
|             public void SetButtonState(PointerEventData.InputButton button, PointerEventData.FramePressState stateForMouseButton, PointerEventData data)
 | |
|             {
 | |
|                 var toModify = GetButtonState(button);
 | |
|                 toModify.eventData.buttonState = stateForMouseButton;
 | |
|                 toModify.eventData.buttonData = data;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Information about a mouse button event.
 | |
|         /// </summary>
 | |
|         public class MouseButtonEventData
 | |
|         {
 | |
|             /// <summary>
 | |
|             /// The state of the button this frame.
 | |
|             /// </summary>
 | |
|             public PointerEventData.FramePressState buttonState;
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Pointer data associated with the mouse event.
 | |
|             /// </summary>
 | |
|             public PointerEventData buttonData;
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Was the button pressed this frame?
 | |
|             /// </summary>
 | |
|             public bool PressedThisFrame()
 | |
|             {
 | |
|                 return buttonState == PointerEventData.FramePressState.Pressed || buttonState == PointerEventData.FramePressState.PressedAndReleased;
 | |
|             }
 | |
| 
 | |
|             /// <summary>
 | |
|             /// Was the button released this frame?
 | |
|             /// </summary>
 | |
|             public bool ReleasedThisFrame()
 | |
|             {
 | |
|                 return buttonState == PointerEventData.FramePressState.Released || buttonState == PointerEventData.FramePressState.PressedAndReleased;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private readonly MouseState m_MouseState = new MouseState();
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the current MouseState. Using the default pointer.
 | |
|         /// </summary>
 | |
|         protected virtual MouseState GetMousePointerEventData()
 | |
|         {
 | |
|             return GetMousePointerEventData(0);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the current MouseState.
 | |
|         /// </summary>
 | |
|         protected virtual MouseState GetMousePointerEventData(int id)
 | |
|         {
 | |
|             // Populate the left button...
 | |
|             PointerEventData leftData;
 | |
|             var created = GetPointerData(kMouseLeftId, out leftData, true);
 | |
| 
 | |
|             leftData.Reset();
 | |
| 
 | |
|             if (created)
 | |
|                 leftData.position = input.mousePosition;
 | |
| 
 | |
|             Vector2 pos = input.mousePosition;
 | |
|             if (Cursor.lockState == CursorLockMode.Locked)
 | |
|             {
 | |
|                 // We don't want to do ANY cursor-based interaction when the mouse is locked
 | |
|                 leftData.position = new Vector2(-1.0f, -1.0f);
 | |
|                 leftData.delta = Vector2.zero;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 leftData.delta = pos - leftData.position;
 | |
|                 leftData.position = pos;
 | |
|             }
 | |
|             leftData.scrollDelta = input.mouseScrollDelta;
 | |
|             leftData.button = PointerEventData.InputButton.Left;
 | |
|             eventSystem.RaycastAll(leftData, m_RaycastResultCache);
 | |
|             var raycast = FindFirstRaycast(m_RaycastResultCache);
 | |
|             leftData.pointerCurrentRaycast = raycast;
 | |
|             m_RaycastResultCache.Clear();
 | |
| 
 | |
|             // copy the apropriate data into right and middle slots
 | |
|             PointerEventData rightData;
 | |
|             GetPointerData(kMouseRightId, out rightData, true);
 | |
|             rightData.Reset();
 | |
| 
 | |
|             CopyFromTo(leftData, rightData);
 | |
|             rightData.button = PointerEventData.InputButton.Right;
 | |
| 
 | |
|             PointerEventData middleData;
 | |
|             GetPointerData(kMouseMiddleId, out middleData, true);
 | |
|             middleData.Reset();
 | |
| 
 | |
|             CopyFromTo(leftData, middleData);
 | |
|             middleData.button = PointerEventData.InputButton.Middle;
 | |
| 
 | |
|             m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData);
 | |
|             m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
 | |
|             m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);
 | |
| 
 | |
|             return m_MouseState;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return the last PointerEventData for the given touch / mouse id.
 | |
|         /// </summary>
 | |
|         protected PointerEventData GetLastPointerEventData(int id)
 | |
|         {
 | |
|             PointerEventData data;
 | |
|             GetPointerData(id, out data, false);
 | |
|             return data;
 | |
|         }
 | |
| 
 | |
|         private static bool ShouldStartDrag(Vector2 pressPos, Vector2 currentPos, float threshold, bool useDragThreshold)
 | |
|         {
 | |
|             if (!useDragThreshold)
 | |
|                 return true;
 | |
| 
 | |
|             return (pressPos - currentPos).sqrMagnitude >= threshold * threshold;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Process movement for the current frame with the given pointer event.
 | |
|         /// </summary>
 | |
|         protected virtual void ProcessMove(PointerEventData pointerEvent)
 | |
|         {
 | |
|             var targetGO = (Cursor.lockState == CursorLockMode.Locked ? null : pointerEvent.pointerCurrentRaycast.gameObject);
 | |
|             HandlePointerExitAndEnter(pointerEvent, targetGO);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Process the drag for the current frame with the given pointer event.
 | |
|         /// </summary>
 | |
|         protected virtual void ProcessDrag(PointerEventData pointerEvent)
 | |
|         {
 | |
|             if (!pointerEvent.IsPointerMoving() ||
 | |
|                 Cursor.lockState == CursorLockMode.Locked ||
 | |
|                 pointerEvent.pointerDrag == null)
 | |
|                 return;
 | |
| 
 | |
|             if (!pointerEvent.dragging
 | |
|                 && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold))
 | |
|             {
 | |
|                 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
 | |
|                 pointerEvent.dragging = true;
 | |
|             }
 | |
| 
 | |
|             // Drag notification
 | |
|             if (pointerEvent.dragging)
 | |
|             {
 | |
|                 // Before doing drag we should cancel any pointer down state
 | |
|                 // And clear selection!
 | |
|                 if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
 | |
|                 {
 | |
|                     ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
 | |
| 
 | |
|                     pointerEvent.eligibleForClick = false;
 | |
|                     pointerEvent.pointerPress = null;
 | |
|                     pointerEvent.rawPointerPress = null;
 | |
|                 }
 | |
|                 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public override bool IsPointerOverGameObject(int pointerId)
 | |
|         {
 | |
|             var lastPointer = GetLastPointerEventData(pointerId);
 | |
|             if (lastPointer != null)
 | |
|                 return lastPointer.pointerEnter != null;
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Clear all pointers and deselect any selected objects in the EventSystem.
 | |
|         /// </summary>
 | |
|         protected void ClearSelection()
 | |
|         {
 | |
|             var baseEventData = GetBaseEventData();
 | |
| 
 | |
|             foreach (var pointer in m_PointerData.Values)
 | |
|             {
 | |
|                 // clear all selection
 | |
|                 HandlePointerExitAndEnter(pointer, null);
 | |
|             }
 | |
| 
 | |
|             m_PointerData.Clear();
 | |
|             eventSystem.SetSelectedGameObject(null, baseEventData);
 | |
|         }
 | |
| 
 | |
|         public override string ToString()
 | |
|         {
 | |
|             var sb = new StringBuilder("<b>Pointer Input Module of type: </b>" + GetType());
 | |
|             sb.AppendLine();
 | |
|             foreach (var pointer in m_PointerData)
 | |
|             {
 | |
|                 if (pointer.Value == null)
 | |
|                     continue;
 | |
|                 sb.AppendLine("<B>Pointer:</b> " + pointer.Key);
 | |
|                 sb.AppendLine(pointer.Value.ToString());
 | |
|             }
 | |
|             return sb.ToString();
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Deselect the current selected GameObject if the currently pointed-at GameObject is different.
 | |
|         /// </summary>
 | |
|         /// <param name="currentOverGo">The GameObject the pointer is currently over.</param>
 | |
|         /// <param name="pointerEvent">Current event data.</param>
 | |
|         protected void DeselectIfSelectionChanged(GameObject currentOverGo, BaseEventData pointerEvent)
 | |
|         {
 | |
|             // Selection tracking
 | |
|             var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo);
 | |
|             // if we have clicked something new, deselect the old thing
 | |
|             // leave 'selection handling' up to the press event though.
 | |
|             if (selectHandlerGO != eventSystem.currentSelectedGameObject)
 | |
|                 eventSystem.SetSelectedGameObject(null, pointerEvent);
 | |
|         }
 | |
|     }
 | |
| }
 |