A game about forced loneliness, made by TACStudios
at master 437 lines 16 kB view raw
1using System.Collections.Generic; 2using System.Text; 3using UnityEngine.UI; 4 5namespace UnityEngine.EventSystems 6{ 7 /// <summary> 8 /// A BaseInputModule for pointer input. 9 /// </summary> 10 public abstract class PointerInputModule : BaseInputModule 11 { 12 /// <summary> 13 /// Id of the cached left mouse pointer event. 14 /// </summary> 15 public const int kMouseLeftId = -1; 16 17 /// <summary> 18 /// Id of the cached right mouse pointer event. 19 /// </summary> 20 public const int kMouseRightId = -2; 21 22 /// <summary> 23 /// Id of the cached middle mouse pointer event. 24 /// </summary> 25 public const int kMouseMiddleId = -3; 26 27 /// <summary> 28 /// Touch id for when simulating touches on a non touch device. 29 /// </summary> 30 public const int kFakeTouchesId = -4; 31 32 protected Dictionary<int, PointerEventData> m_PointerData = new Dictionary<int, PointerEventData>(); 33 34 /// <summary> 35 /// Search the cache for currently active pointers, return true if found. 36 /// </summary> 37 /// <param name="id">Touch ID</param> 38 /// <param name="data">Found data</param> 39 /// <param name="create">If not found should it be created</param> 40 /// <returns>True if pointer is found.</returns> 41 protected bool GetPointerData(int id, out PointerEventData data, bool create) 42 { 43 if (!m_PointerData.TryGetValue(id, out data) && create) 44 { 45 data = new PointerEventData(eventSystem) 46 { 47 pointerId = id, 48 }; 49 m_PointerData.Add(id, data); 50 return true; 51 } 52 return false; 53 } 54 55 /// <summary> 56 /// Remove the PointerEventData from the cache. 57 /// </summary> 58 protected void RemovePointerData(PointerEventData data) 59 { 60 m_PointerData.Remove(data.pointerId); 61 } 62 63 /// <summary> 64 /// Given a touch populate the PointerEventData and return if we are pressed or released. 65 /// </summary> 66 /// <param name="input">Touch being processed</param> 67 /// <param name="pressed">Are we pressed this frame</param> 68 /// <param name="released">Are we released this frame</param> 69 /// <returns></returns> 70 protected PointerEventData GetTouchPointerEventData(Touch input, out bool pressed, out bool released) 71 { 72 PointerEventData pointerData; 73 var created = GetPointerData(input.fingerId, out pointerData, true); 74 75 pointerData.Reset(); 76 77 pressed = created || (input.phase == TouchPhase.Began); 78 released = (input.phase == TouchPhase.Canceled) || (input.phase == TouchPhase.Ended); 79 80 if (created) 81 pointerData.position = input.position; 82 83 if (pressed) 84 pointerData.delta = Vector2.zero; 85 else 86 pointerData.delta = input.position - pointerData.position; 87 88 pointerData.position = input.position; 89 90 pointerData.button = PointerEventData.InputButton.Left; 91 92 if (input.phase == TouchPhase.Canceled) 93 { 94 pointerData.pointerCurrentRaycast = new RaycastResult(); 95 } 96 else 97 { 98 eventSystem.RaycastAll(pointerData, m_RaycastResultCache); 99 100 var raycast = FindFirstRaycast(m_RaycastResultCache); 101 pointerData.pointerCurrentRaycast = raycast; 102 m_RaycastResultCache.Clear(); 103 } 104 105 pointerData.pressure = input.pressure; 106 pointerData.altitudeAngle = input.altitudeAngle; 107 pointerData.azimuthAngle = input.azimuthAngle; 108 pointerData.radius = Vector2.one * input.radius; 109 pointerData.radiusVariance = Vector2.one * input.radiusVariance; 110 111 return pointerData; 112 } 113 114 /// <summary> 115 /// Copy one PointerEventData to another. 116 /// </summary> 117 protected void CopyFromTo(PointerEventData @from, PointerEventData @to) 118 { 119 @to.position = @from.position; 120 @to.delta = @from.delta; 121 @to.scrollDelta = @from.scrollDelta; 122 @to.pointerCurrentRaycast = @from.pointerCurrentRaycast; 123 @to.pointerEnter = @from.pointerEnter; 124 125 @to.pressure = @from.pressure; 126 @to.tangentialPressure = @from.tangentialPressure; 127 @to.altitudeAngle = @from.altitudeAngle; 128 @to.azimuthAngle = @from.azimuthAngle; 129 @to.twist = @from.twist; 130 @to.radius = @from.radius; 131 @to.radiusVariance = @from.radiusVariance; 132 } 133 134 /// <summary> 135 /// Given a mouse button return the current state for the frame. 136 /// </summary> 137 /// <param name="buttonId">Mouse button ID</param> 138 protected PointerEventData.FramePressState StateForMouseButton(int buttonId) 139 { 140 var pressed = input.GetMouseButtonDown(buttonId); 141 var released = input.GetMouseButtonUp(buttonId); 142 if (pressed && released) 143 return PointerEventData.FramePressState.PressedAndReleased; 144 if (pressed) 145 return PointerEventData.FramePressState.Pressed; 146 if (released) 147 return PointerEventData.FramePressState.Released; 148 return PointerEventData.FramePressState.NotChanged; 149 } 150 151 protected class ButtonState 152 { 153 private PointerEventData.InputButton m_Button = PointerEventData.InputButton.Left; 154 155 public MouseButtonEventData eventData 156 { 157 get { return m_EventData; } 158 set { m_EventData = value; } 159 } 160 161 public PointerEventData.InputButton button 162 { 163 get { return m_Button; } 164 set { m_Button = value; } 165 } 166 167 private MouseButtonEventData m_EventData; 168 } 169 170 protected class MouseState 171 { 172 private List<ButtonState> m_TrackedButtons = new List<ButtonState>(); 173 174 public bool AnyPressesThisFrame() 175 { 176 var trackedButtonsCount = m_TrackedButtons.Count; 177 for (int i = 0; i < trackedButtonsCount; i++) 178 { 179 if (m_TrackedButtons[i].eventData.PressedThisFrame()) 180 return true; 181 } 182 return false; 183 } 184 185 public bool AnyReleasesThisFrame() 186 { 187 var trackedButtonsCount = m_TrackedButtons.Count; 188 for (int i = 0; i < trackedButtonsCount; i++) 189 { 190 if (m_TrackedButtons[i].eventData.ReleasedThisFrame()) 191 return true; 192 } 193 return false; 194 } 195 196 public ButtonState GetButtonState(PointerEventData.InputButton button) 197 { 198 ButtonState tracked = null; 199 var trackedButtonsCount = m_TrackedButtons.Count; 200 for (int i = 0; i < trackedButtonsCount; i++) 201 { 202 if (m_TrackedButtons[i].button == button) 203 { 204 tracked = m_TrackedButtons[i]; 205 break; 206 } 207 } 208 209 if (tracked == null) 210 { 211 tracked = new ButtonState { button = button, eventData = new MouseButtonEventData() }; 212 m_TrackedButtons.Add(tracked); 213 } 214 return tracked; 215 } 216 217 public void SetButtonState(PointerEventData.InputButton button, PointerEventData.FramePressState stateForMouseButton, PointerEventData data) 218 { 219 var toModify = GetButtonState(button); 220 toModify.eventData.buttonState = stateForMouseButton; 221 toModify.eventData.buttonData = data; 222 } 223 } 224 225 /// <summary> 226 /// Information about a mouse button event. 227 /// </summary> 228 public class MouseButtonEventData 229 { 230 /// <summary> 231 /// The state of the button this frame. 232 /// </summary> 233 public PointerEventData.FramePressState buttonState; 234 235 /// <summary> 236 /// Pointer data associated with the mouse event. 237 /// </summary> 238 public PointerEventData buttonData; 239 240 /// <summary> 241 /// Was the button pressed this frame? 242 /// </summary> 243 public bool PressedThisFrame() 244 { 245 return buttonState == PointerEventData.FramePressState.Pressed || buttonState == PointerEventData.FramePressState.PressedAndReleased; 246 } 247 248 /// <summary> 249 /// Was the button released this frame? 250 /// </summary> 251 public bool ReleasedThisFrame() 252 { 253 return buttonState == PointerEventData.FramePressState.Released || buttonState == PointerEventData.FramePressState.PressedAndReleased; 254 } 255 } 256 257 private readonly MouseState m_MouseState = new MouseState(); 258 259 /// <summary> 260 /// Return the current MouseState. Using the default pointer. 261 /// </summary> 262 protected virtual MouseState GetMousePointerEventData() 263 { 264 return GetMousePointerEventData(0); 265 } 266 267 /// <summary> 268 /// Return the current MouseState. 269 /// </summary> 270 protected virtual MouseState GetMousePointerEventData(int id) 271 { 272 // Populate the left button... 273 PointerEventData leftData; 274 var created = GetPointerData(kMouseLeftId, out leftData, true); 275 276 leftData.Reset(); 277 278 if (created) 279 leftData.position = input.mousePosition; 280 281 Vector2 pos = input.mousePosition; 282 if (Cursor.lockState == CursorLockMode.Locked) 283 { 284 // We don't want to do ANY cursor-based interaction when the mouse is locked 285 leftData.position = new Vector2(-1.0f, -1.0f); 286 leftData.delta = Vector2.zero; 287 } 288 else 289 { 290 leftData.delta = pos - leftData.position; 291 leftData.position = pos; 292 } 293 leftData.scrollDelta = input.mouseScrollDelta; 294 leftData.button = PointerEventData.InputButton.Left; 295 eventSystem.RaycastAll(leftData, m_RaycastResultCache); 296 var raycast = FindFirstRaycast(m_RaycastResultCache); 297 leftData.pointerCurrentRaycast = raycast; 298 m_RaycastResultCache.Clear(); 299 300 // copy the apropriate data into right and middle slots 301 PointerEventData rightData; 302 GetPointerData(kMouseRightId, out rightData, true); 303 rightData.Reset(); 304 305 CopyFromTo(leftData, rightData); 306 rightData.button = PointerEventData.InputButton.Right; 307 308 PointerEventData middleData; 309 GetPointerData(kMouseMiddleId, out middleData, true); 310 middleData.Reset(); 311 312 CopyFromTo(leftData, middleData); 313 middleData.button = PointerEventData.InputButton.Middle; 314 315 m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData); 316 m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData); 317 m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData); 318 319 return m_MouseState; 320 } 321 322 /// <summary> 323 /// Return the last PointerEventData for the given touch / mouse id. 324 /// </summary> 325 protected PointerEventData GetLastPointerEventData(int id) 326 { 327 PointerEventData data; 328 GetPointerData(id, out data, false); 329 return data; 330 } 331 332 private static bool ShouldStartDrag(Vector2 pressPos, Vector2 currentPos, float threshold, bool useDragThreshold) 333 { 334 if (!useDragThreshold) 335 return true; 336 337 return (pressPos - currentPos).sqrMagnitude >= threshold * threshold; 338 } 339 340 /// <summary> 341 /// Process movement for the current frame with the given pointer event. 342 /// </summary> 343 protected virtual void ProcessMove(PointerEventData pointerEvent) 344 { 345 var targetGO = (Cursor.lockState == CursorLockMode.Locked ? null : pointerEvent.pointerCurrentRaycast.gameObject); 346 HandlePointerExitAndEnter(pointerEvent, targetGO); 347 } 348 349 /// <summary> 350 /// Process the drag for the current frame with the given pointer event. 351 /// </summary> 352 protected virtual void ProcessDrag(PointerEventData pointerEvent) 353 { 354 if (!pointerEvent.IsPointerMoving() || 355 Cursor.lockState == CursorLockMode.Locked || 356 pointerEvent.pointerDrag == null) 357 return; 358 359 if (!pointerEvent.dragging 360 && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold)) 361 { 362 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler); 363 pointerEvent.dragging = true; 364 } 365 366 // Drag notification 367 if (pointerEvent.dragging) 368 { 369 // Before doing drag we should cancel any pointer down state 370 // And clear selection! 371 if (pointerEvent.pointerPress != pointerEvent.pointerDrag) 372 { 373 ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); 374 375 pointerEvent.eligibleForClick = false; 376 pointerEvent.pointerPress = null; 377 pointerEvent.rawPointerPress = null; 378 } 379 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler); 380 } 381 } 382 383 public override bool IsPointerOverGameObject(int pointerId) 384 { 385 var lastPointer = GetLastPointerEventData(pointerId); 386 if (lastPointer != null) 387 return lastPointer.pointerEnter != null; 388 return false; 389 } 390 391 /// <summary> 392 /// Clear all pointers and deselect any selected objects in the EventSystem. 393 /// </summary> 394 protected void ClearSelection() 395 { 396 var baseEventData = GetBaseEventData(); 397 398 foreach (var pointer in m_PointerData.Values) 399 { 400 // clear all selection 401 HandlePointerExitAndEnter(pointer, null); 402 } 403 404 m_PointerData.Clear(); 405 eventSystem.SetSelectedGameObject(null, baseEventData); 406 } 407 408 public override string ToString() 409 { 410 var sb = new StringBuilder("<b>Pointer Input Module of type: </b>" + GetType()); 411 sb.AppendLine(); 412 foreach (var pointer in m_PointerData) 413 { 414 if (pointer.Value == null) 415 continue; 416 sb.AppendLine("<B>Pointer:</b> " + pointer.Key); 417 sb.AppendLine(pointer.Value.ToString()); 418 } 419 return sb.ToString(); 420 } 421 422 /// <summary> 423 /// Deselect the current selected GameObject if the currently pointed-at GameObject is different. 424 /// </summary> 425 /// <param name="currentOverGo">The GameObject the pointer is currently over.</param> 426 /// <param name="pointerEvent">Current event data.</param> 427 protected void DeselectIfSelectionChanged(GameObject currentOverGo, BaseEventData pointerEvent) 428 { 429 // Selection tracking 430 var selectHandlerGO = ExecuteEvents.GetEventHandler<ISelectHandler>(currentOverGo); 431 // if we have clicked something new, deselect the old thing 432 // leave 'selection handling' up to the press event though. 433 if (selectHandlerGO != eventSystem.currentSelectedGameObject) 434 eventSystem.SetSelectedGameObject(null, pointerEvent); 435 } 436 } 437}