A game about forced loneliness, made by TACStudios
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}