mirror of
https://github.com/Project-Redacted/Highscores-Server.git
synced 2025-05-19 01:44:54 +00:00
Add example Unity Project
This commit is contained in:
parent
fda7ff28dd
commit
e3acdb9d6b
7122 changed files with 505543 additions and 2 deletions
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f27709c942d91541be1fd6aa5cb3d78
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b3cdabf2f1e76854d8aab5930305d70d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Event Data associated with Axis Events (Controller / Keyboard).
|
||||
/// </summary>
|
||||
public class AxisEventData : BaseEventData
|
||||
{
|
||||
/// <summary>
|
||||
/// Raw input vector associated with this event.
|
||||
/// </summary>
|
||||
public Vector2 moveVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// MoveDirection for this event.
|
||||
/// </summary>
|
||||
public MoveDirection moveDir { get; set; }
|
||||
|
||||
public AxisEventData(EventSystem eventSystem)
|
||||
: base(eventSystem)
|
||||
{
|
||||
moveVector = Vector2.zero;
|
||||
moveDir = MoveDirection.None;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b180fd8310805e44dbbef545d0231418
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// A class that can be used for sending simple events via the event system.
|
||||
/// </summary>
|
||||
public abstract class AbstractEventData
|
||||
{
|
||||
protected bool m_Used;
|
||||
|
||||
/// <summary>
|
||||
/// Reset the event.
|
||||
/// </summary>
|
||||
public virtual void Reset()
|
||||
{
|
||||
m_Used = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Internally sets a flag that can be checked via used to see if further processing should happen.
|
||||
/// </remarks>
|
||||
public virtual void Use()
|
||||
{
|
||||
m_Used = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the event used?
|
||||
/// </summary>
|
||||
public virtual bool used
|
||||
{
|
||||
get { return m_Used; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class that contains the base event data that is common to all event types in the new EventSystem.
|
||||
/// </summary>
|
||||
public class BaseEventData : AbstractEventData
|
||||
{
|
||||
private readonly EventSystem m_EventSystem;
|
||||
public BaseEventData(EventSystem eventSystem)
|
||||
{
|
||||
m_EventSystem = eventSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// >A reference to the BaseInputModule that sent this event.
|
||||
/// </summary>
|
||||
public BaseInputModule currentInputModule
|
||||
{
|
||||
get { return m_EventSystem.currentInputModule; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The object currently considered selected by the EventSystem.
|
||||
/// </summary>
|
||||
public GameObject selectedObject
|
||||
{
|
||||
get { return m_EventSystem.currentSelectedGameObject; }
|
||||
set { m_EventSystem.SetSelectedGameObject(value, this); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91f495459b6e34f419ac123740d798b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,267 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Each touch event creates one of these containing all the relevant information.
|
||||
/// </summary>
|
||||
public class PointerEventData : BaseEventData
|
||||
{
|
||||
/// <summary>
|
||||
/// Input press tracking.
|
||||
/// </summary>
|
||||
public enum InputButton
|
||||
{
|
||||
/// <summary>
|
||||
/// Left button
|
||||
/// </summary>
|
||||
Left = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Right button.
|
||||
/// </summary>
|
||||
Right = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Middle button
|
||||
/// </summary>
|
||||
Middle = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The state of a press for the given frame.
|
||||
/// </summary>
|
||||
public enum FramePressState
|
||||
{
|
||||
/// <summary>
|
||||
/// Button was pressed this frame.
|
||||
/// </summary>
|
||||
Pressed,
|
||||
|
||||
/// <summary>
|
||||
/// Button was released this frame.
|
||||
/// </summary>
|
||||
Released,
|
||||
|
||||
/// <summary>
|
||||
/// Button was pressed and released this frame.
|
||||
/// </summary>
|
||||
PressedAndReleased,
|
||||
|
||||
/// <summary>
|
||||
/// Same as last frame.
|
||||
/// </summary>
|
||||
NotChanged
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The object that received 'OnPointerEnter'.
|
||||
/// </summary>
|
||||
public GameObject pointerEnter { get; set; }
|
||||
|
||||
// The object that received OnPointerDown
|
||||
private GameObject m_PointerPress;
|
||||
|
||||
/// <summary>
|
||||
/// The raw GameObject for the last press event. This means that it is the 'pressed' GameObject even if it can not receive the press event itself.
|
||||
/// </summary>
|
||||
public GameObject lastPress { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The object that the press happened on even if it can not handle the press event.
|
||||
/// </summary>
|
||||
public GameObject rawPointerPress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The object that is receiving 'OnDrag'.
|
||||
/// </summary>
|
||||
public GameObject pointerDrag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RaycastResult associated with the current event.
|
||||
/// </summary>
|
||||
public RaycastResult pointerCurrentRaycast { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RaycastResult associated with the pointer press.
|
||||
/// </summary>
|
||||
public RaycastResult pointerPressRaycast { get; set; }
|
||||
|
||||
public List<GameObject> hovered = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Is it possible to click this frame
|
||||
/// </summary>
|
||||
public bool eligibleForClick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the pointer (touch id).
|
||||
/// </summary>
|
||||
public int pointerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current pointer position.
|
||||
/// </summary>
|
||||
public Vector2 position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Pointer delta since last update.
|
||||
/// </summary>
|
||||
public Vector2 delta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Position of the press.
|
||||
/// </summary>
|
||||
public Vector2 pressPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// World-space position where a ray cast into the screen hits something
|
||||
/// </summary>
|
||||
|
||||
[Obsolete("Use either pointerCurrentRaycast.worldPosition or pointerPressRaycast.worldPosition")]
|
||||
public Vector3 worldPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// World-space normal where a ray cast into the screen hits something
|
||||
/// </summary>
|
||||
[Obsolete("Use either pointerCurrentRaycast.worldNormal or pointerPressRaycast.worldNormal")]
|
||||
public Vector3 worldNormal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last time a click event was sent. Used for double click
|
||||
/// </summary>
|
||||
public float clickTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of clicks in a row.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI;
|
||||
/// using UnityEngine.EventSystems;// Required when using Event data.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour, IPointerDownHandler
|
||||
/// {
|
||||
/// public void OnPointerDown(PointerEventData eventData)
|
||||
/// {
|
||||
/// //Grab the number of consecutive clicks and assign it to an integer varible.
|
||||
/// int i = eventData.clickCount;
|
||||
/// //Display the click count.
|
||||
/// Debug.Log(i);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public int clickCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of scroll since the last update.
|
||||
/// </summary>
|
||||
public Vector2 scrollDelta { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should a drag threshold be used?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you do not want a drag threshold set this to false in IInitializePotentialDragHandler.OnInitializePotentialDrag.
|
||||
/// </remarks>
|
||||
public bool useDragThreshold { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is a drag operation currently occuring.
|
||||
/// </summary>
|
||||
public bool dragging { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The EventSystems.PointerEventData.InputButton for this event.
|
||||
/// </summary>
|
||||
public InputButton button { get; set; }
|
||||
|
||||
public PointerEventData(EventSystem eventSystem) : base(eventSystem)
|
||||
{
|
||||
eligibleForClick = false;
|
||||
|
||||
pointerId = -1;
|
||||
position = Vector2.zero; // Current position of the mouse or touch event
|
||||
delta = Vector2.zero; // Delta since last update
|
||||
pressPosition = Vector2.zero; // Delta since the event started being tracked
|
||||
clickTime = 0.0f; // The last time a click event was sent out (used for double-clicks)
|
||||
clickCount = 0; // Number of clicks in a row. 2 for a double-click for example.
|
||||
|
||||
scrollDelta = Vector2.zero;
|
||||
useDragThreshold = true;
|
||||
dragging = false;
|
||||
button = InputButton.Left;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the pointer moving.
|
||||
/// </summary>
|
||||
public bool IsPointerMoving()
|
||||
{
|
||||
return delta.sqrMagnitude > 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is scroll being used on the input device.
|
||||
/// </summary>
|
||||
public bool IsScrolling()
|
||||
{
|
||||
return scrollDelta.sqrMagnitude > 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The camera associated with the last OnPointerEnter event.
|
||||
/// </summary>
|
||||
public Camera enterEventCamera
|
||||
{
|
||||
get { return pointerCurrentRaycast.module == null ? null : pointerCurrentRaycast.module.eventCamera; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The camera associated with the last OnPointerPress event.
|
||||
/// </summary>
|
||||
public Camera pressEventCamera
|
||||
{
|
||||
get { return pointerPressRaycast.module == null ? null : pointerPressRaycast.module.eventCamera; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject that received the OnPointerDown.
|
||||
/// </summary>
|
||||
public GameObject pointerPress
|
||||
{
|
||||
get { return m_PointerPress; }
|
||||
set
|
||||
{
|
||||
if (m_PointerPress == value)
|
||||
return;
|
||||
|
||||
lastPress = m_PointerPress;
|
||||
m_PointerPress = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("<b>Position</b>: " + position);
|
||||
sb.AppendLine("<b>delta</b>: " + delta);
|
||||
sb.AppendLine("<b>eligibleForClick</b>: " + eligibleForClick);
|
||||
sb.AppendLine("<b>pointerEnter</b>: " + pointerEnter);
|
||||
sb.AppendLine("<b>pointerPress</b>: " + pointerPress);
|
||||
sb.AppendLine("<b>lastPointerPress</b>: " + lastPress);
|
||||
sb.AppendLine("<b>pointerDrag</b>: " + pointerDrag);
|
||||
sb.AppendLine("<b>Use Drag Threshold</b>: " + useDragThreshold);
|
||||
sb.AppendLine("<b>Current Raycast:</b>");
|
||||
sb.AppendLine(pointerCurrentRaycast.ToString());
|
||||
sb.AppendLine("<b>Press Raycast:</b>");
|
||||
sb.AppendLine(pointerPressRaycast.ToString());
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 75df57ccb1e44c64085399277405e1ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[Flags]
|
||||
/// <summary>
|
||||
/// Enum that tracks event State.
|
||||
/// </summary>
|
||||
public enum EventHandle
|
||||
{
|
||||
Unused = 0,
|
||||
Used = 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db7dd43fe1278a9459cd6036f096b91d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,376 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class that all EventSystem events inherit from.
|
||||
/// </summary>
|
||||
public interface IEventSystemHandler
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnPointerEnter callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IPointerEnterHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect pointer enter events
|
||||
/// </summary>
|
||||
void OnPointerEnter(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnPointerExit callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IPointerExitHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect pointer exit events
|
||||
/// </summary>
|
||||
void OnPointerExit(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnPointerDown callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IPointerDownHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect pointer down events.
|
||||
/// </summary>
|
||||
void OnPointerDown(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnPointerUp callbacks.
|
||||
/// Note: In order to receive OnPointerUp callbacks, you must also implement the EventSystems.IPointerDownHandler|IPointerDownHandler interface
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IPointerUpHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect pointer up events.
|
||||
/// </summary>
|
||||
void OnPointerUp(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnPointerClick callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
/// <remarks>
|
||||
/// Use the IPointerClickHandler Interface to handle click input using OnPointerClick callbacks. Ensure an Event System exists in the Scene to allow click detection. For click detection on non-UI GameObjects, ensure a EventSystems.PhysicsRaycaster is attached to the Camera.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour, IPointerClickHandler
|
||||
/// {
|
||||
/// //Detect if a click occurs
|
||||
/// public void OnPointerClick(PointerEventData pointerEventData)
|
||||
/// {
|
||||
/// //Output to console the clicked GameObject's name and the following message. You can replace this with your own actions for when clicking the GameObject.
|
||||
/// Debug.Log(name + " Game Object Clicked!");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public interface IPointerClickHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect clicks.
|
||||
/// </summary>
|
||||
void OnPointerClick(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnBeginDrag callbacks.
|
||||
/// Note: You need to implement IDragHandler in addition to IBeginDragHandler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IBeginDragHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by a BaseInputModule before a drag is started.
|
||||
/// </summary>
|
||||
void OnBeginDrag(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnInitializePotentialDrag callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IInitializePotentialDragHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by a BaseInputModule when a drag has been found but before it is valid to begin the drag.
|
||||
/// </summary>
|
||||
void OnInitializePotentialDrag(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnDrag callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
/// using UnityEngine.UI;
|
||||
///
|
||||
/// [RequireComponent(typeof(Image))]
|
||||
/// public class DragMe : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
/// {
|
||||
/// public bool dragOnSurfaces = true;
|
||||
///
|
||||
/// private GameObject m_DraggingIcon;
|
||||
/// private RectTransform m_DraggingPlane;
|
||||
///
|
||||
/// public void OnBeginDrag(PointerEventData eventData)
|
||||
/// {
|
||||
/// var canvas = FindInParents<Canvas>(gameObject);
|
||||
/// if (canvas == null)
|
||||
/// return;
|
||||
///
|
||||
/// // We have clicked something that can be dragged.
|
||||
/// // What we want to do is create an icon for this.
|
||||
/// m_DraggingIcon = new GameObject("icon");
|
||||
///
|
||||
/// m_DraggingIcon.transform.SetParent(canvas.transform, false);
|
||||
/// m_DraggingIcon.transform.SetAsLastSibling();
|
||||
///
|
||||
/// var image = m_DraggingIcon.AddComponent<Image>();
|
||||
///
|
||||
/// image.sprite = GetComponent<Image>().sprite;
|
||||
/// image.SetNativeSize();
|
||||
///
|
||||
/// if (dragOnSurfaces)
|
||||
/// m_DraggingPlane = transform as RectTransform;
|
||||
/// else
|
||||
/// m_DraggingPlane = canvas.transform as RectTransform;
|
||||
///
|
||||
/// SetDraggedPosition(eventData);
|
||||
/// }
|
||||
///
|
||||
/// public void OnDrag(PointerEventData data)
|
||||
/// {
|
||||
/// if (m_DraggingIcon != null)
|
||||
/// SetDraggedPosition(data);
|
||||
/// }
|
||||
///
|
||||
/// private void SetDraggedPosition(PointerEventData data)
|
||||
/// {
|
||||
/// if (dragOnSurfaces && data.pointerEnter != null && data.pointerEnter.transform as RectTransform != null)
|
||||
/// m_DraggingPlane = data.pointerEnter.transform as RectTransform;
|
||||
///
|
||||
/// var rt = m_DraggingIcon.GetComponent<RectTransform>();
|
||||
/// Vector3 globalMousePos;
|
||||
/// if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_DraggingPlane, data.position, data.pressEventCamera, out globalMousePos))
|
||||
/// {
|
||||
/// rt.position = globalMousePos;
|
||||
/// rt.rotation = m_DraggingPlane.rotation;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// public void OnEndDrag(PointerEventData eventData)
|
||||
/// {
|
||||
/// if (m_DraggingIcon != null)
|
||||
/// Destroy(m_DraggingIcon);
|
||||
/// }
|
||||
///
|
||||
/// static public T FindInParents<T>(GameObject go) where T : Component
|
||||
/// {
|
||||
/// if (go == null) return null;
|
||||
/// var comp = go.GetComponent<T>();
|
||||
///
|
||||
/// if (comp != null)
|
||||
/// return comp;
|
||||
///
|
||||
/// Transform t = go.transform.parent;
|
||||
/// while (t != null && comp == null)
|
||||
/// {
|
||||
/// comp = t.gameObject.GetComponent<T>();
|
||||
/// t = t.parent;
|
||||
/// }
|
||||
/// return comp;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public interface IDragHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// When dragging is occurring this will be called every time the cursor is moved.
|
||||
/// </summary>
|
||||
void OnDrag(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnEndDrag callbacks.
|
||||
/// Note: You need to implement IDragHandler in addition to IEndDragHandler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IEndDragHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by a BaseInputModule when a drag is ended.
|
||||
/// </summary>
|
||||
void OnEndDrag(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnDrop callbacks.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class DropMe : MonoBehaviour, IDropHandler
|
||||
/// {
|
||||
/// public void OnDrop(PointerEventData data)
|
||||
/// {
|
||||
/// if (data.pointerDrag != null)
|
||||
/// {
|
||||
/// Debug.Log ("Dropped object was: " + data.pointerDrag);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IDropHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by a BaseInputModule on a target that can accept a drop.
|
||||
/// </summary>
|
||||
void OnDrop(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnScroll callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IScrollHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this callback to detect scroll events.
|
||||
/// </summary>
|
||||
void OnScroll(PointerEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnUpdateSelected callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IUpdateSelectedHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when the object associated with this EventTrigger is updated.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class UpdateSelectedExample : MonoBehaviour, IUpdateSelectedHandler
|
||||
/// {
|
||||
/// public void OnUpdateSelected(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnUpdateSelected called.");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
void OnUpdateSelected(BaseEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnSelect callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface ISelectHandler : IEventSystemHandler
|
||||
{
|
||||
void OnSelect(BaseEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnDeselect callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IDeselectHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a new object is being selected.
|
||||
/// </summary>
|
||||
void OnDeselect(BaseEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnMove callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface IMoveHandler : IEventSystemHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by a BaseInputModule when a move event occurs.
|
||||
/// </summary>
|
||||
void OnMove(AxisEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnSubmit callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface ISubmitHandler : IEventSystemHandler
|
||||
{
|
||||
void OnSubmit(BaseEventData eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to implement if you wish to receive OnCancel callbacks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Criteria for this event is implementation dependent. For example see StandAloneInputModule.
|
||||
/// </remarks>
|
||||
public interface ICancelHandler : IEventSystemHandler
|
||||
{
|
||||
void OnCancel(BaseEventData eventData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2359c66dee10c454c97f6aea84e3fe22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,403 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[AddComponentMenu("Event/Event System")]
|
||||
/// <summary>
|
||||
/// Handles input, raycasting, and sending events.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The EventSystem is responsible for processing and handling events in a Unity scene. A scene should only contain one EventSystem. The EventSystem works in conjunction with a number of modules and mostly just holds state and delegates functionality to specific, overrideable components.
|
||||
/// When the EventSystem is started it searches for any BaseInputModules attached to the same GameObject and adds them to an internal list. On update each attached module receives an UpdateModules call, where the module can modify internal state. After each module has been Updated the active module has the Process call executed.This is where custom module processing can take place.
|
||||
/// </remarks>
|
||||
public class EventSystem : UIBehaviour
|
||||
{
|
||||
private List<BaseInputModule> m_SystemInputModules = new List<BaseInputModule>();
|
||||
|
||||
private BaseInputModule m_CurrentInputModule;
|
||||
|
||||
private static List<EventSystem> m_EventSystems = new List<EventSystem>();
|
||||
|
||||
/// <summary>
|
||||
/// Return the current EventSystem.
|
||||
/// </summary>
|
||||
public static EventSystem current
|
||||
{
|
||||
get { return m_EventSystems.Count > 0 ? m_EventSystems[0] : null; }
|
||||
set
|
||||
{
|
||||
int index = m_EventSystems.IndexOf(value);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
m_EventSystems.RemoveAt(index);
|
||||
m_EventSystems.Insert(0, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("m_Selected")]
|
||||
private GameObject m_FirstSelected;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_sendNavigationEvents = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should the EventSystem allow navigation events (move / submit / cancel).
|
||||
/// </summary>
|
||||
public bool sendNavigationEvents
|
||||
{
|
||||
get { return m_sendNavigationEvents; }
|
||||
set { m_sendNavigationEvents = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int m_DragThreshold = 10;
|
||||
|
||||
/// <summary>
|
||||
/// The soft area for dragging in pixels.
|
||||
/// </summary>
|
||||
public int pixelDragThreshold
|
||||
{
|
||||
get { return m_DragThreshold; }
|
||||
set { m_DragThreshold = value; }
|
||||
}
|
||||
|
||||
private GameObject m_CurrentSelected;
|
||||
|
||||
/// <summary>
|
||||
/// The currently active EventSystems.BaseInputModule.
|
||||
/// </summary>
|
||||
public BaseInputModule currentInputModule
|
||||
{
|
||||
get { return m_CurrentInputModule; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only one object can be selected at a time. Think: controller-selected button.
|
||||
/// </summary>
|
||||
public GameObject firstSelectedGameObject
|
||||
{
|
||||
get { return m_FirstSelected; }
|
||||
set { m_FirstSelected = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject currently considered active by the EventSystem.
|
||||
/// </summary>
|
||||
public GameObject currentSelectedGameObject
|
||||
{
|
||||
get { return m_CurrentSelected; }
|
||||
}
|
||||
|
||||
[Obsolete("lastSelectedGameObject is no longer supported")]
|
||||
public GameObject lastSelectedGameObject
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
private bool m_HasFocus = true;
|
||||
|
||||
/// <summary>
|
||||
/// Flag to say whether the EventSystem thinks it should be paused or not based upon focused state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used to determine inside the individual InputModules if the module should be ticked while the application doesnt have focus.
|
||||
/// </remarks>
|
||||
public bool isFocused
|
||||
{
|
||||
get { return m_HasFocus; }
|
||||
}
|
||||
|
||||
protected EventSystem()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Recalculate the internal list of BaseInputModules.
|
||||
/// </summary>
|
||||
public void UpdateModules()
|
||||
{
|
||||
GetComponents(m_SystemInputModules);
|
||||
for (int i = m_SystemInputModules.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_SystemInputModules[i] && m_SystemInputModules[i].IsActive())
|
||||
continue;
|
||||
|
||||
m_SystemInputModules.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
private bool m_SelectionGuard;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the EventSystem is already in a SetSelectedGameObject.
|
||||
/// </summary>
|
||||
public bool alreadySelecting
|
||||
{
|
||||
get { return m_SelectionGuard; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object.
|
||||
/// </summary>
|
||||
/// <param name="selected">GameObject to select.</param>
|
||||
/// <param name="pointer">Associated EventData.</param>
|
||||
public void SetSelectedGameObject(GameObject selected, BaseEventData pointer)
|
||||
{
|
||||
if (m_SelectionGuard)
|
||||
{
|
||||
Debug.LogError("Attempting to select " + selected + "while already selecting an object.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_SelectionGuard = true;
|
||||
if (selected == m_CurrentSelected)
|
||||
{
|
||||
m_SelectionGuard = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug.Log("Selection: new (" + selected + ") old (" + m_CurrentSelected + ")");
|
||||
ExecuteEvents.Execute(m_CurrentSelected, pointer, ExecuteEvents.deselectHandler);
|
||||
m_CurrentSelected = selected;
|
||||
ExecuteEvents.Execute(m_CurrentSelected, pointer, ExecuteEvents.selectHandler);
|
||||
m_SelectionGuard = false;
|
||||
}
|
||||
|
||||
private BaseEventData m_DummyData;
|
||||
private BaseEventData baseEventDataCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_DummyData == null)
|
||||
m_DummyData = new BaseEventData(this);
|
||||
|
||||
return m_DummyData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the object as selected. Will send an OnDeselect the the old selected object and OnSelect to the new selected object.
|
||||
/// </summary>
|
||||
/// <param name="selected">GameObject to select.</param>
|
||||
public void SetSelectedGameObject(GameObject selected)
|
||||
{
|
||||
SetSelectedGameObject(selected, baseEventDataCache);
|
||||
}
|
||||
|
||||
private static int RaycastComparer(RaycastResult lhs, RaycastResult rhs)
|
||||
{
|
||||
if (lhs.module != rhs.module)
|
||||
{
|
||||
var lhsEventCamera = lhs.module.eventCamera;
|
||||
var rhsEventCamera = rhs.module.eventCamera;
|
||||
if (lhsEventCamera != null && rhsEventCamera != null && lhsEventCamera.depth != rhsEventCamera.depth)
|
||||
{
|
||||
// need to reverse the standard compareTo
|
||||
if (lhsEventCamera.depth < rhsEventCamera.depth)
|
||||
return 1;
|
||||
if (lhsEventCamera.depth == rhsEventCamera.depth)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lhs.module.sortOrderPriority != rhs.module.sortOrderPriority)
|
||||
return rhs.module.sortOrderPriority.CompareTo(lhs.module.sortOrderPriority);
|
||||
|
||||
if (lhs.module.renderOrderPriority != rhs.module.renderOrderPriority)
|
||||
return rhs.module.renderOrderPriority.CompareTo(lhs.module.renderOrderPriority);
|
||||
}
|
||||
|
||||
if (lhs.sortingLayer != rhs.sortingLayer)
|
||||
{
|
||||
// Uses the layer value to properly compare the relative order of the layers.
|
||||
var rid = SortingLayer.GetLayerValueFromID(rhs.sortingLayer);
|
||||
var lid = SortingLayer.GetLayerValueFromID(lhs.sortingLayer);
|
||||
return rid.CompareTo(lid);
|
||||
}
|
||||
|
||||
if (lhs.sortingOrder != rhs.sortingOrder)
|
||||
return rhs.sortingOrder.CompareTo(lhs.sortingOrder);
|
||||
|
||||
// comparing depth only makes sense if the two raycast results have the same root canvas (case 912396)
|
||||
if (lhs.depth != rhs.depth && lhs.module.rootRaycaster == rhs.module.rootRaycaster)
|
||||
return rhs.depth.CompareTo(lhs.depth);
|
||||
|
||||
if (lhs.distance != rhs.distance)
|
||||
return lhs.distance.CompareTo(rhs.distance);
|
||||
|
||||
return lhs.index.CompareTo(rhs.index);
|
||||
}
|
||||
|
||||
private static readonly Comparison<RaycastResult> s_RaycastComparer = RaycastComparer;
|
||||
|
||||
/// <summary>
|
||||
/// Raycast into the scene using all configured BaseRaycasters.
|
||||
/// </summary>
|
||||
/// <param name="eventData">Current pointer data.</param>
|
||||
/// <param name="raycastResults">List of 'hits' to populate.</param>
|
||||
public void RaycastAll(PointerEventData eventData, List<RaycastResult> raycastResults)
|
||||
{
|
||||
raycastResults.Clear();
|
||||
var modules = RaycasterManager.GetRaycasters();
|
||||
for (int i = 0; i < modules.Count; ++i)
|
||||
{
|
||||
var module = modules[i];
|
||||
if (module == null || !module.IsActive())
|
||||
continue;
|
||||
|
||||
module.Raycast(eventData, raycastResults);
|
||||
}
|
||||
|
||||
raycastResults.Sort(s_RaycastComparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the pointer with the given ID over an EventSystem object?
|
||||
/// </summary>
|
||||
public bool IsPointerOverGameObject()
|
||||
{
|
||||
return IsPointerOverGameObject(PointerInputModule.kMouseLeftId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the pointer with the given ID over an EventSystem object?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If you use IsPointerOverGameObject() without a parameter, it points to the "left mouse button" (pointerId = -1); therefore when you use IsPointerOverGameObject for touch, you should consider passing a pointerId to it
|
||||
/// Note that for touch, IsPointerOverGameObject should be used with ''OnMouseDown()'' or ''Input.GetMouseButtonDown(0)'' or ''Input.GetTouch(0).phase == TouchPhase.Began''.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class MouseExample : MonoBehaviour
|
||||
/// {
|
||||
/// void Update()
|
||||
/// {
|
||||
/// // Check if the left mouse button was clicked
|
||||
/// if (Input.GetMouseButtonDown(0))
|
||||
/// {
|
||||
/// // Check if the mouse was clicked over a UI element
|
||||
/// if (EventSystem.current.IsPointerOverGameObject())
|
||||
/// {
|
||||
/// Debug.Log("Clicked on the UI");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public bool IsPointerOverGameObject(int pointerId)
|
||||
{
|
||||
if (m_CurrentInputModule == null)
|
||||
return false;
|
||||
|
||||
return m_CurrentInputModule.IsPointerOverGameObject(pointerId);
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
m_EventSystems.Add(this);
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
if (m_CurrentInputModule != null)
|
||||
{
|
||||
m_CurrentInputModule.DeactivateModule();
|
||||
m_CurrentInputModule = null;
|
||||
}
|
||||
|
||||
m_EventSystems.Remove(this);
|
||||
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
private void TickModules()
|
||||
{
|
||||
for (var i = 0; i < m_SystemInputModules.Count; i++)
|
||||
{
|
||||
if (m_SystemInputModules[i] != null)
|
||||
m_SystemInputModules[i].UpdateModule();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnApplicationFocus(bool hasFocus)
|
||||
{
|
||||
m_HasFocus = hasFocus;
|
||||
}
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (current != this)
|
||||
return;
|
||||
TickModules();
|
||||
|
||||
bool changedModule = false;
|
||||
for (var i = 0; i < m_SystemInputModules.Count; i++)
|
||||
{
|
||||
var module = m_SystemInputModules[i];
|
||||
if (module.IsModuleSupported() && module.ShouldActivateModule())
|
||||
{
|
||||
if (m_CurrentInputModule != module)
|
||||
{
|
||||
ChangeEventModule(module);
|
||||
changedModule = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no event module set... set the first valid one...
|
||||
if (m_CurrentInputModule == null)
|
||||
{
|
||||
for (var i = 0; i < m_SystemInputModules.Count; i++)
|
||||
{
|
||||
var module = m_SystemInputModules[i];
|
||||
if (module.IsModuleSupported())
|
||||
{
|
||||
ChangeEventModule(module);
|
||||
changedModule = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!changedModule && m_CurrentInputModule != null)
|
||||
m_CurrentInputModule.Process();
|
||||
}
|
||||
|
||||
private void ChangeEventModule(BaseInputModule module)
|
||||
{
|
||||
if (m_CurrentInputModule == module)
|
||||
return;
|
||||
|
||||
if (m_CurrentInputModule != null)
|
||||
m_CurrentInputModule.DeactivateModule();
|
||||
|
||||
if (module != null)
|
||||
module.ActivateModule();
|
||||
m_CurrentInputModule = module;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("<b>Selected:</b>" + currentSelectedGameObject);
|
||||
sb.AppendLine();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine(m_CurrentInputModule != null ? m_CurrentInputModule.ToString() : "No module");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 76c392e42b5098c458856cdf6ecaaaa1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,354 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[AddComponentMenu("Event/Event Trigger")]
|
||||
/// <summary>
|
||||
/// Receives events from the EventSystem and calls registered functions for each event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The EventTrigger can be used to specify functions you wish to be called for each EventSystem event.
|
||||
/// You can assign multiple functions to a single event and whenever the EventTrigger receives that event it will call those functions in the order they were provided.
|
||||
///
|
||||
/// NOTE: Attaching this component to a GameObject will make that object intercept ALL events, and no events will propagate to parent objects.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// There are two ways to intercept events: You could extend EventTrigger, and override the functions for the events you are interested in intercepting; as shown in this example:
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class EventTriggerExample : EventTrigger
|
||||
/// {
|
||||
/// public override void OnBeginDrag(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnBeginDrag called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnCancel(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnCancel called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnDeselect(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnDeselect called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnDrag(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnDrag called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnDrop(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnDrop called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnEndDrag(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnEndDrag called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnInitializePotentialDrag(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnInitializePotentialDrag called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnMove(AxisEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnMove called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnPointerClick(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerClick called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnPointerDown(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerDown called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnPointerEnter(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerEnter called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnPointerExit(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerExit called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnPointerUp(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerUp called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnScroll(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnScroll called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnSelect(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnSelect called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnSubmit(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnSubmit called.");
|
||||
/// }
|
||||
///
|
||||
/// public override void OnUpdateSelected(BaseEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnUpdateSelected called.");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// or you can specify individual delegates:
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
///
|
||||
/// public class EventTriggerDelegateExample : MonoBehaviour
|
||||
/// {
|
||||
/// void Start()
|
||||
/// {
|
||||
/// EventTrigger trigger = GetComponent<EventTrigger>();
|
||||
/// EventTrigger.Entry entry = new EventTrigger.Entry();
|
||||
/// entry.eventID = EventTriggerType.PointerDown;
|
||||
/// entry.callback.AddListener((data) => { OnPointerDownDelegate((PointerEventData)data); });
|
||||
/// trigger.triggers.Add(entry);
|
||||
/// }
|
||||
///
|
||||
/// public void OnPointerDownDelegate(PointerEventData data)
|
||||
/// {
|
||||
/// Debug.Log("OnPointerDownDelegate called.");
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class EventTrigger :
|
||||
MonoBehaviour,
|
||||
IPointerEnterHandler,
|
||||
IPointerExitHandler,
|
||||
IPointerDownHandler,
|
||||
IPointerUpHandler,
|
||||
IPointerClickHandler,
|
||||
IInitializePotentialDragHandler,
|
||||
IBeginDragHandler,
|
||||
IDragHandler,
|
||||
IEndDragHandler,
|
||||
IDropHandler,
|
||||
IScrollHandler,
|
||||
IUpdateSelectedHandler,
|
||||
ISelectHandler,
|
||||
IDeselectHandler,
|
||||
IMoveHandler,
|
||||
ISubmitHandler,
|
||||
ICancelHandler
|
||||
{
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// UnityEvent class for Triggers.
|
||||
/// </summary>
|
||||
public class TriggerEvent : UnityEvent<BaseEventData>
|
||||
{}
|
||||
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// An Entry in the EventSystem delegates list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It stores the callback and which event type should this callback be fired.
|
||||
/// </remarks>
|
||||
public class Entry
|
||||
{
|
||||
/// <summary>
|
||||
/// What type of event is the associated callback listening for.
|
||||
/// </summary>
|
||||
public EventTriggerType eventID = EventTriggerType.PointerClick;
|
||||
|
||||
/// <summary>
|
||||
/// The desired TriggerEvent to be Invoked.
|
||||
/// </summary>
|
||||
public TriggerEvent callback = new TriggerEvent();
|
||||
}
|
||||
|
||||
[FormerlySerializedAs("delegates")]
|
||||
[SerializeField]
|
||||
private List<Entry> m_Delegates;
|
||||
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
[Obsolete("Please use triggers instead (UnityUpgradable) -> triggers", true)]
|
||||
public List<Entry> delegates { get { return triggers; } set { triggers = value; } }
|
||||
|
||||
protected EventTrigger()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// All the functions registered in this EventTrigger
|
||||
/// </summary>
|
||||
public List<Entry> triggers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Delegates == null)
|
||||
m_Delegates = new List<Entry>();
|
||||
return m_Delegates;
|
||||
}
|
||||
set { m_Delegates = value; }
|
||||
}
|
||||
|
||||
private void Execute(EventTriggerType id, BaseEventData eventData)
|
||||
{
|
||||
for (int i = 0, imax = triggers.Count; i < imax; ++i)
|
||||
{
|
||||
var ent = triggers[i];
|
||||
if (ent.eventID == id && ent.callback != null)
|
||||
ent.callback.Invoke(eventData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when the pointer enters the object associated with this EventTrigger.
|
||||
/// </summary>
|
||||
public virtual void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.PointerEnter, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when the pointer exits the object associated with this EventTrigger.
|
||||
/// </summary>
|
||||
public virtual void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.PointerExit, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem every time the pointer is moved during dragging.
|
||||
/// </summary>
|
||||
public virtual void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Drag, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when an object accepts a drop.
|
||||
/// </summary>
|
||||
public virtual void OnDrop(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Drop, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a PointerDown event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.PointerDown, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a PointerUp event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.PointerUp, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a Click event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.PointerClick, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a Select event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnSelect(BaseEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Select, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a new object is being selected.
|
||||
/// </summary>
|
||||
public virtual void OnDeselect(BaseEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Deselect, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a new Scroll event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnScroll(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Scroll, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a Move event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnMove(AxisEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Move, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when the object associated with this EventTrigger is updated.
|
||||
/// </summary>
|
||||
public virtual void OnUpdateSelected(BaseEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.UpdateSelected, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a drag has been found, but before it is valid to begin the drag.
|
||||
/// </summary>
|
||||
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.InitializePotentialDrag, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a drag is started.
|
||||
/// </summary>
|
||||
public virtual void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.BeginDrag, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem once dragging ends.
|
||||
/// </summary>
|
||||
public virtual void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.EndDrag, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a Submit event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnSubmit(BaseEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Submit, eventData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the EventSystem when a Cancel event occurs.
|
||||
/// </summary>
|
||||
public virtual void OnCancel(BaseEventData eventData)
|
||||
{
|
||||
Execute(EventTriggerType.Cancel, eventData);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0b148fe25e99eb48b9724523833bab1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,96 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is capable of triggering one or more remote functions from a specified event.
|
||||
/// Usage: Attach it to an object with a collider, or to a GUI Graphic of your choice.
|
||||
/// NOTE: Doing this will make this object intercept ALL events, and no event bubbling will occur from this object!
|
||||
/// </summary>
|
||||
|
||||
public enum EventTriggerType
|
||||
{
|
||||
/// <summary>
|
||||
/// Intercepts a IPointerEnterHandler.OnPointerEnter.
|
||||
/// </summary>
|
||||
PointerEnter = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IPointerExitHandler.OnPointerExit.
|
||||
/// </summary>
|
||||
PointerExit = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IPointerDownHandler.OnPointerDown.
|
||||
/// </summary>
|
||||
PointerDown = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IPointerUpHandler.OnPointerUp.
|
||||
/// </summary>
|
||||
PointerUp = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IPointerClickHandler.OnPointerClick.
|
||||
/// </summary>
|
||||
PointerClick = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IDragHandler.OnDrag.
|
||||
/// </summary>
|
||||
Drag = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IDropHandler.OnDrop.
|
||||
/// </summary>
|
||||
Drop = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IScrollHandler.OnScroll.
|
||||
/// </summary>
|
||||
Scroll = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IUpdateSelectedHandler.OnUpdateSelected.
|
||||
/// </summary>
|
||||
UpdateSelected = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a ISelectHandler.OnSelect.
|
||||
/// </summary>
|
||||
Select = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IDeselectHandler.OnDeselect.
|
||||
/// </summary>
|
||||
Deselect = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts a IMoveHandler.OnMove.
|
||||
/// </summary>
|
||||
Move = 11,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts IInitializePotentialDrag.InitializePotentialDrag.
|
||||
/// </summary>
|
||||
InitializePotentialDrag = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts IBeginDragHandler.OnBeginDrag.</
|
||||
/// </summary>
|
||||
BeginDrag = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts IEndDragHandler.OnEndDrag.
|
||||
/// </summary>
|
||||
EndDrag = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts ISubmitHandler.Submit.
|
||||
/// </summary>
|
||||
Submit = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Intercepts ICancelHandler.OnCancel.
|
||||
/// </summary>
|
||||
Cancel = 16
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3fa274f26b1574c40b949e114327022e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,360 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
public static class ExecuteEvents
|
||||
{
|
||||
public delegate void EventFunction<T1>(T1 handler, BaseEventData eventData);
|
||||
|
||||
public static T ValidateEventData<T>(BaseEventData data) where T : class
|
||||
{
|
||||
if ((data as T) == null)
|
||||
throw new ArgumentException(String.Format("Invalid type: {0} passed to event expecting {1}", data.GetType(), typeof(T)));
|
||||
return data as T;
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IPointerEnterHandler> s_PointerEnterHandler = Execute;
|
||||
|
||||
private static void Execute(IPointerEnterHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnPointerEnter(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IPointerExitHandler> s_PointerExitHandler = Execute;
|
||||
|
||||
private static void Execute(IPointerExitHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnPointerExit(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IPointerDownHandler> s_PointerDownHandler = Execute;
|
||||
|
||||
private static void Execute(IPointerDownHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnPointerDown(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IPointerUpHandler> s_PointerUpHandler = Execute;
|
||||
|
||||
private static void Execute(IPointerUpHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnPointerUp(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IPointerClickHandler> s_PointerClickHandler = Execute;
|
||||
|
||||
private static void Execute(IPointerClickHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnPointerClick(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IInitializePotentialDragHandler> s_InitializePotentialDragHandler = Execute;
|
||||
|
||||
private static void Execute(IInitializePotentialDragHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnInitializePotentialDrag(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IBeginDragHandler> s_BeginDragHandler = Execute;
|
||||
|
||||
private static void Execute(IBeginDragHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnBeginDrag(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IDragHandler> s_DragHandler = Execute;
|
||||
|
||||
private static void Execute(IDragHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnDrag(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IEndDragHandler> s_EndDragHandler = Execute;
|
||||
|
||||
private static void Execute(IEndDragHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnEndDrag(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IDropHandler> s_DropHandler = Execute;
|
||||
|
||||
private static void Execute(IDropHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnDrop(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IScrollHandler> s_ScrollHandler = Execute;
|
||||
|
||||
private static void Execute(IScrollHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnScroll(ValidateEventData<PointerEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IUpdateSelectedHandler> s_UpdateSelectedHandler = Execute;
|
||||
|
||||
private static void Execute(IUpdateSelectedHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnUpdateSelected(eventData);
|
||||
}
|
||||
|
||||
private static readonly EventFunction<ISelectHandler> s_SelectHandler = Execute;
|
||||
|
||||
private static void Execute(ISelectHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnSelect(eventData);
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IDeselectHandler> s_DeselectHandler = Execute;
|
||||
|
||||
private static void Execute(IDeselectHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnDeselect(eventData);
|
||||
}
|
||||
|
||||
private static readonly EventFunction<IMoveHandler> s_MoveHandler = Execute;
|
||||
|
||||
private static void Execute(IMoveHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnMove(ValidateEventData<AxisEventData>(eventData));
|
||||
}
|
||||
|
||||
private static readonly EventFunction<ISubmitHandler> s_SubmitHandler = Execute;
|
||||
|
||||
private static void Execute(ISubmitHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnSubmit(eventData);
|
||||
}
|
||||
|
||||
private static readonly EventFunction<ICancelHandler> s_CancelHandler = Execute;
|
||||
|
||||
private static void Execute(ICancelHandler handler, BaseEventData eventData)
|
||||
{
|
||||
handler.OnCancel(eventData);
|
||||
}
|
||||
|
||||
public static EventFunction<IPointerEnterHandler> pointerEnterHandler
|
||||
{
|
||||
get { return s_PointerEnterHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IPointerExitHandler> pointerExitHandler
|
||||
{
|
||||
get { return s_PointerExitHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IPointerDownHandler> pointerDownHandler
|
||||
{
|
||||
get { return s_PointerDownHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IPointerUpHandler> pointerUpHandler
|
||||
{
|
||||
get { return s_PointerUpHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IPointerClickHandler> pointerClickHandler
|
||||
{
|
||||
get { return s_PointerClickHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IInitializePotentialDragHandler> initializePotentialDrag
|
||||
{
|
||||
get { return s_InitializePotentialDragHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IBeginDragHandler> beginDragHandler
|
||||
{
|
||||
get { return s_BeginDragHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IDragHandler> dragHandler
|
||||
{
|
||||
get { return s_DragHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IEndDragHandler> endDragHandler
|
||||
{
|
||||
get { return s_EndDragHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IDropHandler> dropHandler
|
||||
{
|
||||
get { return s_DropHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IScrollHandler> scrollHandler
|
||||
{
|
||||
get { return s_ScrollHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IUpdateSelectedHandler> updateSelectedHandler
|
||||
{
|
||||
get { return s_UpdateSelectedHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<ISelectHandler> selectHandler
|
||||
{
|
||||
get { return s_SelectHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IDeselectHandler> deselectHandler
|
||||
{
|
||||
get { return s_DeselectHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<IMoveHandler> moveHandler
|
||||
{
|
||||
get { return s_MoveHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<ISubmitHandler> submitHandler
|
||||
{
|
||||
get { return s_SubmitHandler; }
|
||||
}
|
||||
|
||||
public static EventFunction<ICancelHandler> cancelHandler
|
||||
{
|
||||
get { return s_CancelHandler; }
|
||||
}
|
||||
|
||||
private static void GetEventChain(GameObject root, IList<Transform> eventChain)
|
||||
{
|
||||
eventChain.Clear();
|
||||
if (root == null)
|
||||
return;
|
||||
|
||||
var t = root.transform;
|
||||
while (t != null)
|
||||
{
|
||||
eventChain.Add(t);
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ObjectPool<List<IEventSystemHandler>> s_HandlerListPool = new ObjectPool<List<IEventSystemHandler>>(null, l => l.Clear());
|
||||
|
||||
public static bool Execute<T>(GameObject target, BaseEventData eventData, EventFunction<T> functor) where T : IEventSystemHandler
|
||||
{
|
||||
var internalHandlers = s_HandlerListPool.Get();
|
||||
GetEventList<T>(target, internalHandlers);
|
||||
// if (s_InternalHandlers.Count > 0)
|
||||
// Debug.Log("Executinng " + typeof (T) + " on " + target);
|
||||
|
||||
for (var i = 0; i < internalHandlers.Count; i++)
|
||||
{
|
||||
T arg;
|
||||
try
|
||||
{
|
||||
arg = (T)internalHandlers[i];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var temp = internalHandlers[i];
|
||||
Debug.LogException(new Exception(string.Format("Type {0} expected {1} received.", typeof(T).Name, temp.GetType().Name), e));
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
functor(arg, eventData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
var handlerCount = internalHandlers.Count;
|
||||
s_HandlerListPool.Release(internalHandlers);
|
||||
return handlerCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the specified event on the first game object underneath the current touch.
|
||||
/// </summary>
|
||||
private static readonly List<Transform> s_InternalTransformList = new List<Transform>(30);
|
||||
|
||||
public static GameObject ExecuteHierarchy<T>(GameObject root, BaseEventData eventData, EventFunction<T> callbackFunction) where T : IEventSystemHandler
|
||||
{
|
||||
GetEventChain(root, s_InternalTransformList);
|
||||
|
||||
for (var i = 0; i < s_InternalTransformList.Count; i++)
|
||||
{
|
||||
var transform = s_InternalTransformList[i];
|
||||
if (Execute(transform.gameObject, eventData, callbackFunction))
|
||||
return transform.gameObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool ShouldSendToComponent<T>(Component component) where T : IEventSystemHandler
|
||||
{
|
||||
var valid = component is T;
|
||||
if (!valid)
|
||||
return false;
|
||||
|
||||
var behaviour = component as Behaviour;
|
||||
if (behaviour != null)
|
||||
return behaviour.isActiveAndEnabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the specified object's event event.
|
||||
/// </summary>
|
||||
private static void GetEventList<T>(GameObject go, IList<IEventSystemHandler> results) where T : IEventSystemHandler
|
||||
{
|
||||
// Debug.LogWarning("GetEventList<" + typeof(T).Name + ">");
|
||||
if (results == null)
|
||||
throw new ArgumentException("Results array is null", "results");
|
||||
|
||||
if (go == null || !go.activeInHierarchy)
|
||||
return;
|
||||
|
||||
var components = ListPool<Component>.Get();
|
||||
go.GetComponents(components);
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
if (!ShouldSendToComponent<T>(components[i]))
|
||||
continue;
|
||||
|
||||
// Debug.Log(string.Format("{2} found! On {0}.{1}", go, s_GetComponentsScratch[i].GetType(), typeof(T)));
|
||||
results.Add(components[i] as IEventSystemHandler);
|
||||
}
|
||||
ListPool<Component>.Release(components);
|
||||
// Debug.LogWarning("end GetEventList<" + typeof(T).Name + ">");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the specified game object will be able to handle the specified event.
|
||||
/// </summary>
|
||||
public static bool CanHandleEvent<T>(GameObject go) where T : IEventSystemHandler
|
||||
{
|
||||
var internalHandlers = s_HandlerListPool.Get();
|
||||
GetEventList<T>(go, internalHandlers);
|
||||
var handlerCount = internalHandlers.Count;
|
||||
s_HandlerListPool.Release(internalHandlers);
|
||||
return handlerCount != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bubble the specified event on the game object, figuring out which object will actually receive the event.
|
||||
/// </summary>
|
||||
public static GameObject GetEventHandler<T>(GameObject root) where T : IEventSystemHandler
|
||||
{
|
||||
if (root == null)
|
||||
return null;
|
||||
|
||||
Transform t = root.transform;
|
||||
while (t != null)
|
||||
{
|
||||
if (CanHandleEvent<T>(t.gameObject))
|
||||
return t.gameObject;
|
||||
t = t.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 623c79a1e113b4941afdbfc88d19e8fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8e78f8a8575e4a04f8337a54e241cdc5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,129 @@
|
|||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to the Input system used by the BaseInputModule. With this it is possible to bypass the Input system with your own but still use the same InputModule. For example this can be used to feed fake input into the UI or interface with a different input system.
|
||||
/// </summary>
|
||||
public class BaseInput : UIBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface to Input.compositionString. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual string compositionString
|
||||
{
|
||||
get { return Input.compositionString; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.imeCompositionMode. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual IMECompositionMode imeCompositionMode
|
||||
{
|
||||
get { return Input.imeCompositionMode; }
|
||||
set { Input.imeCompositionMode = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.compositionCursorPos. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual Vector2 compositionCursorPos
|
||||
{
|
||||
get { return Input.compositionCursorPos; }
|
||||
set { Input.compositionCursorPos = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.mousePresent. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual bool mousePresent
|
||||
{
|
||||
get { return Input.mousePresent; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetMouseButtonDown. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
/// <param name="button"></param>
|
||||
/// <returns></returns>
|
||||
public virtual bool GetMouseButtonDown(int button)
|
||||
{
|
||||
return Input.GetMouseButtonDown(button);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetMouseButtonUp. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual bool GetMouseButtonUp(int button)
|
||||
{
|
||||
return Input.GetMouseButtonUp(button);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetMouseButton. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual bool GetMouseButton(int button)
|
||||
{
|
||||
return Input.GetMouseButton(button);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.mousePosition. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual Vector2 mousePosition
|
||||
{
|
||||
get { return MultipleDisplayUtilities.GetMousePositionRelativeToMainDisplayResolution(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.mouseScrollDelta. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual Vector2 mouseScrollDelta
|
||||
{
|
||||
get { return Input.mouseScrollDelta; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.touchSupported. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual bool touchSupported
|
||||
{
|
||||
get { return Input.touchSupported; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.touchCount. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
public virtual int touchCount
|
||||
{
|
||||
get { return Input.touchCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetTouch. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
/// <param name="index">Touch index to get</param>
|
||||
public virtual Touch GetTouch(int index)
|
||||
{
|
||||
return Input.GetTouch(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetAxisRaw. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
/// <param name="axisName">Axis name to check</param>
|
||||
public virtual float GetAxisRaw(string axisName)
|
||||
{
|
||||
return Input.GetAxisRaw(axisName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface to Input.GetButtonDown. Can be overridden to provide custom input instead of using the Input class.
|
||||
/// </summary>
|
||||
/// <param name="buttonName">Button name to get</param>
|
||||
public virtual bool GetButtonDown(string buttonName)
|
||||
{
|
||||
return Input.GetButtonDown(buttonName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1511ccae7919cfc46b603b9b337fdc94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,327 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[RequireComponent(typeof(EventSystem))]
|
||||
/// <summary>
|
||||
/// A base module that raises events and sends them to GameObjects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An Input Module is a component of the EventSystem that is responsible for raising events and sending them to GameObjects for handling. The BaseInputModule is a class that all Input Modules in the EventSystem inherit from. Examples of provided modules are TouchInputModule and StandaloneInputModule, if these are inadequate for your project you can create your own by extending from the BaseInputModule.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// /**
|
||||
/// * Create a module that every tick sends a 'Move' event to
|
||||
/// * the target object
|
||||
/// */
|
||||
/// public class MyInputModule : BaseInputModule
|
||||
/// {
|
||||
/// public GameObject m_TargetObject;
|
||||
///
|
||||
/// public override void Process()
|
||||
/// {
|
||||
/// if (m_TargetObject == null)
|
||||
/// return;
|
||||
/// ExecuteEvents.Execute (m_TargetObject, new BaseEventData (eventSystem), ExecuteEvents.moveHandler);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public abstract class BaseInputModule : UIBehaviour
|
||||
{
|
||||
[NonSerialized]
|
||||
protected List<RaycastResult> m_RaycastResultCache = new List<RaycastResult>();
|
||||
|
||||
private AxisEventData m_AxisEventData;
|
||||
|
||||
private EventSystem m_EventSystem;
|
||||
private BaseEventData m_BaseEventData;
|
||||
|
||||
protected BaseInput m_InputOverride;
|
||||
private BaseInput m_DefaultInput;
|
||||
|
||||
/// <summary>
|
||||
/// The current BaseInput being used by the input module.
|
||||
/// </summary>
|
||||
public BaseInput input
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_InputOverride != null)
|
||||
return m_InputOverride;
|
||||
|
||||
if (m_DefaultInput == null)
|
||||
{
|
||||
var inputs = GetComponents<BaseInput>();
|
||||
foreach (var baseInput in inputs)
|
||||
{
|
||||
// We dont want to use any classes that derrive from BaseInput for default.
|
||||
if (baseInput != null && baseInput.GetType() == typeof(BaseInput))
|
||||
{
|
||||
m_DefaultInput = baseInput;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_DefaultInput == null)
|
||||
m_DefaultInput = gameObject.AddComponent<BaseInput>();
|
||||
}
|
||||
|
||||
return m_DefaultInput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to override the default BaseInput for the input module.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this it is possible to bypass the Input system with your own but still use the same InputModule. For example this can be used to feed fake input into the UI or interface with a different input system.
|
||||
/// </remarks>
|
||||
public BaseInput inputOverride
|
||||
{
|
||||
get { return m_InputOverride; }
|
||||
set { m_InputOverride = value; }
|
||||
}
|
||||
|
||||
protected EventSystem eventSystem
|
||||
{
|
||||
get { return m_EventSystem; }
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
m_EventSystem = GetComponent<EventSystem>();
|
||||
m_EventSystem.UpdateModules();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
m_EventSystem.UpdateModules();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the current tick for the module.
|
||||
/// </summary>
|
||||
public abstract void Process();
|
||||
|
||||
/// <summary>
|
||||
/// Return the first valid RaycastResult.
|
||||
/// </summary>
|
||||
protected static RaycastResult FindFirstRaycast(List<RaycastResult> candidates)
|
||||
{
|
||||
for (var i = 0; i < candidates.Count; ++i)
|
||||
{
|
||||
if (candidates[i].gameObject == null)
|
||||
continue;
|
||||
|
||||
return candidates[i];
|
||||
}
|
||||
return new RaycastResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given an input movement, determine the best MoveDirection.
|
||||
/// </summary>
|
||||
/// <param name="x">X movement.</param>
|
||||
/// <param name="y">Y movement.</param>
|
||||
protected static MoveDirection DetermineMoveDirection(float x, float y)
|
||||
{
|
||||
return DetermineMoveDirection(x, y, 0.6f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given an input movement, determine the best MoveDirection.
|
||||
/// </summary>
|
||||
/// <param name="x">X movement.</param>
|
||||
/// <param name="y">Y movement.</param>
|
||||
/// <param name="deadZone">Dead zone.</param>
|
||||
protected static MoveDirection DetermineMoveDirection(float x, float y, float deadZone)
|
||||
{
|
||||
// if vector is too small... just return
|
||||
if (new Vector2(x, y).sqrMagnitude < deadZone * deadZone)
|
||||
return MoveDirection.None;
|
||||
|
||||
if (Mathf.Abs(x) > Mathf.Abs(y))
|
||||
{
|
||||
if (x > 0)
|
||||
return MoveDirection.Right;
|
||||
return MoveDirection.Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y > 0)
|
||||
return MoveDirection.Up;
|
||||
return MoveDirection.Down;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given 2 GameObjects, return a common root GameObject (or null).
|
||||
/// </summary>
|
||||
/// <param name="g1">GameObject to compare</param>
|
||||
/// <param name="g2">GameObject to compare</param>
|
||||
/// <returns></returns>
|
||||
protected static GameObject FindCommonRoot(GameObject g1, GameObject g2)
|
||||
{
|
||||
if (g1 == null || g2 == null)
|
||||
return null;
|
||||
|
||||
var t1 = g1.transform;
|
||||
while (t1 != null)
|
||||
{
|
||||
var t2 = g2.transform;
|
||||
while (t2 != null)
|
||||
{
|
||||
if (t1 == t2)
|
||||
return t1.gameObject;
|
||||
t2 = t2.parent;
|
||||
}
|
||||
t1 = t1.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// walk up the tree till a common root between the last entered and the current entered is foung
|
||||
// send exit events up to (but not inluding) the common root. Then send enter events up to
|
||||
// (but not including the common root).
|
||||
protected void HandlePointerExitAndEnter(PointerEventData currentPointerData, GameObject newEnterTarget)
|
||||
{
|
||||
// if we have no target / pointerEnter has been deleted
|
||||
// just send exit events to anything we are tracking
|
||||
// then exit
|
||||
if (newEnterTarget == null || currentPointerData.pointerEnter == null)
|
||||
{
|
||||
for (var i = 0; i < currentPointerData.hovered.Count; ++i)
|
||||
ExecuteEvents.Execute(currentPointerData.hovered[i], currentPointerData, ExecuteEvents.pointerExitHandler);
|
||||
|
||||
currentPointerData.hovered.Clear();
|
||||
|
||||
if (newEnterTarget == null)
|
||||
{
|
||||
currentPointerData.pointerEnter = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have not changed hover target
|
||||
if (currentPointerData.pointerEnter == newEnterTarget && newEnterTarget)
|
||||
return;
|
||||
|
||||
GameObject commonRoot = FindCommonRoot(currentPointerData.pointerEnter, newEnterTarget);
|
||||
|
||||
// and we already an entered object from last time
|
||||
if (currentPointerData.pointerEnter != null)
|
||||
{
|
||||
// send exit handler call to all elements in the chain
|
||||
// until we reach the new target, or null!
|
||||
Transform t = currentPointerData.pointerEnter.transform;
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
// if we reach the common root break out!
|
||||
if (commonRoot != null && commonRoot.transform == t)
|
||||
break;
|
||||
|
||||
ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerExitHandler);
|
||||
currentPointerData.hovered.Remove(t.gameObject);
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
|
||||
// now issue the enter call up to but not including the common root
|
||||
currentPointerData.pointerEnter = newEnterTarget;
|
||||
if (newEnterTarget != null)
|
||||
{
|
||||
Transform t = newEnterTarget.transform;
|
||||
|
||||
while (t != null && t.gameObject != commonRoot)
|
||||
{
|
||||
ExecuteEvents.Execute(t.gameObject, currentPointerData, ExecuteEvents.pointerEnterHandler);
|
||||
currentPointerData.hovered.Add(t.gameObject);
|
||||
t = t.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given some input data generate an AxisEventData that can be used by the event system.
|
||||
/// </summary>
|
||||
/// <param name="x">X movement.</param>
|
||||
/// <param name="y">Y movement.</param>
|
||||
/// <param name="deadZone">Dead zone.</param>
|
||||
protected virtual AxisEventData GetAxisEventData(float x, float y, float moveDeadZone)
|
||||
{
|
||||
if (m_AxisEventData == null)
|
||||
m_AxisEventData = new AxisEventData(eventSystem);
|
||||
|
||||
m_AxisEventData.Reset();
|
||||
m_AxisEventData.moveVector = new Vector2(x, y);
|
||||
m_AxisEventData.moveDir = DetermineMoveDirection(x, y, moveDeadZone);
|
||||
return m_AxisEventData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a BaseEventData that can be used by the EventSystem.
|
||||
/// </summary>
|
||||
protected virtual BaseEventData GetBaseEventData()
|
||||
{
|
||||
if (m_BaseEventData == null)
|
||||
m_BaseEventData = new BaseEventData(eventSystem);
|
||||
|
||||
m_BaseEventData.Reset();
|
||||
return m_BaseEventData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the module is pointer based, then override this to return true if the pointer is over an event system object.
|
||||
/// </summary>
|
||||
/// <param name="pointerId">Pointer ID</param>
|
||||
/// <returns>Is the given pointer over an event system object?</returns>
|
||||
public virtual bool IsPointerOverGameObject(int pointerId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should the module be activated.
|
||||
/// </summary>
|
||||
public virtual bool ShouldActivateModule()
|
||||
{
|
||||
return enabled && gameObject.activeInHierarchy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the module is deactivated. Override this if you want custom code to execute when you deactivate your module.
|
||||
/// </summary>
|
||||
public virtual void DeactivateModule()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the module is activated. Override this if you want custom code to execute when you activate your module.
|
||||
/// </summary>
|
||||
public virtual void ActivateModule()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Update the internal state of the Module.
|
||||
/// </summary>
|
||||
public virtual void UpdateModule()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if the module is supported. Override this if you have a platform specific module (eg. TouchInputModule that you do not want to activate on standalone.)
|
||||
/// </summary>
|
||||
/// <returns>Is the module supported.</returns>
|
||||
public virtual bool IsModuleSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1ea10891dd782154ca0fb67bce9e6f72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,415 @@
|
|||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
for (int i = 0; i < m_TrackedButtons.Count; i++)
|
||||
{
|
||||
if (m_TrackedButtons[i].eventData.PressedThisFrame())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool AnyReleasesThisFrame()
|
||||
{
|
||||
for (int i = 0; i < m_TrackedButtons.Count; i++)
|
||||
{
|
||||
if (m_TrackedButtons[i].eventData.ReleasedThisFrame())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ButtonState GetButtonState(PointerEventData.InputButton button)
|
||||
{
|
||||
ButtonState tracked = null;
|
||||
for (int i = 0; i < m_TrackedButtons.Count; 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);
|
||||
CopyFromTo(leftData, rightData);
|
||||
rightData.button = PointerEventData.InputButton.Right;
|
||||
|
||||
PointerEventData middleData;
|
||||
GetPointerData(kMouseMiddleId, out middleData, true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cbab8835092323a4389f2dc7d8f6c781
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,654 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[AddComponentMenu("Event/Standalone Input Module")]
|
||||
/// <summary>
|
||||
/// A BaseInputModule designed for mouse / keyboard / controller input.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Input module for working with, mouse, keyboard, or controller.
|
||||
/// </remarks>
|
||||
public class StandaloneInputModule : PointerInputModule
|
||||
{
|
||||
private float m_PrevActionTime;
|
||||
private Vector2 m_LastMoveVector;
|
||||
private int m_ConsecutiveMoveCount = 0;
|
||||
|
||||
private Vector2 m_LastMousePosition;
|
||||
private Vector2 m_MousePosition;
|
||||
|
||||
private GameObject m_CurrentFocusedGameObject;
|
||||
|
||||
private PointerEventData m_InputPointerEvent;
|
||||
|
||||
protected StandaloneInputModule()
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
|
||||
public enum InputMode
|
||||
{
|
||||
Mouse,
|
||||
Buttons
|
||||
}
|
||||
|
||||
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
|
||||
public InputMode inputMode
|
||||
{
|
||||
get { return InputMode.Mouse; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string m_HorizontalAxis = "Horizontal";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the vertical axis for movement (if axis events are used).
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private string m_VerticalAxis = "Vertical";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the submit button.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private string m_SubmitButton = "Submit";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the submit button.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private string m_CancelButton = "Cancel";
|
||||
|
||||
[SerializeField]
|
||||
private float m_InputActionsPerSecond = 10;
|
||||
|
||||
[SerializeField]
|
||||
private float m_RepeatDelay = 0.5f;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("m_AllowActivationOnMobileDevice")]
|
||||
private bool m_ForceModuleActive;
|
||||
|
||||
[Obsolete("allowActivationOnMobileDevice has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")]
|
||||
public bool allowActivationOnMobileDevice
|
||||
{
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Force this module to be active.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If there is no module active with higher priority (ordered in the inspector) this module will be forced active even if valid enabling conditions are not met.
|
||||
/// </remarks>
|
||||
public bool forceModuleActive
|
||||
{
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of keyboard / controller inputs allowed per second.
|
||||
/// </summary>
|
||||
public float inputActionsPerSecond
|
||||
{
|
||||
get { return m_InputActionsPerSecond; }
|
||||
set { m_InputActionsPerSecond = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delay in seconds before the input actions per second repeat rate takes effect.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the same direction is sustained, the inputActionsPerSecond property can be used to control the rate at which events are fired. However, it can be desirable that the first repetition is delayed, so the user doesn't get repeated actions by accident.
|
||||
/// </remarks>
|
||||
public float repeatDelay
|
||||
{
|
||||
get { return m_RepeatDelay; }
|
||||
set { m_RepeatDelay = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the horizontal axis for movement (if axis events are used).
|
||||
/// </summary>
|
||||
public string horizontalAxis
|
||||
{
|
||||
get { return m_HorizontalAxis; }
|
||||
set { m_HorizontalAxis = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the vertical axis for movement (if axis events are used).
|
||||
/// </summary>
|
||||
public string verticalAxis
|
||||
{
|
||||
get { return m_VerticalAxis; }
|
||||
set { m_VerticalAxis = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of input events handled per second.
|
||||
/// </summary>
|
||||
public string submitButton
|
||||
{
|
||||
get { return m_SubmitButton; }
|
||||
set { m_SubmitButton = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Input manager name for the 'cancel' button.
|
||||
/// </summary>
|
||||
public string cancelButton
|
||||
{
|
||||
get { return m_CancelButton; }
|
||||
set { m_CancelButton = value; }
|
||||
}
|
||||
|
||||
private bool ShouldIgnoreEventsOnNoFocus()
|
||||
{
|
||||
switch (SystemInfo.operatingSystemFamily)
|
||||
{
|
||||
case OperatingSystemFamily.Windows:
|
||||
case OperatingSystemFamily.Linux:
|
||||
case OperatingSystemFamily.MacOSX:
|
||||
#if UNITY_EDITOR
|
||||
if (UnityEditor.EditorApplication.isRemoteConnected)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateModule()
|
||||
{
|
||||
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
|
||||
{
|
||||
if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
|
||||
{
|
||||
ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject);
|
||||
}
|
||||
|
||||
m_InputPointerEvent = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastMousePosition = m_MousePosition;
|
||||
m_MousePosition = input.mousePosition;
|
||||
}
|
||||
|
||||
private void ReleaseMouse(PointerEventData pointerEvent, GameObject currentOverGo)
|
||||
{
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
|
||||
|
||||
var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// PointerClick and Drop events
|
||||
if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
|
||||
{
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
|
||||
}
|
||||
else if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
{
|
||||
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
|
||||
}
|
||||
|
||||
pointerEvent.eligibleForClick = false;
|
||||
pointerEvent.pointerPress = null;
|
||||
pointerEvent.rawPointerPress = null;
|
||||
|
||||
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
// redo pointer enter / exit to refresh state
|
||||
// so that if we moused over something that ignored it before
|
||||
// due to having pressed on something else
|
||||
// it now gets it.
|
||||
if (currentOverGo != pointerEvent.pointerEnter)
|
||||
{
|
||||
HandlePointerExitAndEnter(pointerEvent, null);
|
||||
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
|
||||
}
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
|
||||
public override bool IsModuleSupported()
|
||||
{
|
||||
return m_ForceModuleActive || input.mousePresent || input.touchSupported;
|
||||
}
|
||||
|
||||
public override bool ShouldActivateModule()
|
||||
{
|
||||
if (!base.ShouldActivateModule())
|
||||
return false;
|
||||
|
||||
var shouldActivate = m_ForceModuleActive;
|
||||
shouldActivate |= input.GetButtonDown(m_SubmitButton);
|
||||
shouldActivate |= input.GetButtonDown(m_CancelButton);
|
||||
shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_HorizontalAxis), 0.0f);
|
||||
shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_VerticalAxis), 0.0f);
|
||||
shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
|
||||
shouldActivate |= input.GetMouseButtonDown(0);
|
||||
|
||||
if (input.touchCount > 0)
|
||||
shouldActivate = true;
|
||||
|
||||
return shouldActivate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See BaseInputModule.
|
||||
/// </summary>
|
||||
public override void ActivateModule()
|
||||
{
|
||||
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
|
||||
return;
|
||||
|
||||
base.ActivateModule();
|
||||
m_MousePosition = input.mousePosition;
|
||||
m_LastMousePosition = input.mousePosition;
|
||||
|
||||
var toSelect = eventSystem.currentSelectedGameObject;
|
||||
if (toSelect == null)
|
||||
toSelect = eventSystem.firstSelectedGameObject;
|
||||
|
||||
eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See BaseInputModule.
|
||||
/// </summary>
|
||||
public override void DeactivateModule()
|
||||
{
|
||||
base.DeactivateModule();
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus())
|
||||
return;
|
||||
|
||||
bool usedEvent = SendUpdateEventToSelectedObject();
|
||||
|
||||
// case 1004066 - touch / mouse events should be processed before navigation events in case
|
||||
// they change the current selected gameobject and the submit button is a touch / mouse button.
|
||||
|
||||
// touch needs to take precedence because of the mouse emulation layer
|
||||
if (!ProcessTouchEvents() && input.mousePresent)
|
||||
ProcessMouseEvent();
|
||||
|
||||
if (eventSystem.sendNavigationEvents)
|
||||
{
|
||||
if (!usedEvent)
|
||||
usedEvent |= SendMoveEventToSelectedObject();
|
||||
|
||||
if (!usedEvent)
|
||||
SendSubmitEventToSelectedObject();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ProcessTouchEvents()
|
||||
{
|
||||
for (int i = 0; i < input.touchCount; ++i)
|
||||
{
|
||||
Touch touch = input.GetTouch(i);
|
||||
|
||||
if (touch.type == TouchType.Indirect)
|
||||
continue;
|
||||
|
||||
bool released;
|
||||
bool pressed;
|
||||
var pointer = GetTouchPointerEventData(touch, out pressed, out released);
|
||||
|
||||
ProcessTouchPress(pointer, pressed, released);
|
||||
|
||||
if (!released)
|
||||
{
|
||||
ProcessMove(pointer);
|
||||
ProcessDrag(pointer);
|
||||
}
|
||||
else
|
||||
RemovePointerData(pointer);
|
||||
}
|
||||
return input.touchCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called by Unity whenever a touch event is processed. Override this method with a custom implementation to process touch events yourself.
|
||||
/// </summary>
|
||||
/// <param name="pointerEvent">Event data relating to the touch event, such as position and ID to be passed to the touch event destination object.</param>
|
||||
/// <param name="pressed">This is true for the first frame of a touch event, and false thereafter. This can therefore be used to determine the instant a touch event occurred.</param>
|
||||
/// <param name="released">This is true only for the last frame of a touch event.</param>
|
||||
/// <remarks>
|
||||
/// This method can be overridden in derived classes to change how touch press events are handled.
|
||||
/// </remarks>
|
||||
protected void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released)
|
||||
{
|
||||
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// PointerDown notification
|
||||
if (pressed)
|
||||
{
|
||||
pointerEvent.eligibleForClick = true;
|
||||
pointerEvent.delta = Vector2.zero;
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.useDragThreshold = true;
|
||||
pointerEvent.pressPosition = pointerEvent.position;
|
||||
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
|
||||
|
||||
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
|
||||
|
||||
if (pointerEvent.pointerEnter != currentOverGo)
|
||||
{
|
||||
// send a pointer enter to the touched element if it isn't the one to select...
|
||||
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
|
||||
pointerEvent.pointerEnter = currentOverGo;
|
||||
}
|
||||
|
||||
// search for the control that will receive the press
|
||||
// if we can't find a press handler set the press
|
||||
// handler to be what would receive a click.
|
||||
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
|
||||
|
||||
// didnt find a press handler... search for a click handler
|
||||
if (newPressed == null)
|
||||
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// Debug.Log("Pressed: " + newPressed);
|
||||
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
if (newPressed == pointerEvent.lastPress)
|
||||
{
|
||||
var diffTime = time - pointerEvent.clickTime;
|
||||
if (diffTime < 0.3f)
|
||||
++pointerEvent.clickCount;
|
||||
else
|
||||
pointerEvent.clickCount = 1;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
pointerEvent.clickCount = 1;
|
||||
}
|
||||
|
||||
pointerEvent.pointerPress = newPressed;
|
||||
pointerEvent.rawPointerPress = currentOverGo;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
|
||||
// Save the drag handler as well
|
||||
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
|
||||
|
||||
if (pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
|
||||
// PointerUp notification
|
||||
if (released)
|
||||
{
|
||||
// Debug.Log("Executing pressup on: " + pointer.pointerPress);
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
|
||||
|
||||
// Debug.Log("KeyCode: " + pointer.eventData.keyCode);
|
||||
|
||||
// see if we mouse up on the same element that we clicked on...
|
||||
var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// PointerClick and Drop events
|
||||
if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
|
||||
{
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
|
||||
}
|
||||
|
||||
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
{
|
||||
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
|
||||
}
|
||||
|
||||
pointerEvent.eligibleForClick = false;
|
||||
pointerEvent.pointerPress = null;
|
||||
pointerEvent.rawPointerPress = null;
|
||||
|
||||
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
// send exit events as we need to simulate this on touch up on touch device
|
||||
ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler);
|
||||
pointerEvent.pointerEnter = null;
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate and send a submit event to the current selected object.
|
||||
/// </summary>
|
||||
/// <returns>If the submit event was used by the selected object.</returns>
|
||||
protected bool SendSubmitEventToSelectedObject()
|
||||
{
|
||||
if (eventSystem.currentSelectedGameObject == null)
|
||||
return false;
|
||||
|
||||
var data = GetBaseEventData();
|
||||
if (input.GetButtonDown(m_SubmitButton))
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);
|
||||
|
||||
if (input.GetButtonDown(m_CancelButton))
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
|
||||
return data.used;
|
||||
}
|
||||
|
||||
private Vector2 GetRawMoveVector()
|
||||
{
|
||||
Vector2 move = Vector2.zero;
|
||||
move.x = input.GetAxisRaw(m_HorizontalAxis);
|
||||
move.y = input.GetAxisRaw(m_VerticalAxis);
|
||||
|
||||
if (input.GetButtonDown(m_HorizontalAxis))
|
||||
{
|
||||
if (move.x < 0)
|
||||
move.x = -1f;
|
||||
if (move.x > 0)
|
||||
move.x = 1f;
|
||||
}
|
||||
if (input.GetButtonDown(m_VerticalAxis))
|
||||
{
|
||||
if (move.y < 0)
|
||||
move.y = -1f;
|
||||
if (move.y > 0)
|
||||
move.y = 1f;
|
||||
}
|
||||
return move;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate and send a move event to the current selected object.
|
||||
/// </summary>
|
||||
/// <returns>If the move event was used by the selected object.</returns>
|
||||
protected bool SendMoveEventToSelectedObject()
|
||||
{
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
Vector2 movement = GetRawMoveVector();
|
||||
if (Mathf.Approximately(movement.x, 0f) && Mathf.Approximately(movement.y, 0f))
|
||||
{
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool similarDir = (Vector2.Dot(movement, m_LastMoveVector) > 0);
|
||||
|
||||
// If direction didn't change at least 90 degrees, wait for delay before allowing consequtive event.
|
||||
if (similarDir && m_ConsecutiveMoveCount == 1)
|
||||
{
|
||||
if (time <= m_PrevActionTime + m_RepeatDelay)
|
||||
return false;
|
||||
}
|
||||
// If direction changed at least 90 degree, or we already had the delay, repeat at repeat rate.
|
||||
else
|
||||
{
|
||||
if (time <= m_PrevActionTime + 1f / m_InputActionsPerSecond)
|
||||
return false;
|
||||
}
|
||||
|
||||
var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f);
|
||||
|
||||
if (axisEventData.moveDir != MoveDirection.None)
|
||||
{
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);
|
||||
if (!similarDir)
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
m_ConsecutiveMoveCount++;
|
||||
m_PrevActionTime = time;
|
||||
m_LastMoveVector = movement;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
}
|
||||
|
||||
return axisEventData.used;
|
||||
}
|
||||
|
||||
protected void ProcessMouseEvent()
|
||||
{
|
||||
ProcessMouseEvent(0);
|
||||
}
|
||||
|
||||
[Obsolete("This method is no longer checked, overriding it with return true does nothing!")]
|
||||
protected virtual bool ForceAutoSelect()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process all mouse events.
|
||||
/// </summary>
|
||||
protected void ProcessMouseEvent(int id)
|
||||
{
|
||||
var mouseData = GetMousePointerEventData(id);
|
||||
var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
|
||||
|
||||
m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// Process the first mouse button fully
|
||||
ProcessMousePress(leftButtonData);
|
||||
ProcessMove(leftButtonData.buttonData);
|
||||
ProcessDrag(leftButtonData.buttonData);
|
||||
|
||||
// Now process right / middle clicks
|
||||
ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
|
||||
ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
|
||||
ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
|
||||
ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
|
||||
|
||||
if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
|
||||
{
|
||||
var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
|
||||
ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool SendUpdateEventToSelectedObject()
|
||||
{
|
||||
if (eventSystem.currentSelectedGameObject == null)
|
||||
return false;
|
||||
|
||||
var data = GetBaseEventData();
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
|
||||
return data.used;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate and process any mouse button state changes.
|
||||
/// </summary>
|
||||
protected void ProcessMousePress(MouseButtonEventData data)
|
||||
{
|
||||
var pointerEvent = data.buttonData;
|
||||
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// PointerDown notification
|
||||
if (data.PressedThisFrame())
|
||||
{
|
||||
pointerEvent.eligibleForClick = true;
|
||||
pointerEvent.delta = Vector2.zero;
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.useDragThreshold = true;
|
||||
pointerEvent.pressPosition = pointerEvent.position;
|
||||
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
|
||||
|
||||
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
|
||||
|
||||
// search for the control that will receive the press
|
||||
// if we can't find a press handler set the press
|
||||
// handler to be what would receive a click.
|
||||
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
|
||||
|
||||
// didnt find a press handler... search for a click handler
|
||||
if (newPressed == null)
|
||||
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// Debug.Log("Pressed: " + newPressed);
|
||||
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
if (newPressed == pointerEvent.lastPress)
|
||||
{
|
||||
var diffTime = time - pointerEvent.clickTime;
|
||||
if (diffTime < 0.3f)
|
||||
++pointerEvent.clickCount;
|
||||
else
|
||||
pointerEvent.clickCount = 1;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
pointerEvent.clickCount = 1;
|
||||
}
|
||||
|
||||
pointerEvent.pointerPress = newPressed;
|
||||
pointerEvent.rawPointerPress = currentOverGo;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
|
||||
// Save the drag handler as well
|
||||
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
|
||||
|
||||
if (pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
|
||||
// PointerUp notification
|
||||
if (data.ReleasedThisFrame())
|
||||
{
|
||||
ReleaseMouse(pointerEvent, currentOverGo);
|
||||
}
|
||||
}
|
||||
|
||||
protected GameObject GetCurrentFocusedGameObject()
|
||||
{
|
||||
return m_CurrentFocusedGameObject;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4f231c4fb786f3946a6b90b886c48677
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,269 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
[Obsolete("TouchInputModule is no longer required as Touch input is now handled in StandaloneInputModule.")]
|
||||
[AddComponentMenu("Event/Touch Input Module")]
|
||||
public class TouchInputModule : PointerInputModule
|
||||
{
|
||||
protected TouchInputModule()
|
||||
{}
|
||||
|
||||
private Vector2 m_LastMousePosition;
|
||||
private Vector2 m_MousePosition;
|
||||
|
||||
private PointerEventData m_InputPointerEvent;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("m_AllowActivationOnStandalone")]
|
||||
private bool m_ForceModuleActive;
|
||||
|
||||
[Obsolete("allowActivationOnStandalone has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")]
|
||||
public bool allowActivationOnStandalone
|
||||
{
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
public bool forceModuleActive
|
||||
{
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
public override void UpdateModule()
|
||||
{
|
||||
if (!eventSystem.isFocused)
|
||||
{
|
||||
if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging)
|
||||
ExecuteEvents.Execute(m_InputPointerEvent.pointerDrag, m_InputPointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
m_InputPointerEvent = null;
|
||||
}
|
||||
|
||||
m_LastMousePosition = m_MousePosition;
|
||||
m_MousePosition = input.mousePosition;
|
||||
}
|
||||
|
||||
public override bool IsModuleSupported()
|
||||
{
|
||||
return forceModuleActive || input.touchSupported;
|
||||
}
|
||||
|
||||
public override bool ShouldActivateModule()
|
||||
{
|
||||
if (!base.ShouldActivateModule())
|
||||
return false;
|
||||
|
||||
if (m_ForceModuleActive)
|
||||
return true;
|
||||
|
||||
if (UseFakeInput())
|
||||
{
|
||||
bool wantsEnable = input.GetMouseButtonDown(0);
|
||||
|
||||
wantsEnable |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
|
||||
return wantsEnable;
|
||||
}
|
||||
|
||||
if (input.touchCount > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool UseFakeInput()
|
||||
{
|
||||
return !input.touchSupported;
|
||||
}
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
if (UseFakeInput())
|
||||
FakeTouches();
|
||||
else
|
||||
ProcessTouchEvents();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For debugging touch-based devices using the mouse.
|
||||
/// </summary>
|
||||
private void FakeTouches()
|
||||
{
|
||||
var pointerData = GetMousePointerEventData(0);
|
||||
|
||||
var leftPressData = pointerData.GetButtonState(PointerEventData.InputButton.Left).eventData;
|
||||
|
||||
// fake touches... on press clear delta
|
||||
if (leftPressData.PressedThisFrame())
|
||||
leftPressData.buttonData.delta = Vector2.zero;
|
||||
|
||||
ProcessTouchPress(leftPressData.buttonData, leftPressData.PressedThisFrame(), leftPressData.ReleasedThisFrame());
|
||||
|
||||
// only process move if we are pressed...
|
||||
if (input.GetMouseButton(0))
|
||||
{
|
||||
ProcessMove(leftPressData.buttonData);
|
||||
ProcessDrag(leftPressData.buttonData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process all touch events.
|
||||
/// </summary>
|
||||
private void ProcessTouchEvents()
|
||||
{
|
||||
for (int i = 0; i < input.touchCount; ++i)
|
||||
{
|
||||
Touch touch = input.GetTouch(i);
|
||||
|
||||
if (touch.type == TouchType.Indirect)
|
||||
continue;
|
||||
|
||||
bool released;
|
||||
bool pressed;
|
||||
var pointer = GetTouchPointerEventData(touch, out pressed, out released);
|
||||
|
||||
ProcessTouchPress(pointer, pressed, released);
|
||||
|
||||
if (!released)
|
||||
{
|
||||
ProcessMove(pointer);
|
||||
ProcessDrag(pointer);
|
||||
}
|
||||
else
|
||||
RemovePointerData(pointer);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released)
|
||||
{
|
||||
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// PointerDown notification
|
||||
if (pressed)
|
||||
{
|
||||
pointerEvent.eligibleForClick = true;
|
||||
pointerEvent.delta = Vector2.zero;
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.useDragThreshold = true;
|
||||
pointerEvent.pressPosition = pointerEvent.position;
|
||||
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
|
||||
|
||||
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
|
||||
|
||||
if (pointerEvent.pointerEnter != currentOverGo)
|
||||
{
|
||||
// send a pointer enter to the touched element if it isn't the one to select...
|
||||
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
|
||||
pointerEvent.pointerEnter = currentOverGo;
|
||||
}
|
||||
|
||||
// search for the control that will receive the press
|
||||
// if we can't find a press handler set the press
|
||||
// handler to be what would receive a click.
|
||||
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
|
||||
|
||||
// didnt find a press handler... search for a click handler
|
||||
if (newPressed == null)
|
||||
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// Debug.Log("Pressed: " + newPressed);
|
||||
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
if (newPressed == pointerEvent.lastPress)
|
||||
{
|
||||
var diffTime = time - pointerEvent.clickTime;
|
||||
if (diffTime < 0.3f)
|
||||
++pointerEvent.clickCount;
|
||||
else
|
||||
pointerEvent.clickCount = 1;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
pointerEvent.clickCount = 1;
|
||||
}
|
||||
|
||||
pointerEvent.pointerPress = newPressed;
|
||||
pointerEvent.rawPointerPress = currentOverGo;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
|
||||
// Save the drag handler as well
|
||||
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
|
||||
|
||||
if (pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
|
||||
// PointerUp notification
|
||||
if (released)
|
||||
{
|
||||
// Debug.Log("Executing pressup on: " + pointer.pointerPress);
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
|
||||
|
||||
// Debug.Log("KeyCode: " + pointer.eventData.keyCode);
|
||||
|
||||
// see if we mouse up on the same element that we clicked on...
|
||||
var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// PointerClick and Drop events
|
||||
if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
|
||||
{
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
|
||||
}
|
||||
else if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
{
|
||||
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
|
||||
}
|
||||
|
||||
pointerEvent.eligibleForClick = false;
|
||||
pointerEvent.pointerPress = null;
|
||||
pointerEvent.rawPointerPress = null;
|
||||
|
||||
if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
// send exit events as we need to simulate this on touch up on touch device
|
||||
ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler);
|
||||
pointerEvent.pointerEnter = null;
|
||||
|
||||
m_InputPointerEvent = pointerEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DeactivateModule()
|
||||
{
|
||||
base.DeactivateModule();
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(UseFakeInput() ? "Input: Faked" : "Input: Touch");
|
||||
if (UseFakeInput())
|
||||
{
|
||||
var pointerData = GetLastPointerEventData(kMouseLeftId);
|
||||
if (pointerData != null)
|
||||
sb.AppendLine(pointerData.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var pointerEventData in m_PointerData)
|
||||
sb.AppendLine(pointerEventData.ToString());
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d49b7c1bcd2e07499844da127be038d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,557 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This is an 4 direction movement enum.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// MoveDirection provides a way of switching between moving states. You must assign these states to actions, such as moving the GameObject by an up vector when in the Up state.
|
||||
/// Having states like these are easier to identify than always having to include a large amount of vectors and calculations.Instead, you define what you want the state to do in only one part, and switch to the appropriate state when it is needed.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //This is a full example of how a GameObject changes direction using MoveDirection states
|
||||
/// //Assign this script to a visible GameObject (with a Rigidbody attached) to see it in action
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_UpVector;
|
||||
/// Vector3 m_RightVector;
|
||||
/// const float speed = 5.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the y axis (for moving upwards)
|
||||
/// m_UpVector = Vector3.up;
|
||||
/// //This Vector is set to 1 in the x axis (for moving in the right direction)
|
||||
/// m_RightVector = Vector3.right;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving in an upwards direction
|
||||
/// case MoveDirection.Up:
|
||||
/// //Change the velocity so that the Rigidbody travels upwards
|
||||
/// m_Rigidbody.velocity = m_UpVector * speed;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving left
|
||||
/// case MoveDirection.Left:
|
||||
/// //This moves the Rigidbody to the left (minus right Vector)
|
||||
/// m_Rigidbody.velocity = -m_RightVector * speed;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving right
|
||||
/// case MoveDirection.Right:
|
||||
/// //This moves the Rigidbody to the right
|
||||
/// m_Rigidbody.velocity = m_RightVector * speed;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving down
|
||||
/// case MoveDirection.Down:
|
||||
/// //This moves the Rigidbody down
|
||||
/// m_Rigidbody.velocity = -m_UpVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Left button to switch the Rigidbody direction to the left
|
||||
/// if (GUI.Button(new Rect(100, 30, 150, 30), "Move Left"))
|
||||
/// {
|
||||
/// //Switch to the left direction
|
||||
/// m_MoveDirection = MoveDirection.Left;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Up button to switch the Rigidbody direction to upwards
|
||||
/// if (GUI.Button(new Rect(100, 60, 150, 30), "Move Up"))
|
||||
/// {
|
||||
/// //Switch to Up Direction
|
||||
/// m_MoveDirection = MoveDirection.Up;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Down button to switch the direction to down
|
||||
/// if (GUI.Button(new Rect(100, 90, 150, 30), "Move Down"))
|
||||
/// {
|
||||
/// //Switch to Down Direction
|
||||
/// m_MoveDirection = MoveDirection.Down;
|
||||
/// }
|
||||
///
|
||||
/// //Press the right button to switch to the right direction
|
||||
/// if (GUI.Button(new Rect(100, 120, 150, 30), "Move Right"))
|
||||
/// {
|
||||
/// //Switch to Right Direction
|
||||
/// m_MoveDirection = MoveDirection.Right;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public enum MoveDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the Left state of MoveDirection. Assign functionality for moving to the left.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use the Left state for an easily identifiable way of moving a GameObject to the left (-1 , 0 , 0). This is a state without any predefined functionality. Before using this state, you should define what your GameObject will do in code.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Assign this script to a visible GameObject (with a Rigidbody attached) to see this in action
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_RightVector;
|
||||
/// const float speed = 5.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the x axis (for moving in the right direction)
|
||||
/// m_RightVector = Vector3.right;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving left
|
||||
/// case MoveDirection.Left:
|
||||
/// //This moves the Rigidbody to the left (minus right Vector)
|
||||
/// m_Rigidbody.velocity = -m_RightVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Left button to switch the Rigidbody direction to the left
|
||||
/// if (GUI.Button(new Rect(100, 30, 150, 30), "Move Left"))
|
||||
/// {
|
||||
/// //Switch to the left direction
|
||||
/// m_MoveDirection = MoveDirection.Left;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
Left,
|
||||
|
||||
/// <summary>
|
||||
/// This is the Up state of MoveDirection. Assign functionality for moving in an upward direction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use the Up state for an easily identifiable way of moving a GameObject upwards (0 , 1 , 0). This is a state without any predefined functionality. Before using this state, you should define what your GameObject will do in code.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Attach this script to a GameObject with a Rigidbody component. Press the "Move Up" button in Game view to see it in action.
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_UpVector;
|
||||
/// const float speed = 10.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the y axis (for moving upwards)
|
||||
/// m_UpVector = Vector3.up;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving in an upwards direction
|
||||
/// case MoveDirection.Up:
|
||||
/// //Change the velocity so that the Rigidbody travels upwards
|
||||
/// m_Rigidbody.velocity = m_UpVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Up button to switch the Rigidbody direction to upwards
|
||||
/// if (GUI.Button(new Rect(100, 60, 150, 30), "Move Up"))
|
||||
/// {
|
||||
/// //Switch to Up Direction
|
||||
/// m_MoveDirection = MoveDirection.Up;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
Up,
|
||||
|
||||
/// <summary>
|
||||
/// This is the Right state of MoveDirection. Assign functionality for moving to the right.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use the Right state for an easily identifiable way of moving a GameObject to the right (1 , 0 , 0). This is a state without any predefined functionality. Before using this state, you should define what your GameObject will do in code.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Attach this script to a GameObject with a Rigidbody component. Press the "Move Right" button in Game view to see it in action.
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class MoveDirectionExample : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_RightVector;
|
||||
/// const float speed = 5.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the x axis (for moving in the right direction)
|
||||
/// m_RightVector = Vector3.right;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving right
|
||||
/// case MoveDirection.Right:
|
||||
/// //This moves the Rigidbody to the right
|
||||
/// m_Rigidbody.velocity = m_RightVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Left button to switch the Rigidbody direction to the right
|
||||
/// if (GUI.Button(new Rect(100, 30, 150, 30), "Move Right"))
|
||||
/// {
|
||||
/// //Switch to the left direction
|
||||
/// m_MoveDirection = MoveDirection.Right;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
Right,
|
||||
|
||||
/// <summary>
|
||||
/// The Down State of MoveDirection. Assign functionality for moving in a downward direction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use the Down state for an easily identifiable way of moving a GameObject downwards (0 , -1 , 0). This is a state without any predefined functionality. Before using this state, you should define what your GameObject will do in code.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Attach this script to a GameObject with a Rigidbody component. Press the "Move Down" button in Game view to see it in action.
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_UpVector;
|
||||
/// const float speed = 10.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the y axis (for moving upwards)
|
||||
/// m_UpVector = Vector3.up;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving down
|
||||
/// case MoveDirection.Down:
|
||||
/// //This moves the Rigidbody down
|
||||
/// m_Rigidbody.velocity = -m_UpVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Down button to switch the direction to down
|
||||
/// if (GUI.Button(new Rect(100, 90, 150, 30), "Move Down"))
|
||||
/// {
|
||||
/// //Switch to Down Direction
|
||||
/// m_MoveDirection = MoveDirection.Down;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
Down,
|
||||
|
||||
/// <summary>
|
||||
/// This is the None state. Assign functionality that stops movement.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use the None state for an easily identifiable way of stopping, resetting or initialising a GameObject's movement. This is a state without any predefined functionality. Before using this state, you should define what your GameObject will do in code.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Attach this script to a GameObject with a Rigidbody attached. This script starts off on the ModeDirection.None state but changes depending on buttons you press.
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Vector3 m_StartPosition, m_StartForce;
|
||||
/// Rigidbody m_Rigidbody;
|
||||
/// //Use Enum for easy switching between direction states
|
||||
/// MoveDirection m_MoveDirection;
|
||||
///
|
||||
/// //Use these Vectors for moving Rigidbody components
|
||||
/// Vector3 m_ResetVector;
|
||||
/// Vector3 m_UpVector;
|
||||
/// const float speed = 10.0f;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //You get the Rigidbody component attached to the GameObject
|
||||
/// m_Rigidbody = GetComponent<Rigidbody>();
|
||||
/// //This starts with the Rigidbody not moving in any direction at all
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
///
|
||||
/// //These are the GameObject’s starting position and Rigidbody position
|
||||
/// m_StartPosition = transform.position;
|
||||
/// m_StartForce = m_Rigidbody.transform.position;
|
||||
///
|
||||
/// //This Vector is set to 1 in the y axis (for moving upwards)
|
||||
/// m_UpVector = Vector3.up;
|
||||
/// //This Vector is zeroed out for when the Rigidbody should not move
|
||||
/// m_ResetVector = Vector3.zero;
|
||||
/// }
|
||||
///
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //This switches the direction depending on button presses
|
||||
/// switch (m_MoveDirection)
|
||||
/// {
|
||||
/// //The starting state which resets the object
|
||||
/// case MoveDirection.None:
|
||||
/// //Reset to the starting position of the GameObject and Rigidbody
|
||||
/// transform.position = m_StartPosition;
|
||||
/// m_Rigidbody.transform.position = m_StartForce;
|
||||
/// //This resets the velocity of the Rigidbody
|
||||
/// m_Rigidbody.velocity = m_ResetVector;
|
||||
/// break;
|
||||
///
|
||||
/// //This is for moving down
|
||||
/// case MoveDirection.Down:
|
||||
/// //This moves the Rigidbody down
|
||||
/// m_Rigidbody.velocity = -m_UpVector * speed;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// void OnGUI()
|
||||
/// {
|
||||
/// //Press the reset Button to switch to no mode
|
||||
/// if (GUI.Button(new Rect(100, 0, 150, 30), "Reset"))
|
||||
/// {
|
||||
/// //Switch to start/reset case
|
||||
/// m_MoveDirection = MoveDirection.None;
|
||||
/// }
|
||||
///
|
||||
/// //Press the Down button to switch the direction to down
|
||||
/// if (GUI.Button(new Rect(100, 90, 150, 30), "Move Down"))
|
||||
/// {
|
||||
/// //Switch to Down Direction
|
||||
/// m_MoveDirection = MoveDirection.Down;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
None
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4d2250412b81fe34abf39f246e274479
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,123 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// A hit result from a BaseRaycaster.
|
||||
/// </summary>
|
||||
public struct RaycastResult
|
||||
{
|
||||
private GameObject m_GameObject; // Game object hit by the raycast
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject that was hit by the raycast.
|
||||
/// </summary>
|
||||
public GameObject gameObject
|
||||
{
|
||||
get { return m_GameObject; }
|
||||
set { m_GameObject = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BaseRaycaster that raised the hit.
|
||||
/// </summary>
|
||||
public BaseRaycaster module;
|
||||
|
||||
/// <summary>
|
||||
/// Distance to the hit.
|
||||
/// </summary>
|
||||
public float distance;
|
||||
|
||||
/// <summary>
|
||||
/// Hit index
|
||||
/// </summary>
|
||||
public float index;
|
||||
|
||||
/// <summary>
|
||||
/// Used by raycasters where elements may have the same unit distance, but have specific ordering.
|
||||
/// </summary>
|
||||
public int depth;
|
||||
|
||||
/// <summary>
|
||||
/// The SortingLayer of the hit object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For UI.Graphic elements this will be the values from that graphic's Canvas
|
||||
/// For 3D objects this will always be 0.
|
||||
/// For 2D objects if a SpriteRenderer is attached to the same object as the hit collider that SpriteRenderer sortingLayerID will be used.
|
||||
/// </remarks>
|
||||
public int sortingLayer;
|
||||
|
||||
/// <summary>
|
||||
/// The SortingOrder for the hit object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For Graphic elements this will be the values from that graphics Canvas
|
||||
/// For 3D objects this will always be 0.
|
||||
/// For 2D objects if a SpriteRenderer is attached to the same object as the hit collider that SpriteRenderer sortingOrder will be used.
|
||||
/// </remarks>
|
||||
public int sortingOrder;
|
||||
|
||||
/// <summary>
|
||||
/// The world position of the where the raycast has hit.
|
||||
/// </summary>
|
||||
public Vector3 worldPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The normal at the hit location of the raycast.
|
||||
/// </summary>
|
||||
public Vector3 worldNormal;
|
||||
|
||||
/// <summary>
|
||||
/// The screen position from which the raycast was generated.
|
||||
/// </summary>
|
||||
public Vector2 screenPosition;
|
||||
|
||||
/// <summary>
|
||||
/// The display index from which the raycast was generated.
|
||||
/// </summary>
|
||||
public int displayIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Is there an associated module and a hit GameObject.
|
||||
/// </summary>
|
||||
public bool isValid
|
||||
{
|
||||
get { return module != null && gameObject != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the result.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
gameObject = null;
|
||||
module = null;
|
||||
distance = 0;
|
||||
index = 0;
|
||||
depth = 0;
|
||||
sortingLayer = 0;
|
||||
sortingOrder = 0;
|
||||
worldNormal = Vector3.up;
|
||||
worldPosition = Vector3.zero;
|
||||
screenPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (!isValid)
|
||||
return "";
|
||||
|
||||
return "Name: " + gameObject + "\n" +
|
||||
"module: " + module + "\n" +
|
||||
"distance: " + distance + "\n" +
|
||||
"index: " + index + "\n" +
|
||||
"depth: " + depth + "\n" +
|
||||
"worldNormal: " + worldNormal + "\n" +
|
||||
"worldPosition: " + worldPosition + "\n" +
|
||||
"screenPosition: " + screenPosition + "\n" +
|
||||
"module.sortOrderPriority: " + module.sortOrderPriority + "\n" +
|
||||
"module.renderOrderPriority: " + module.renderOrderPriority + "\n" +
|
||||
"sortingLayer: " + sortingLayer + "\n" +
|
||||
"sortingOrder: " + sortingOrder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3550d8ec6f29ab34d895ae9a43d560c2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,29 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
internal static class RaycasterManager
|
||||
{
|
||||
private static readonly List<BaseRaycaster> s_Raycasters = new List<BaseRaycaster>();
|
||||
|
||||
public static void AddRaycaster(BaseRaycaster baseRaycaster)
|
||||
{
|
||||
if (s_Raycasters.Contains(baseRaycaster))
|
||||
return;
|
||||
|
||||
s_Raycasters.Add(baseRaycaster);
|
||||
}
|
||||
|
||||
public static List<BaseRaycaster> GetRaycasters()
|
||||
{
|
||||
return s_Raycasters;
|
||||
}
|
||||
|
||||
public static void RemoveRaycasters(BaseRaycaster baseRaycaster)
|
||||
{
|
||||
if (!s_Raycasters.Contains(baseRaycaster))
|
||||
return;
|
||||
s_Raycasters.Remove(baseRaycaster);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 26570be2af04195458e6f1ac1f5c48e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 46646a5562f14984690c85ee7b946bc9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for any RayCaster.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Raycaster is responsible for raycasting against scene elements to determine if the cursor is over them. Default Raycasters include PhysicsRaycaster, Physics2DRaycaster, GraphicRaycaster.
|
||||
/// Custom raycasters can be added by extending this class.
|
||||
/// </remarks>
|
||||
public abstract class BaseRaycaster : UIBehaviour
|
||||
{
|
||||
private BaseRaycaster m_RootRaycaster;
|
||||
|
||||
/// <summary>
|
||||
/// Raycast against the scene.
|
||||
/// </summary>
|
||||
/// <param name="eventData">Current event data.</param>
|
||||
/// <param name="resultAppendList">List of hit Objects.</param>
|
||||
public abstract void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList);
|
||||
|
||||
/// <summary>
|
||||
/// The camera that will generate rays for this raycaster.
|
||||
/// </summary>
|
||||
public abstract Camera eventCamera { get; }
|
||||
|
||||
[Obsolete("Please use sortOrderPriority and renderOrderPriority", false)]
|
||||
public virtual int priority
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the raycaster based upon sort order.
|
||||
/// </summary>
|
||||
public virtual int sortOrderPriority
|
||||
{
|
||||
get { return int.MinValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the raycaster based upon render order.
|
||||
/// </summary>
|
||||
public virtual int renderOrderPriority
|
||||
{
|
||||
get { return int.MinValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raycaster on root canvas
|
||||
/// </summary>
|
||||
public BaseRaycaster rootRaycaster
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RootRaycaster == null)
|
||||
{
|
||||
var baseRaycasters = GetComponentsInParent<BaseRaycaster>();
|
||||
if (baseRaycasters.Length != 0)
|
||||
m_RootRaycaster = baseRaycasters[baseRaycasters.Length - 1];
|
||||
}
|
||||
|
||||
return m_RootRaycaster;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "Name: " + gameObject + "\n" +
|
||||
"eventCamera: " + eventCamera + "\n" +
|
||||
"sortOrderPriority: " + sortOrderPriority + "\n" +
|
||||
"renderOrderPriority: " + renderOrderPriority;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
RaycasterManager.AddRaycaster(this);
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
RaycasterManager.RemoveRaycasters(this);
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
protected override void OnCanvasHierarchyChanged()
|
||||
{
|
||||
base.OnCanvasHierarchyChanged();
|
||||
m_RootRaycaster = null;
|
||||
}
|
||||
|
||||
protected override void OnTransformParentChanged()
|
||||
{
|
||||
base.OnTransformParentChanged();
|
||||
m_RootRaycaster = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 426106349a0ff964fa4e7178c1d3a4f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,83 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple event system using physics raycasts.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Event/Physics 2D Raycaster")]
|
||||
[RequireComponent(typeof(Camera))]
|
||||
/// <summary>
|
||||
/// Raycaster for casting against 2D Physics components.
|
||||
/// </summary>
|
||||
public class Physics2DRaycaster : PhysicsRaycaster
|
||||
{
|
||||
#if PACKAGE_PHYSICS2D
|
||||
RaycastHit2D[] m_Hits;
|
||||
#endif
|
||||
|
||||
protected Physics2DRaycaster()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Raycast against 2D elements in the scene.
|
||||
/// </summary>
|
||||
public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
|
||||
{
|
||||
#if PACKAGE_PHYSICS2D
|
||||
Ray ray = new Ray();
|
||||
float distanceToClipPlane = 0;
|
||||
int displayIndex = 0;
|
||||
if (!ComputeRayAndDistance(eventData, ref ray, ref displayIndex, ref distanceToClipPlane))
|
||||
return;
|
||||
|
||||
int hitCount = 0;
|
||||
|
||||
if (maxRayIntersections == 0)
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.getRayIntersectionAll == null)
|
||||
return;
|
||||
m_Hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, finalEventMask);
|
||||
hitCount = m_Hits.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.getRayIntersectionAllNonAlloc == null)
|
||||
return;
|
||||
|
||||
if (m_LastMaxRayIntersections != m_MaxRayIntersections)
|
||||
{
|
||||
m_Hits = new RaycastHit2D[maxRayIntersections];
|
||||
m_LastMaxRayIntersections = m_MaxRayIntersections;
|
||||
}
|
||||
|
||||
hitCount = ReflectionMethodsCache.Singleton.getRayIntersectionAllNonAlloc(ray, m_Hits, distanceToClipPlane, finalEventMask);
|
||||
}
|
||||
|
||||
if (hitCount != 0)
|
||||
{
|
||||
for (int b = 0, bmax = hitCount; b < bmax; ++b)
|
||||
{
|
||||
var sr = m_Hits[b].collider.gameObject.GetComponent<SpriteRenderer>();
|
||||
|
||||
var result = new RaycastResult
|
||||
{
|
||||
gameObject = m_Hits[b].collider.gameObject,
|
||||
module = this,
|
||||
distance = Vector3.Distance(eventCamera.transform.position, m_Hits[b].point),
|
||||
worldPosition = m_Hits[b].point,
|
||||
worldNormal = m_Hits[b].normal,
|
||||
screenPosition = eventData.position,
|
||||
displayIndex = displayIndex,
|
||||
index = resultAppendList.Count,
|
||||
sortingLayer = sr != null ? sr.sortingLayerID : 0,
|
||||
sortingOrder = sr != null ? sr.sortingOrder : 0
|
||||
};
|
||||
resultAppendList.Add(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56666c5a40171f54783dd416a44f42bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,203 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple event system using physics raycasts.
|
||||
/// </summary>
|
||||
[AddComponentMenu("Event/Physics Raycaster")]
|
||||
[RequireComponent(typeof(Camera))]
|
||||
/// <summary>
|
||||
/// Raycaster for casting against 3D Physics components.
|
||||
/// </summary>
|
||||
public class PhysicsRaycaster : BaseRaycaster
|
||||
{
|
||||
/// <summary>
|
||||
/// Const to use for clarity when no event mask is set
|
||||
/// </summary>
|
||||
protected const int kNoEventMaskSet = -1;
|
||||
|
||||
protected Camera m_EventCamera;
|
||||
|
||||
/// <summary>
|
||||
/// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected LayerMask m_EventMask = kNoEventMaskSet;
|
||||
|
||||
/// <summary>
|
||||
/// The max number of intersections allowed. 0 = allocating version anything else is non alloc.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected int m_MaxRayIntersections = 0;
|
||||
protected int m_LastMaxRayIntersections = 0;
|
||||
|
||||
#if PACKAGE_PHYSICS
|
||||
RaycastHit[] m_Hits;
|
||||
#endif
|
||||
|
||||
protected PhysicsRaycaster()
|
||||
{}
|
||||
|
||||
public override Camera eventCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_EventCamera == null)
|
||||
m_EventCamera = GetComponent<Camera>();
|
||||
return m_EventCamera ?? Camera.main;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Depth used to determine the order of event processing.
|
||||
/// </summary>
|
||||
public virtual int depth
|
||||
{
|
||||
get { return (eventCamera != null) ? (int)eventCamera.depth : 0xFFFFFF; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event mask used to determine which objects will receive events.
|
||||
/// </summary>
|
||||
public int finalEventMask
|
||||
{
|
||||
get { return (eventCamera != null) ? eventCamera.cullingMask & m_EventMask : kNoEventMaskSet; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Layer mask used to filter events. Always combined with the camera's culling mask if a camera is used.
|
||||
/// </summary>
|
||||
public LayerMask eventMask
|
||||
{
|
||||
get { return m_EventMask; }
|
||||
set { m_EventMask = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Max number of ray intersection allowed to be found.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A value of zero will represent using the allocating version of the raycast function where as any other value will use the non allocating version.
|
||||
/// </remarks>
|
||||
public int maxRayIntersections
|
||||
{
|
||||
get { return m_MaxRayIntersections; }
|
||||
set { m_MaxRayIntersections = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a ray going from camera through the event position and the distance between the near and far clipping planes along that ray.
|
||||
/// </summary>
|
||||
/// <param name="eventData">The pointer event for which we will cast a ray.</param>
|
||||
/// <param name="ray">The ray to use.</param>
|
||||
/// <param name="eventDisplayIndex">The display index used.</param>
|
||||
/// <param name="distanceToClipPlane">The distance between the near and far clipping planes along the ray.</param>
|
||||
/// <returns>True if the operation was successful. false if it was not possible to compute, such as the eventPosition being outside of the view.</returns>
|
||||
protected bool ComputeRayAndDistance(PointerEventData eventData, ref Ray ray, ref int eventDisplayIndex, ref float distanceToClipPlane)
|
||||
{
|
||||
if (eventCamera == null)
|
||||
return false;
|
||||
|
||||
var eventPosition = Display.RelativeMouseAt(eventData.position);
|
||||
if (eventPosition != Vector3.zero)
|
||||
{
|
||||
// We support multiple display and display identification based on event position.
|
||||
eventDisplayIndex = (int)eventPosition.z;
|
||||
|
||||
// Discard events that are not part of this display so the user does not interact with multiple displays at once.
|
||||
if (eventDisplayIndex != eventCamera.targetDisplay)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The multiple display system is not supported on all platforms, when it is not supported the returned position
|
||||
// will be all zeros so when the returned index is 0 we will default to the event data to be safe.
|
||||
eventPosition = eventData.position;
|
||||
}
|
||||
|
||||
// Cull ray casts that are outside of the view rect. (case 636595)
|
||||
if (!eventCamera.pixelRect.Contains(eventPosition))
|
||||
return false;
|
||||
|
||||
ray = eventCamera.ScreenPointToRay(eventPosition);
|
||||
// compensate far plane distance - see MouseEvents.cs
|
||||
float projectionDirection = ray.direction.z;
|
||||
distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection)
|
||||
? Mathf.Infinity
|
||||
: Mathf.Abs((eventCamera.farClipPlane - eventCamera.nearClipPlane) / projectionDirection);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
|
||||
{
|
||||
#if PACKAGE_PHYSICS
|
||||
Ray ray = new Ray();
|
||||
int displayIndex = 0;
|
||||
float distanceToClipPlane = 0;
|
||||
if (!ComputeRayAndDistance(eventData, ref ray, ref displayIndex, ref distanceToClipPlane))
|
||||
return;
|
||||
|
||||
int hitCount = 0;
|
||||
|
||||
if (m_MaxRayIntersections == 0)
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.raycast3DAll == null)
|
||||
return;
|
||||
|
||||
m_Hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, finalEventMask);
|
||||
hitCount = m_Hits.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.getRaycastNonAlloc == null)
|
||||
return;
|
||||
if (m_LastMaxRayIntersections != m_MaxRayIntersections)
|
||||
{
|
||||
m_Hits = new RaycastHit[m_MaxRayIntersections];
|
||||
m_LastMaxRayIntersections = m_MaxRayIntersections;
|
||||
}
|
||||
|
||||
hitCount = ReflectionMethodsCache.Singleton.getRaycastNonAlloc(ray, m_Hits, distanceToClipPlane, finalEventMask);
|
||||
}
|
||||
|
||||
if (hitCount != 0)
|
||||
{
|
||||
if (hitCount > 1)
|
||||
System.Array.Sort(m_Hits, 0, hitCount, RaycastHitComparer.instance);
|
||||
|
||||
for (int b = 0, bmax = hitCount; b < bmax; ++b)
|
||||
{
|
||||
var result = new RaycastResult
|
||||
{
|
||||
gameObject = m_Hits[b].collider.gameObject,
|
||||
module = this,
|
||||
distance = m_Hits[b].distance,
|
||||
worldPosition = m_Hits[b].point,
|
||||
worldNormal = m_Hits[b].normal,
|
||||
screenPosition = eventData.position,
|
||||
displayIndex = displayIndex,
|
||||
index = resultAppendList.Count,
|
||||
sortingLayer = 0,
|
||||
sortingOrder = 0
|
||||
};
|
||||
resultAppendList.Add(result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PACKAGE_PHYSICS
|
||||
private class RaycastHitComparer : IComparer<RaycastHit>
|
||||
{
|
||||
public static RaycastHitComparer instance = new RaycastHitComparer();
|
||||
public int Compare(RaycastHit x, RaycastHit y)
|
||||
{
|
||||
return x.distance.CompareTo(y.distance);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c49b4cc203aa6414fae5c798d1d0e7d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,76 @@
|
|||
namespace UnityEngine.EventSystems
|
||||
{
|
||||
/// <summary>
|
||||
/// Base behaviour that has protected implementations of Unity lifecycle functions.
|
||||
/// </summary>
|
||||
public abstract class UIBehaviour : MonoBehaviour
|
||||
{
|
||||
protected virtual void Awake()
|
||||
{}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{}
|
||||
|
||||
protected virtual void Start()
|
||||
{}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the GameObject and the Component are active.
|
||||
/// </summary>
|
||||
public virtual bool IsActive()
|
||||
{
|
||||
return isActiveAndEnabled;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected virtual void OnValidate()
|
||||
{}
|
||||
|
||||
protected virtual void Reset()
|
||||
{}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// This callback is called if an associated RectTransform has its dimensions changed. The call is also made to all child rect transforms, even if the child transform itself doesn't change - as it could have, depending on its anchoring.
|
||||
/// </summary>
|
||||
protected virtual void OnRectTransformDimensionsChange()
|
||||
{}
|
||||
|
||||
protected virtual void OnBeforeTransformParentChanged()
|
||||
{}
|
||||
|
||||
protected virtual void OnTransformParentChanged()
|
||||
{}
|
||||
|
||||
protected virtual void OnDidApplyAnimationProperties()
|
||||
{}
|
||||
|
||||
protected virtual void OnCanvasGroupChanged()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the state of the parent Canvas is changed.
|
||||
/// </summary>
|
||||
protected virtual void OnCanvasHierarchyChanged()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the native representation of the behaviour has been destroyed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When a parent canvas is either enabled, disabled or a nested canvas's OverrideSorting is changed this function is called. You can for example use this to modify objects below a canvas that may depend on a parent canvas - for example, if a canvas is disabled you may want to halt some processing of a UI element.
|
||||
/// </remarks>
|
||||
public bool IsDestroyed()
|
||||
{
|
||||
// Workaround for Unity native side of the object
|
||||
// having been destroyed but accessing via interface
|
||||
// won't call the overloaded ==
|
||||
return this == null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0aaa057ce5566e940b18a0ccd0344693
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32e2186f4598cff489784aae586f2215
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("guisystem")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("guisystem")]
|
||||
[assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: InternalsVisibleTo("UnityEngine.UI.Tests")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("d4f464c7-9b15-460d-b4bc-2cacd1c1df73")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d7bd4bcc815cfb44b9990c29dabdb9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 742654cad2425334696ba6ed4495cfef
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5472815444de2ce45bf2053a4af04b9d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,244 @@
|
|||
using System.Collections;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace UnityEngine.UI.CoroutineTween
|
||||
{
|
||||
// Base interface for tweeners,
|
||||
// using an interface instead of
|
||||
// an abstract class as we want the
|
||||
// tweens to be structs.
|
||||
internal interface ITweenValue
|
||||
{
|
||||
void TweenValue(float floatPercentage);
|
||||
bool ignoreTimeScale { get; }
|
||||
float duration { get; }
|
||||
bool ValidTarget();
|
||||
}
|
||||
|
||||
// Color tween class, receives the
|
||||
// TweenValue callback and then sets
|
||||
// the value on the target.
|
||||
internal struct ColorTween : ITweenValue
|
||||
{
|
||||
public enum ColorTweenMode
|
||||
{
|
||||
All,
|
||||
RGB,
|
||||
Alpha
|
||||
}
|
||||
|
||||
public class ColorTweenCallback : UnityEvent<Color> {}
|
||||
|
||||
private ColorTweenCallback m_Target;
|
||||
private Color m_StartColor;
|
||||
private Color m_TargetColor;
|
||||
private ColorTweenMode m_TweenMode;
|
||||
|
||||
private float m_Duration;
|
||||
private bool m_IgnoreTimeScale;
|
||||
|
||||
public Color startColor
|
||||
{
|
||||
get { return m_StartColor; }
|
||||
set { m_StartColor = value; }
|
||||
}
|
||||
|
||||
public Color targetColor
|
||||
{
|
||||
get { return m_TargetColor; }
|
||||
set { m_TargetColor = value; }
|
||||
}
|
||||
|
||||
public ColorTweenMode tweenMode
|
||||
{
|
||||
get { return m_TweenMode; }
|
||||
set { m_TweenMode = value; }
|
||||
}
|
||||
|
||||
public float duration
|
||||
{
|
||||
get { return m_Duration; }
|
||||
set { m_Duration = value; }
|
||||
}
|
||||
|
||||
public bool ignoreTimeScale
|
||||
{
|
||||
get { return m_IgnoreTimeScale; }
|
||||
set { m_IgnoreTimeScale = value; }
|
||||
}
|
||||
|
||||
public void TweenValue(float floatPercentage)
|
||||
{
|
||||
if (!ValidTarget())
|
||||
return;
|
||||
|
||||
var newColor = Color.Lerp(m_StartColor, m_TargetColor, floatPercentage);
|
||||
|
||||
if (m_TweenMode == ColorTweenMode.Alpha)
|
||||
{
|
||||
newColor.r = m_StartColor.r;
|
||||
newColor.g = m_StartColor.g;
|
||||
newColor.b = m_StartColor.b;
|
||||
}
|
||||
else if (m_TweenMode == ColorTweenMode.RGB)
|
||||
{
|
||||
newColor.a = m_StartColor.a;
|
||||
}
|
||||
m_Target.Invoke(newColor);
|
||||
}
|
||||
|
||||
public void AddOnChangedCallback(UnityAction<Color> callback)
|
||||
{
|
||||
if (m_Target == null)
|
||||
m_Target = new ColorTweenCallback();
|
||||
|
||||
m_Target.AddListener(callback);
|
||||
}
|
||||
|
||||
public bool GetIgnoreTimescale()
|
||||
{
|
||||
return m_IgnoreTimeScale;
|
||||
}
|
||||
|
||||
public float GetDuration()
|
||||
{
|
||||
return m_Duration;
|
||||
}
|
||||
|
||||
public bool ValidTarget()
|
||||
{
|
||||
return m_Target != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Float tween class, receives the
|
||||
// TweenValue callback and then sets
|
||||
// the value on the target.
|
||||
internal struct FloatTween : ITweenValue
|
||||
{
|
||||
public class FloatTweenCallback : UnityEvent<float> {}
|
||||
|
||||
private FloatTweenCallback m_Target;
|
||||
private float m_StartValue;
|
||||
private float m_TargetValue;
|
||||
|
||||
private float m_Duration;
|
||||
private bool m_IgnoreTimeScale;
|
||||
|
||||
public float startValue
|
||||
{
|
||||
get { return m_StartValue; }
|
||||
set { m_StartValue = value; }
|
||||
}
|
||||
|
||||
public float targetValue
|
||||
{
|
||||
get { return m_TargetValue; }
|
||||
set { m_TargetValue = value; }
|
||||
}
|
||||
|
||||
public float duration
|
||||
{
|
||||
get { return m_Duration; }
|
||||
set { m_Duration = value; }
|
||||
}
|
||||
|
||||
public bool ignoreTimeScale
|
||||
{
|
||||
get { return m_IgnoreTimeScale; }
|
||||
set { m_IgnoreTimeScale = value; }
|
||||
}
|
||||
|
||||
public void TweenValue(float floatPercentage)
|
||||
{
|
||||
if (!ValidTarget())
|
||||
return;
|
||||
|
||||
var newValue = Mathf.Lerp(m_StartValue, m_TargetValue, floatPercentage);
|
||||
m_Target.Invoke(newValue);
|
||||
}
|
||||
|
||||
public void AddOnChangedCallback(UnityAction<float> callback)
|
||||
{
|
||||
if (m_Target == null)
|
||||
m_Target = new FloatTweenCallback();
|
||||
|
||||
m_Target.AddListener(callback);
|
||||
}
|
||||
|
||||
public bool GetIgnoreTimescale()
|
||||
{
|
||||
return m_IgnoreTimeScale;
|
||||
}
|
||||
|
||||
public float GetDuration()
|
||||
{
|
||||
return m_Duration;
|
||||
}
|
||||
|
||||
public bool ValidTarget()
|
||||
{
|
||||
return m_Target != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Tween runner, executes the given tween.
|
||||
// The coroutine will live within the given
|
||||
// behaviour container.
|
||||
internal class TweenRunner<T> where T : struct, ITweenValue
|
||||
{
|
||||
protected MonoBehaviour m_CoroutineContainer;
|
||||
protected IEnumerator m_Tween;
|
||||
|
||||
// utility function for starting the tween
|
||||
private static IEnumerator Start(T tweenInfo)
|
||||
{
|
||||
if (!tweenInfo.ValidTarget())
|
||||
yield break;
|
||||
|
||||
var elapsedTime = 0.0f;
|
||||
while (elapsedTime < tweenInfo.duration)
|
||||
{
|
||||
elapsedTime += tweenInfo.ignoreTimeScale ? Time.unscaledDeltaTime : Time.deltaTime;
|
||||
var percentage = Mathf.Clamp01(elapsedTime / tweenInfo.duration);
|
||||
tweenInfo.TweenValue(percentage);
|
||||
yield return null;
|
||||
}
|
||||
tweenInfo.TweenValue(1.0f);
|
||||
}
|
||||
|
||||
public void Init(MonoBehaviour coroutineContainer)
|
||||
{
|
||||
m_CoroutineContainer = coroutineContainer;
|
||||
}
|
||||
|
||||
public void StartTween(T info)
|
||||
{
|
||||
if (m_CoroutineContainer == null)
|
||||
{
|
||||
Debug.LogWarning("Coroutine container not configured... did you forget to call Init?");
|
||||
return;
|
||||
}
|
||||
|
||||
StopTween();
|
||||
|
||||
if (!m_CoroutineContainer.gameObject.activeInHierarchy)
|
||||
{
|
||||
info.TweenValue(1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
m_Tween = Start(info);
|
||||
m_CoroutineContainer.StartCoroutine(m_Tween);
|
||||
}
|
||||
|
||||
public void StopTween()
|
||||
{
|
||||
if (m_Tween != null)
|
||||
{
|
||||
m_CoroutineContainer.StopCoroutine(m_Tween);
|
||||
m_Tween = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7be84a49bb2cd7e4a9ed097ba22794d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 12c42068351bb084abde965d725b9887
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure that stores the state of an animation transition on a Selectable.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AnimationTriggers
|
||||
{
|
||||
private const string kDefaultNormalAnimName = "Normal";
|
||||
private const string kDefaultHighlightedAnimName = "Highlighted";
|
||||
private const string kDefaultPressedAnimName = "Pressed";
|
||||
private const string kDefaultSelectedAnimName = "Selected";
|
||||
private const string kDefaultDisabledAnimName = "Disabled";
|
||||
|
||||
[FormerlySerializedAs("normalTrigger")]
|
||||
[SerializeField]
|
||||
private string m_NormalTrigger = kDefaultNormalAnimName;
|
||||
|
||||
[FormerlySerializedAs("highlightedTrigger")]
|
||||
[SerializeField]
|
||||
private string m_HighlightedTrigger = kDefaultHighlightedAnimName;
|
||||
|
||||
[FormerlySerializedAs("pressedTrigger")]
|
||||
[SerializeField]
|
||||
private string m_PressedTrigger = kDefaultPressedAnimName;
|
||||
|
||||
[FormerlySerializedAs("m_HighlightedTrigger")]
|
||||
[SerializeField]
|
||||
private string m_SelectedTrigger = kDefaultSelectedAnimName;
|
||||
|
||||
[FormerlySerializedAs("disabledTrigger")]
|
||||
[SerializeField]
|
||||
private string m_DisabledTrigger = kDefaultDisabledAnimName;
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to send to animator when entering normal state.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Animator buttonAnimator;
|
||||
/// public Button button;
|
||||
/// void SomeFunction()
|
||||
/// {
|
||||
/// //Sets the button to the Normal state (Useful when making tutorials).
|
||||
/// buttonAnimator.SetTrigger(button.animationTriggers.normalTrigger);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string normalTrigger { get { return m_NormalTrigger; } set { m_NormalTrigger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to send to animator when entering highlighted state.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Animator buttonAnimator;
|
||||
/// public Button button;
|
||||
/// void SomeFunction()
|
||||
/// {
|
||||
/// //Sets the button to the Highlighted state (Useful when making tutorials).
|
||||
/// buttonAnimator.SetTrigger(button.animationTriggers.highlightedTrigger);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string highlightedTrigger { get { return m_HighlightedTrigger; } set { m_HighlightedTrigger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to send to animator when entering pressed state.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Animator buttonAnimator;
|
||||
/// public Button button;
|
||||
/// void SomeFunction()
|
||||
/// {
|
||||
/// //Sets the button to the Pressed state (Useful when making tutorials).
|
||||
/// buttonAnimator.SetTrigger(button.animationTriggers.pressedTrigger);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string pressedTrigger { get { return m_PressedTrigger; } set { m_PressedTrigger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to send to animator when entering selected state.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Animator buttonAnimator;
|
||||
/// public Button button;
|
||||
/// void SomeFunction()
|
||||
/// {
|
||||
/// //Sets the button to the Selected state (Useful when making tutorials).
|
||||
/// buttonAnimator.SetTrigger(button.animationTriggers.selectedTrigger);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string selectedTrigger { get { return m_SelectedTrigger; } set { m_SelectedTrigger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Trigger to send to animator when entering disabled state.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Animator buttonAnimator;
|
||||
/// public Button button;
|
||||
/// void SomeFunction()
|
||||
/// {
|
||||
/// //Sets the button to the Disabled state (Useful when making tutorials).
|
||||
/// buttonAnimator.SetTrigger(button.animationTriggers.disabledTrigger);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public string disabledTrigger { get { return m_DisabledTrigger; } set { m_DisabledTrigger = value; } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c67ac6e40bbb6fe47a095b949b609ce0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,171 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// A standard button that sends an event when clicked.
|
||||
/// </summary>
|
||||
[AddComponentMenu("UI/Button", 30)]
|
||||
public class Button : Selectable, IPointerClickHandler, ISubmitHandler
|
||||
{
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// Function definition for a button click event.
|
||||
/// </summary>
|
||||
public class ButtonClickedEvent : UnityEvent {}
|
||||
|
||||
// Event delegates triggered on click.
|
||||
[FormerlySerializedAs("onClick")]
|
||||
[SerializeField]
|
||||
private ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
|
||||
|
||||
protected Button()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// UnityEvent that is triggered when the button is pressed.
|
||||
/// Note: Triggered on MouseUp after MouseDown on the same object.
|
||||
/// </summary>
|
||||
///<example>
|
||||
///<code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.UI;
|
||||
/// using System.Collections;
|
||||
///
|
||||
/// public class ClickExample : MonoBehaviour
|
||||
/// {
|
||||
/// public Button yourButton;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// Button btn = yourButton.GetComponent<Button>();
|
||||
/// btn.onClick.AddListener(TaskOnClick);
|
||||
/// }
|
||||
///
|
||||
/// void TaskOnClick()
|
||||
/// {
|
||||
/// Debug.Log("You have clicked the button!");
|
||||
/// }
|
||||
/// }
|
||||
///</code>
|
||||
///</example>
|
||||
public ButtonClickedEvent onClick
|
||||
{
|
||||
get { return m_OnClick; }
|
||||
set { m_OnClick = value; }
|
||||
}
|
||||
|
||||
private void Press()
|
||||
{
|
||||
if (!IsActive() || !IsInteractable())
|
||||
return;
|
||||
|
||||
UISystemProfilerApi.AddMarker("Button.onClick", this);
|
||||
m_OnClick.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call all registered IPointerClickHandlers.
|
||||
/// Register button presses using the IPointerClickHandler. You can also use it to tell what type of click happened (left, right etc.).
|
||||
/// Make sure your Scene has an EventSystem.
|
||||
/// </summary>
|
||||
/// <param name="eventData">Pointer Data associated with the event. Typically by the event system.</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Attatch this script to a Button GameObject
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.EventSystems;
|
||||
///
|
||||
/// public class Example : MonoBehaviour, IPointerClickHandler
|
||||
/// {
|
||||
/// //Detect if a click occurs
|
||||
/// public void OnPointerClick(PointerEventData pointerEventData)
|
||||
/// {
|
||||
/// //Use this to tell when the user right-clicks on the Button
|
||||
/// if (pointerEventData.button == PointerEventData.InputButton.Right)
|
||||
/// {
|
||||
/// //Output to console the clicked GameObject's name and the following message. You can replace this with your own actions for when clicking the GameObject.
|
||||
/// Debug.Log(name + " Game Object Right Clicked!");
|
||||
/// }
|
||||
///
|
||||
/// //Use this to tell when the user left-clicks on the Button
|
||||
/// if (pointerEventData.button == PointerEventData.InputButton.Left)
|
||||
/// {
|
||||
/// Debug.Log(name + " Game Object Left Clicked!");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
|
||||
public virtual void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
return;
|
||||
|
||||
Press();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call all registered ISubmitHandler.
|
||||
/// </summary>
|
||||
/// <param name="eventData">Associated data with the event. Typically by the event system.</param>
|
||||
/// <remarks>
|
||||
/// This detects when a Button has been selected via a "submit" key you specify (default is the return key).
|
||||
///
|
||||
/// To change the submit key, either:
|
||||
///
|
||||
/// 1. Go to Edit->Project Settings->Input.
|
||||
///
|
||||
/// 2. Next, expand the Axes section and go to the Submit section if it exists.
|
||||
///
|
||||
/// 3. If Submit doesn’t exist, add 1 number to the Size field. This creates a new section at the bottom. Expand the new section and change the Name field to “Submit”.
|
||||
///
|
||||
/// 4. Change the Positive Button field to the key you want (e.g. space).
|
||||
///
|
||||
///
|
||||
/// Or:
|
||||
///
|
||||
/// 1. Go to your EventSystem in your Project
|
||||
///
|
||||
/// 2. Go to the Inspector window and change the Submit Button field to one of the sections in the Input Manager (e.g. "Submit"), or create your own by naming it what you like, then following the next few steps.
|
||||
///
|
||||
/// 3. Go to Edit->Project Settings->Input to get to the Input Manager.
|
||||
///
|
||||
/// 4. Expand the Axes section in the Inspector window. Add 1 to the number in the Size field. This creates a new section at the bottom.
|
||||
///
|
||||
/// 5. Expand the new section and name it the same as the name you inserted in the Submit Button field in the EventSystem. Set the Positive Button field to the key you want (e.g. space)
|
||||
/// </remarks>
|
||||
|
||||
public virtual void OnSubmit(BaseEventData eventData)
|
||||
{
|
||||
Press();
|
||||
|
||||
// if we get set disabled during the press
|
||||
// don't run the coroutine.
|
||||
if (!IsActive() || !IsInteractable())
|
||||
return;
|
||||
|
||||
DoStateTransition(SelectionState.Pressed, false);
|
||||
StartCoroutine(OnFinishSubmit());
|
||||
}
|
||||
|
||||
private IEnumerator OnFinishSubmit()
|
||||
{
|
||||
var fadeTime = colors.fadeDuration;
|
||||
var elapsedTime = 0f;
|
||||
|
||||
while (elapsedTime < fadeTime)
|
||||
{
|
||||
elapsedTime += Time.unscaledDeltaTime;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
DoStateTransition(currentSelectionState, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e29b1a8efbd4b44bb3f3716e73f07ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,374 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.UI.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Values of 'update' called on a Canvas update.
|
||||
/// </summary>
|
||||
/// <remarks> If modifying also modify m_CanvasUpdateProfilerStrings to match.</remarks>
|
||||
public enum CanvasUpdate
|
||||
{
|
||||
/// <summary>
|
||||
/// Called before layout.
|
||||
/// </summary>
|
||||
Prelayout = 0,
|
||||
/// <summary>
|
||||
/// Called for layout.
|
||||
/// </summary>
|
||||
Layout = 1,
|
||||
/// <summary>
|
||||
/// Called after layout.
|
||||
/// </summary>
|
||||
PostLayout = 2,
|
||||
/// <summary>
|
||||
/// Called before rendering.
|
||||
/// </summary>
|
||||
PreRender = 3,
|
||||
/// <summary>
|
||||
/// Called late, before render.
|
||||
/// </summary>
|
||||
LatePreRender = 4,
|
||||
/// <summary>
|
||||
/// Max enum value. Always last.
|
||||
/// </summary>
|
||||
MaxUpdateValue = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is an element that can live on a Canvas.
|
||||
/// </summary>
|
||||
public interface ICanvasElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Rebuild the element for the given stage.
|
||||
/// </summary>
|
||||
/// <param name="executing">The current CanvasUpdate stage being rebuild.</param>
|
||||
void Rebuild(CanvasUpdate executing);
|
||||
|
||||
/// <summary>
|
||||
/// Get the transform associated with the ICanvasElement.
|
||||
/// </summary>
|
||||
Transform transform { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Callback sent when this ICanvasElement has completed layout.
|
||||
/// </summary>
|
||||
void LayoutComplete();
|
||||
|
||||
/// <summary>
|
||||
/// Callback sent when this ICanvasElement has completed Graphic rebuild.
|
||||
/// </summary>
|
||||
void GraphicUpdateComplete();
|
||||
|
||||
/// <summary>
|
||||
/// Used if the native representation has been destroyed.
|
||||
/// </summary>
|
||||
/// <returns>Return true if the element is considered destroyed.</returns>
|
||||
bool IsDestroyed();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A place where CanvasElements can register themselves for rebuilding.
|
||||
/// </summary>
|
||||
public class CanvasUpdateRegistry
|
||||
{
|
||||
private static CanvasUpdateRegistry s_Instance;
|
||||
|
||||
private bool m_PerformingLayoutUpdate;
|
||||
private bool m_PerformingGraphicUpdate;
|
||||
|
||||
// This list matches the CanvasUpdate enum above. Keep in sync
|
||||
private string[] m_CanvasUpdateProfilerStrings = new string[] { "CanvasUpdate.Prelayout", "CanvasUpdate.Layout", "CanvasUpdate.PostLayout", "CanvasUpdate.PreRender", "CanvasUpdate.LatePreRender" };
|
||||
private const string m_CullingUpdateProfilerString = "ClipperRegistry.Cull";
|
||||
|
||||
private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();
|
||||
private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();
|
||||
|
||||
protected CanvasUpdateRegistry()
|
||||
{
|
||||
Canvas.willRenderCanvases += PerformUpdate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the singleton registry instance.
|
||||
/// </summary>
|
||||
public static CanvasUpdateRegistry instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance == null)
|
||||
s_Instance = new CanvasUpdateRegistry();
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ObjectValidForUpdate(ICanvasElement element)
|
||||
{
|
||||
var valid = element != null;
|
||||
|
||||
var isUnityObject = element is Object;
|
||||
if (isUnityObject)
|
||||
valid = (element as Object) != null; //Here we make use of the overloaded UnityEngine.Object == null, that checks if the native object is alive.
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private void CleanInvalidItems()
|
||||
{
|
||||
// So MB's override the == operator for null equality, which checks
|
||||
// if they are destroyed. This is fine if you are looking at a concrete
|
||||
// mb, but in this case we are looking at a list of ICanvasElement
|
||||
// this won't forward the == operator to the MB, but just check if the
|
||||
// interface is null. IsDestroyed will return if the backend is destroyed.
|
||||
|
||||
for (int i = m_LayoutRebuildQueue.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var item = m_LayoutRebuildQueue[i];
|
||||
if (item == null)
|
||||
{
|
||||
m_LayoutRebuildQueue.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.IsDestroyed())
|
||||
{
|
||||
m_LayoutRebuildQueue.RemoveAt(i);
|
||||
item.LayoutComplete();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = m_GraphicRebuildQueue.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var item = m_GraphicRebuildQueue[i];
|
||||
if (item == null)
|
||||
{
|
||||
m_GraphicRebuildQueue.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.IsDestroyed())
|
||||
{
|
||||
m_GraphicRebuildQueue.RemoveAt(i);
|
||||
item.GraphicUpdateComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Comparison<ICanvasElement> s_SortLayoutFunction = SortLayoutList;
|
||||
private void PerformUpdate()
|
||||
{
|
||||
UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout);
|
||||
CleanInvalidItems();
|
||||
|
||||
m_PerformingLayoutUpdate = true;
|
||||
|
||||
m_LayoutRebuildQueue.Sort(s_SortLayoutFunction);
|
||||
for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample(m_CanvasUpdateProfilerStrings[i]);
|
||||
for (int j = 0; j < m_LayoutRebuildQueue.Count; j++)
|
||||
{
|
||||
var rebuild = instance.m_LayoutRebuildQueue[j];
|
||||
try
|
||||
{
|
||||
if (ObjectValidForUpdate(rebuild))
|
||||
rebuild.Rebuild((CanvasUpdate)i);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e, rebuild.transform);
|
||||
}
|
||||
}
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i)
|
||||
m_LayoutRebuildQueue[i].LayoutComplete();
|
||||
|
||||
instance.m_LayoutRebuildQueue.Clear();
|
||||
m_PerformingLayoutUpdate = false;
|
||||
UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout);
|
||||
UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Render);
|
||||
|
||||
// now layout is complete do culling...
|
||||
UnityEngine.Profiling.Profiler.BeginSample(m_CullingUpdateProfilerString);
|
||||
ClipperRegistry.instance.Cull();
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
|
||||
m_PerformingGraphicUpdate = true;
|
||||
for (var i = (int)CanvasUpdate.PreRender; i < (int)CanvasUpdate.MaxUpdateValue; i++)
|
||||
{
|
||||
UnityEngine.Profiling.Profiler.BeginSample(m_CanvasUpdateProfilerStrings[i]);
|
||||
for (var k = 0; k < instance.m_GraphicRebuildQueue.Count; k++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var element = instance.m_GraphicRebuildQueue[k];
|
||||
if (ObjectValidForUpdate(element))
|
||||
element.Rebuild((CanvasUpdate)i);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e, instance.m_GraphicRebuildQueue[k].transform);
|
||||
}
|
||||
}
|
||||
UnityEngine.Profiling.Profiler.EndSample();
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i)
|
||||
m_GraphicRebuildQueue[i].GraphicUpdateComplete();
|
||||
|
||||
instance.m_GraphicRebuildQueue.Clear();
|
||||
m_PerformingGraphicUpdate = false;
|
||||
UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Render);
|
||||
}
|
||||
|
||||
private static int ParentCount(Transform child)
|
||||
{
|
||||
if (child == null)
|
||||
return 0;
|
||||
|
||||
var parent = child.parent;
|
||||
int count = 0;
|
||||
while (parent != null)
|
||||
{
|
||||
count++;
|
||||
parent = parent.parent;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int SortLayoutList(ICanvasElement x, ICanvasElement y)
|
||||
{
|
||||
Transform t1 = x.transform;
|
||||
Transform t2 = y.transform;
|
||||
|
||||
return ParentCount(t1) - ParentCount(t2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try and add the given element to the layout rebuild list.
|
||||
/// Will not return if successfully added.
|
||||
/// </summary>
|
||||
/// <param name="element">The element that is needing rebuilt.</param>
|
||||
public static void RegisterCanvasElementForLayoutRebuild(ICanvasElement element)
|
||||
{
|
||||
instance.InternalRegisterCanvasElementForLayoutRebuild(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try and add the given element to the layout rebuild list.
|
||||
/// </summary>
|
||||
/// <param name="element">The element that is needing rebuilt.</param>
|
||||
/// <returns>
|
||||
/// True if the element was successfully added to the rebuilt list.
|
||||
/// False if either already inside a Graphic Update loop OR has already been added to the list.
|
||||
/// </returns>
|
||||
public static bool TryRegisterCanvasElementForLayoutRebuild(ICanvasElement element)
|
||||
{
|
||||
return instance.InternalRegisterCanvasElementForLayoutRebuild(element);
|
||||
}
|
||||
|
||||
private bool InternalRegisterCanvasElementForLayoutRebuild(ICanvasElement element)
|
||||
{
|
||||
if (m_LayoutRebuildQueue.Contains(element))
|
||||
return false;
|
||||
|
||||
/* TODO: this likely should be here but causes the error to show just resizing the game view (case 739376)
|
||||
if (m_PerformingLayoutUpdate)
|
||||
{
|
||||
Debug.LogError(string.Format("Trying to add {0} for layout rebuild while we are already inside a layout rebuild loop. This is not supported.", element));
|
||||
return false;
|
||||
}*/
|
||||
|
||||
return m_LayoutRebuildQueue.AddUnique(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try and add the given element to the rebuild list.
|
||||
/// Will not return if successfully added.
|
||||
/// </summary>
|
||||
/// <param name="element">The element that is needing rebuilt.</param>
|
||||
public static void RegisterCanvasElementForGraphicRebuild(ICanvasElement element)
|
||||
{
|
||||
instance.InternalRegisterCanvasElementForGraphicRebuild(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try and add the given element to the rebuild list.
|
||||
/// </summary>
|
||||
/// <param name="element">The element that is needing rebuilt.</param>
|
||||
/// <returns>
|
||||
/// True if the element was successfully added to the rebuilt list.
|
||||
/// False if either already inside a Graphic Update loop OR has already been added to the list.
|
||||
/// </returns>
|
||||
public static bool TryRegisterCanvasElementForGraphicRebuild(ICanvasElement element)
|
||||
{
|
||||
return instance.InternalRegisterCanvasElementForGraphicRebuild(element);
|
||||
}
|
||||
|
||||
private bool InternalRegisterCanvasElementForGraphicRebuild(ICanvasElement element)
|
||||
{
|
||||
if (m_PerformingGraphicUpdate)
|
||||
{
|
||||
Debug.LogError(string.Format("Trying to add {0} for graphic rebuild while we are already inside a graphic rebuild loop. This is not supported.", element));
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_GraphicRebuildQueue.AddUnique(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the given element from both the graphic and the layout rebuild lists.
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
public static void UnRegisterCanvasElementForRebuild(ICanvasElement element)
|
||||
{
|
||||
instance.InternalUnRegisterCanvasElementForLayoutRebuild(element);
|
||||
instance.InternalUnRegisterCanvasElementForGraphicRebuild(element);
|
||||
}
|
||||
|
||||
private void InternalUnRegisterCanvasElementForLayoutRebuild(ICanvasElement element)
|
||||
{
|
||||
if (m_PerformingLayoutUpdate)
|
||||
{
|
||||
Debug.LogError(string.Format("Trying to remove {0} from rebuild list while we are already inside a rebuild loop. This is not supported.", element));
|
||||
return;
|
||||
}
|
||||
|
||||
element.LayoutComplete();
|
||||
instance.m_LayoutRebuildQueue.Remove(element);
|
||||
}
|
||||
|
||||
private void InternalUnRegisterCanvasElementForGraphicRebuild(ICanvasElement element)
|
||||
{
|
||||
if (m_PerformingGraphicUpdate)
|
||||
{
|
||||
Debug.LogError(string.Format("Trying to remove {0} from rebuild list while we are already inside a rebuild loop. This is not supported.", element));
|
||||
return;
|
||||
}
|
||||
element.GraphicUpdateComplete();
|
||||
instance.m_GraphicRebuildQueue.Remove(element);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are graphics layouts currently being calculated..
|
||||
/// </summary>
|
||||
/// <returns>True if the rebuild loop is CanvasUpdate.Prelayout, CanvasUpdate.Layout or CanvasUpdate.Postlayout</returns>
|
||||
public static bool IsRebuildingLayout()
|
||||
{
|
||||
return instance.m_PerformingLayoutUpdate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are graphics currently being rebuild.
|
||||
/// </summary>
|
||||
/// <returns>True if the rebuild loop is CanvasUpdate.PreRender or CanvasUpdate.Render</returns>
|
||||
public static bool IsRebuildingGraphics()
|
||||
{
|
||||
return instance.m_PerformingGraphicUpdate;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfb788a43e03363419155b8af77da971
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,235 @@
|
|||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// Structure that stores the state of a color transition on a Selectable.
|
||||
/// </summary>
|
||||
public struct ColorBlock : IEquatable<ColorBlock>
|
||||
{
|
||||
[FormerlySerializedAs("normalColor")]
|
||||
[SerializeField]
|
||||
private Color m_NormalColor;
|
||||
|
||||
[FormerlySerializedAs("highlightedColor")]
|
||||
[SerializeField]
|
||||
private Color m_HighlightedColor;
|
||||
|
||||
[FormerlySerializedAs("pressedColor")]
|
||||
[SerializeField]
|
||||
private Color m_PressedColor;
|
||||
|
||||
[FormerlySerializedAs("m_HighlightedColor")]
|
||||
[SerializeField]
|
||||
private Color m_SelectedColor;
|
||||
|
||||
[FormerlySerializedAs("disabledColor")]
|
||||
[SerializeField]
|
||||
private Color m_DisabledColor;
|
||||
|
||||
[Range(1, 5)]
|
||||
[SerializeField]
|
||||
private float m_ColorMultiplier;
|
||||
|
||||
[FormerlySerializedAs("fadeDuration")]
|
||||
[SerializeField]
|
||||
private float m_FadeDuration;
|
||||
|
||||
/// <summary>
|
||||
/// The normal color for this color block.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Button button;
|
||||
/// public Color newColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Changes the button's Normal color to the new color.
|
||||
/// ColorBlock cb = button.colors;
|
||||
/// cb.normalColor = newColor;
|
||||
/// button.colors = cb;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Color normalColor { get { return m_NormalColor; } set { m_NormalColor = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The highlight color for this color block.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Button button;
|
||||
/// public Color newColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Changes the button's Highlighted color to the new color.
|
||||
/// ColorBlock cb = button.colors;
|
||||
/// cb.highlightedColor = newColor;
|
||||
/// button.colors = cb;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Color highlightedColor { get { return m_HighlightedColor; } set { m_HighlightedColor = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The pressed color for this color block.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Button button;
|
||||
/// public Color newColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Changes the button's Pressed color to the new color.
|
||||
/// ColorBlock cb = button.colors;
|
||||
/// cb.pressedColor = newColor;
|
||||
/// button.colors = cb;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Color pressedColor { get { return m_PressedColor; } set { m_PressedColor = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The selected color for this color block.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Button button;
|
||||
/// public Color newColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Changes the button's Selected color to the new color.
|
||||
/// ColorBlock cb = button.colors;
|
||||
/// cb.selectedColor = newColor;
|
||||
/// button.colors = cb;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Color selectedColor { get { return m_SelectedColor; } set { m_SelectedColor = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The disabled color for this color block.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class ExampleClass : MonoBehaviour
|
||||
/// {
|
||||
/// public Button button;
|
||||
/// public Color newColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Changes the button's Disabled color to the new color.
|
||||
/// ColorBlock cb = button.colors;
|
||||
/// cb.disabledColor = newColor;
|
||||
/// button.colors = cb;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Color disabledColor { get { return m_DisabledColor; } set { m_DisabledColor = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Multiplier applied to colors (allows brightening greater then base color).
|
||||
/// </summary>
|
||||
public float colorMultiplier { get { return m_ColorMultiplier; } set { m_ColorMultiplier = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// How long a color transition between states should take.
|
||||
/// </summary>
|
||||
public float fadeDuration { get { return m_FadeDuration; } set { m_FadeDuration = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Simple getter for a code generated default ColorBlock.
|
||||
/// </summary>
|
||||
public static ColorBlock defaultColorBlock
|
||||
{
|
||||
get
|
||||
{
|
||||
var c = new ColorBlock
|
||||
{
|
||||
m_NormalColor = new Color32(255, 255, 255, 255),
|
||||
m_HighlightedColor = new Color32(245, 245, 245, 255),
|
||||
m_PressedColor = new Color32(200, 200, 200, 255),
|
||||
m_SelectedColor = new Color32(245, 245, 245, 255),
|
||||
m_DisabledColor = new Color32(200, 200, 200, 128),
|
||||
colorMultiplier = 1.0f,
|
||||
fadeDuration = 0.1f
|
||||
};
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is ColorBlock))
|
||||
return false;
|
||||
|
||||
return Equals((ColorBlock)obj);
|
||||
}
|
||||
|
||||
public bool Equals(ColorBlock other)
|
||||
{
|
||||
return normalColor == other.normalColor &&
|
||||
highlightedColor == other.highlightedColor &&
|
||||
pressedColor == other.pressedColor &&
|
||||
selectedColor == other.selectedColor &&
|
||||
disabledColor == other.disabledColor &&
|
||||
colorMultiplier == other.colorMultiplier &&
|
||||
fadeDuration == other.fadeDuration;
|
||||
}
|
||||
|
||||
public static bool operator==(ColorBlock point1, ColorBlock point2)
|
||||
{
|
||||
return point1.Equals(point2);
|
||||
}
|
||||
|
||||
public static bool operator!=(ColorBlock point1, ColorBlock point2)
|
||||
{
|
||||
return !point1.Equals(point2);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 83088ba2132cbc940b7ca0c679a02b0d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 27ed3e221887b3544bd9d6505d4a789f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,70 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine.UI.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Registry class to keep track of all IClippers that exist in the scene
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is used during the CanvasUpdate loop to cull clippable elements. The clipping is called after layout, but before Graphic update.
|
||||
/// </remarks>
|
||||
public class ClipperRegistry
|
||||
{
|
||||
static ClipperRegistry s_Instance;
|
||||
|
||||
readonly IndexedSet<IClipper> m_Clippers = new IndexedSet<IClipper>();
|
||||
|
||||
protected ClipperRegistry()
|
||||
{
|
||||
// This is needed for AOT platforms. Without it the compile doesn't get the definition of the Dictionarys
|
||||
#pragma warning disable 168
|
||||
Dictionary<IClipper, int> emptyIClipperDic;
|
||||
#pragma warning restore 168
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance of the clipper registry.
|
||||
/// </summary>
|
||||
public static ClipperRegistry instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance == null)
|
||||
s_Instance = new ClipperRegistry();
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform the clipping on all registered IClipper
|
||||
/// </summary>
|
||||
public void Cull()
|
||||
{
|
||||
for (var i = 0; i < m_Clippers.Count; ++i)
|
||||
{
|
||||
m_Clippers[i].PerformClipping();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a unique IClipper element
|
||||
/// </summary>
|
||||
/// <param name="c">The clipper element to add</param>
|
||||
public static void Register(IClipper c)
|
||||
{
|
||||
if (c == null)
|
||||
return;
|
||||
instance.m_Clippers.AddUnique(c);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnRegister a IClipper element
|
||||
/// </summary>
|
||||
/// <param name="c">The Element to try and remove.</param>
|
||||
public static void Unregister(IClipper c)
|
||||
{
|
||||
instance.m_Clippers.Remove(c);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9f1026265f8e3d54fb6e9f082c43debf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,52 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class to help when clipping using IClipper.
|
||||
/// </summary>
|
||||
public static class Clipping
|
||||
{
|
||||
/// <summary>
|
||||
/// Find the Rect to use for clipping.
|
||||
/// Given the input RectMask2ds find a rectangle that is the overlap of all the inputs.
|
||||
/// </summary>
|
||||
/// <param name="rectMaskParents">RectMasks to build the overlap rect from.</param>
|
||||
/// <param name="validRect">Was there a valid Rect found.</param>
|
||||
/// <returns>The final compounded overlapping rect</returns>
|
||||
public static Rect FindCullAndClipWorldRect(List<RectMask2D> rectMaskParents, out bool validRect)
|
||||
{
|
||||
if (rectMaskParents.Count == 0)
|
||||
{
|
||||
validRect = false;
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
Rect current = rectMaskParents[0].canvasRect;
|
||||
Vector4 offset = rectMaskParents[0].padding;
|
||||
float xMin = current.xMin + offset.x;
|
||||
float xMax = current.xMax - offset.z;
|
||||
float yMin = current.yMin + offset.y;
|
||||
float yMax = current.yMax - offset.w;
|
||||
for (var i = 1; i < rectMaskParents.Count; ++i)
|
||||
{
|
||||
current = rectMaskParents[i].canvasRect;
|
||||
offset = rectMaskParents[i].padding;
|
||||
if (xMin < current.xMin + offset.x)
|
||||
xMin = current.xMin + offset.x;
|
||||
if (yMin < current.yMin + offset.y)
|
||||
yMin = current.yMin + offset.y;
|
||||
if (xMax > current.xMax - offset.z)
|
||||
xMax = current.xMax - offset.z;
|
||||
if (yMax > current.yMax - offset.w)
|
||||
yMax = current.yMax - offset.w;
|
||||
}
|
||||
|
||||
validRect = xMax > xMin && yMax > yMin;
|
||||
if (validRect)
|
||||
return new Rect(xMin, yMin, xMax - xMin, yMax - yMin);
|
||||
else
|
||||
return new Rect();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67e3583b91179094094c6a188b232262
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,60 @@
|
|||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that can be used to recieve clipping callbacks as part of the canvas update loop.
|
||||
/// </summary>
|
||||
public interface IClipper
|
||||
{
|
||||
/// <summary>
|
||||
/// Function to to cull / clip children elements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Called after layout and before Graphic update of the Canvas update loop.
|
||||
/// </remarks>
|
||||
|
||||
void PerformClipping();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for elements that can be clipped if they are under an IClipper
|
||||
/// </summary>
|
||||
public interface IClippable
|
||||
{
|
||||
/// <summary>
|
||||
/// GameObject of the IClippable object
|
||||
/// </summary>
|
||||
GameObject gameObject { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Will be called when the state of a parent IClippable changed.
|
||||
/// </summary>
|
||||
void RecalculateClipping();
|
||||
|
||||
/// <summary>
|
||||
/// The RectTransform of the clippable.
|
||||
/// </summary>
|
||||
RectTransform rectTransform { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Clip and cull the IClippable given a specific clipping rect
|
||||
/// </summary>
|
||||
/// <param name="clipRect">The Rectangle in which to clip against.</param>
|
||||
/// <param name="validRect">Is the Rect valid. If not then the rect has 0 size.</param>
|
||||
void Cull(Rect clipRect, bool validRect);
|
||||
|
||||
/// <summary>
|
||||
/// Set the clip rect for the IClippable.
|
||||
/// </summary>
|
||||
/// <param name="value">The Rectangle for the clipping</param>
|
||||
/// <param name="validRect">Is the rect valid.</param>
|
||||
void SetClipRect(Rect value, bool validRect);
|
||||
|
||||
/// <summary>
|
||||
/// Set the clip softness for the IClippable.
|
||||
///
|
||||
/// The softness is a linear alpha falloff over clipSoftness pixels.
|
||||
/// </summary>
|
||||
/// <param name="clipSoftness">The number of pixels to apply the softness to </param>
|
||||
void SetClipSoftness(Vector2 clipSoftness);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 371b6b9c8adc50745ace66a6fdf67481
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
|||
namespace UnityEngine.UI
|
||||
{
|
||||
internal class RectangularVertexClipper
|
||||
{
|
||||
readonly Vector3[] m_WorldCorners = new Vector3[4];
|
||||
readonly Vector3[] m_CanvasCorners = new Vector3[4];
|
||||
|
||||
public Rect GetCanvasRect(RectTransform t, Canvas c)
|
||||
{
|
||||
if (c == null)
|
||||
return new Rect();
|
||||
|
||||
t.GetWorldCorners(m_WorldCorners);
|
||||
var canvasTransform = c.GetComponent<Transform>();
|
||||
for (int i = 0; i < 4; ++i)
|
||||
m_CanvasCorners[i] = canvasTransform.InverseTransformPoint(m_WorldCorners[i]);
|
||||
|
||||
return new Rect(m_CanvasCorners[0].x, m_CanvasCorners[0].y, m_CanvasCorners[2].x - m_CanvasCorners[0].x, m_CanvasCorners[2].y - m_CanvasCorners[0].y);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c606041f02fc7d542b1429806872292b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,802 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class for creating default implementations of builtin UI controls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The recommended workflow for using UI controls with the UI system is to create a prefab for each type of control and instantiate those when needed. This way changes can be made to the prefabs which immediately have effect on all used instances.
|
||||
///
|
||||
/// However, in certain cases there can be reasons to create UI controls entirely from code. The DefaultControls class provide methods to create each of the builtin UI controls. The resulting objects are the same as are obtained from using the corresponding UI menu entries in the GameObject menu in the Editor.
|
||||
///
|
||||
/// An example use of this is creating menu items for custom new UI controls that mimics the ones that are builtin in Unity. Some such UI controls may contain other UI controls. For example, a scroll view contains scrollbars.By using the DefaultControls methods to create those parts, it is ensured that they are identical in look and setup to the ones provided in the menu items builtin with Unity.
|
||||
///
|
||||
/// Note that the details of the setup of the UI controls created by the methods in this class may change with later revisions of the UI system.As such, they are not guaranteed to be 100% backwards compatible. It is recommended not to rely on the specific hierarchies of the GameObjects created by these methods, and limit your code to only interface with the root GameObject created by each method.
|
||||
/// </remarks>
|
||||
public static class DefaultControls
|
||||
{
|
||||
static IFactoryControls m_CurrentFactory = DefaultRuntimeFactory.Default;
|
||||
public static IFactoryControls factory
|
||||
{
|
||||
get { return m_CurrentFactory; }
|
||||
#if UNITY_EDITOR
|
||||
set { m_CurrentFactory = value; }
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory interface to create a GameObject in this class.
|
||||
/// It is necessary to use this interface in the whole class so MenuOption and Editor can work using ObjectFactory and default Presets.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The only available method is CreateGameObject.
|
||||
/// It needs to be called with every Components the created Object will need because of a bug with Undo and RectTransform.
|
||||
/// Adding a UI component on the created GameObject may crash if done after Undo.SetTransformParent,
|
||||
/// So it's better to prevent such behavior in this class by asking for full creation with all the components.
|
||||
/// </remarks>
|
||||
public interface IFactoryControls
|
||||
{
|
||||
GameObject CreateGameObject(string name, params Type[] components);
|
||||
}
|
||||
|
||||
private class DefaultRuntimeFactory : IFactoryControls
|
||||
{
|
||||
public static IFactoryControls Default = new DefaultRuntimeFactory();
|
||||
|
||||
public GameObject CreateGameObject(string name, params Type[] components)
|
||||
{
|
||||
return new GameObject(name, components);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Object used to pass resources to use for the default controls.
|
||||
/// </summary>
|
||||
public struct Resources
|
||||
{
|
||||
/// <summary>
|
||||
/// The primary sprite to be used for graphical UI elements, used by the button, toggle, and dropdown controls, among others.
|
||||
/// </summary>
|
||||
public Sprite standard;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used for background elements.
|
||||
/// </summary>
|
||||
public Sprite background;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used as background for input fields.
|
||||
/// </summary>
|
||||
public Sprite inputField;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used for knobs that can be dragged, such as on a slider.
|
||||
/// </summary>
|
||||
public Sprite knob;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used for representation of an "on" state when present, such as a checkmark.
|
||||
/// </summary>
|
||||
public Sprite checkmark;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used to indicate that a button will open a dropdown when clicked.
|
||||
/// </summary>
|
||||
public Sprite dropdown;
|
||||
|
||||
/// <summary>
|
||||
/// Sprite used for masking purposes, for example to be used for the viewport of a scroll view.
|
||||
/// </summary>
|
||||
public Sprite mask;
|
||||
}
|
||||
|
||||
private const float kWidth = 160f;
|
||||
private const float kThickHeight = 30f;
|
||||
private const float kThinHeight = 20f;
|
||||
private static Vector2 s_ThickElementSize = new Vector2(kWidth, kThickHeight);
|
||||
private static Vector2 s_ThinElementSize = new Vector2(kWidth, kThinHeight);
|
||||
private static Vector2 s_ImageElementSize = new Vector2(100f, 100f);
|
||||
private static Color s_DefaultSelectableColor = new Color(1f, 1f, 1f, 1f);
|
||||
private static Color s_PanelColor = new Color(1f, 1f, 1f, 0.392f);
|
||||
private static Color s_TextColor = new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
|
||||
|
||||
// Helper methods at top
|
||||
|
||||
private static GameObject CreateUIElementRoot(string name, Vector2 size, params Type[] components)
|
||||
{
|
||||
GameObject child = factory.CreateGameObject(name, components);
|
||||
RectTransform rectTransform = child.GetComponent<RectTransform>();
|
||||
rectTransform.sizeDelta = size;
|
||||
return child;
|
||||
}
|
||||
|
||||
private static GameObject CreateUIObject(string name, GameObject parent, params Type[] components)
|
||||
{
|
||||
GameObject go = factory.CreateGameObject(name, components);
|
||||
SetParentAndAlign(go, parent);
|
||||
return go;
|
||||
}
|
||||
|
||||
private static void SetDefaultTextValues(Text lbl)
|
||||
{
|
||||
// Set text values we want across UI elements in default controls.
|
||||
// Don't set values which are the same as the default values for the Text component,
|
||||
// since there's no point in that, and it's good to keep them as consistent as possible.
|
||||
lbl.color = s_TextColor;
|
||||
|
||||
// Reset() is not called when playing. We still want the default font to be assigned
|
||||
lbl.AssignDefaultFont();
|
||||
}
|
||||
|
||||
private static void SetDefaultColorTransitionValues(Selectable slider)
|
||||
{
|
||||
ColorBlock colors = slider.colors;
|
||||
colors.highlightedColor = new Color(0.882f, 0.882f, 0.882f);
|
||||
colors.pressedColor = new Color(0.698f, 0.698f, 0.698f);
|
||||
colors.disabledColor = new Color(0.521f, 0.521f, 0.521f);
|
||||
}
|
||||
|
||||
private static void SetParentAndAlign(GameObject child, GameObject parent)
|
||||
{
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Undo.SetTransformParent(child.transform, parent.transform, "");
|
||||
#else
|
||||
child.transform.SetParent(parent.transform, false);
|
||||
#endif
|
||||
SetLayerRecursively(child, parent.layer);
|
||||
}
|
||||
|
||||
private static void SetLayerRecursively(GameObject go, int layer)
|
||||
{
|
||||
go.layer = layer;
|
||||
Transform t = go.transform;
|
||||
for (int i = 0; i < t.childCount; i++)
|
||||
SetLayerRecursively(t.GetChild(i).gameObject, layer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Panel.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Image
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreatePanel(Resources resources)
|
||||
{
|
||||
GameObject panelRoot = CreateUIElementRoot("Panel", s_ThickElementSize, typeof(Image));
|
||||
|
||||
// Set RectTransform to stretch
|
||||
RectTransform rectTransform = panelRoot.GetComponent<RectTransform>();
|
||||
rectTransform.anchorMin = Vector2.zero;
|
||||
rectTransform.anchorMax = Vector2.one;
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
rectTransform.sizeDelta = Vector2.zero;
|
||||
|
||||
Image image = panelRoot.GetComponent<Image>();
|
||||
image.sprite = resources.background;
|
||||
image.type = Image.Type.Sliced;
|
||||
image.color = s_PanelColor;
|
||||
|
||||
return panelRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI button.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Button
|
||||
/// -Text
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateButton(Resources resources)
|
||||
{
|
||||
GameObject buttonRoot = CreateUIElementRoot("Button", s_ThickElementSize, typeof(Image), typeof(Button));
|
||||
|
||||
GameObject childText = CreateUIObject("Text", buttonRoot, typeof(Text));
|
||||
|
||||
Image image = buttonRoot.GetComponent<Image>();
|
||||
image.sprite = resources.standard;
|
||||
image.type = Image.Type.Sliced;
|
||||
image.color = s_DefaultSelectableColor;
|
||||
|
||||
Button bt = buttonRoot.GetComponent<Button>();
|
||||
SetDefaultColorTransitionValues(bt);
|
||||
|
||||
Text text = childText.GetComponent<Text>();
|
||||
text.text = "Button";
|
||||
text.alignment = TextAnchor.MiddleCenter;
|
||||
SetDefaultTextValues(text);
|
||||
|
||||
RectTransform textRectTransform = childText.GetComponent<RectTransform>();
|
||||
textRectTransform.anchorMin = Vector2.zero;
|
||||
textRectTransform.anchorMax = Vector2.one;
|
||||
textRectTransform.sizeDelta = Vector2.zero;
|
||||
|
||||
return buttonRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Text.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Text
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateText(Resources resources)
|
||||
{
|
||||
GameObject go = CreateUIElementRoot("Text", s_ThickElementSize, typeof(Text));
|
||||
|
||||
Text lbl = go.GetComponent<Text>();
|
||||
lbl.text = "New Text";
|
||||
SetDefaultTextValues(lbl);
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Image.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Image
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateImage(Resources resources)
|
||||
{
|
||||
GameObject go = CreateUIElementRoot("Image", s_ImageElementSize, typeof(Image));
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI RawImage.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// RawImage
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateRawImage(Resources resources)
|
||||
{
|
||||
GameObject go = CreateUIElementRoot("RawImage", s_ImageElementSize, typeof(RawImage));
|
||||
return go;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Slider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Slider
|
||||
/// - Background
|
||||
/// - Fill Area
|
||||
/// - Fill
|
||||
/// - Handle Slide Area
|
||||
/// - Handle
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateSlider(Resources resources)
|
||||
{
|
||||
// Create GOs Hierarchy
|
||||
GameObject root = CreateUIElementRoot("Slider", s_ThinElementSize, typeof(Slider));
|
||||
|
||||
GameObject background = CreateUIObject("Background", root, typeof(Image));
|
||||
GameObject fillArea = CreateUIObject("Fill Area", root, typeof(RectTransform));
|
||||
GameObject fill = CreateUIObject("Fill", fillArea, typeof(Image));
|
||||
GameObject handleArea = CreateUIObject("Handle Slide Area", root, typeof(RectTransform));
|
||||
GameObject handle = CreateUIObject("Handle", handleArea, typeof(Image));
|
||||
|
||||
// Background
|
||||
Image backgroundImage = background.GetComponent<Image>();
|
||||
backgroundImage.sprite = resources.background;
|
||||
backgroundImage.type = Image.Type.Sliced;
|
||||
backgroundImage.color = s_DefaultSelectableColor;
|
||||
RectTransform backgroundRect = background.GetComponent<RectTransform>();
|
||||
backgroundRect.anchorMin = new Vector2(0, 0.25f);
|
||||
backgroundRect.anchorMax = new Vector2(1, 0.75f);
|
||||
backgroundRect.sizeDelta = new Vector2(0, 0);
|
||||
|
||||
// Fill Area
|
||||
RectTransform fillAreaRect = fillArea.GetComponent<RectTransform>();
|
||||
fillAreaRect.anchorMin = new Vector2(0, 0.25f);
|
||||
fillAreaRect.anchorMax = new Vector2(1, 0.75f);
|
||||
fillAreaRect.anchoredPosition = new Vector2(-5, 0);
|
||||
fillAreaRect.sizeDelta = new Vector2(-20, 0);
|
||||
|
||||
// Fill
|
||||
Image fillImage = fill.GetComponent<Image>();
|
||||
fillImage.sprite = resources.standard;
|
||||
fillImage.type = Image.Type.Sliced;
|
||||
fillImage.color = s_DefaultSelectableColor;
|
||||
|
||||
RectTransform fillRect = fill.GetComponent<RectTransform>();
|
||||
fillRect.sizeDelta = new Vector2(10, 0);
|
||||
|
||||
// Handle Area
|
||||
RectTransform handleAreaRect = handleArea.GetComponent<RectTransform>();
|
||||
handleAreaRect.sizeDelta = new Vector2(-20, 0);
|
||||
handleAreaRect.anchorMin = new Vector2(0, 0);
|
||||
handleAreaRect.anchorMax = new Vector2(1, 1);
|
||||
|
||||
// Handle
|
||||
Image handleImage = handle.GetComponent<Image>();
|
||||
handleImage.sprite = resources.knob;
|
||||
handleImage.color = s_DefaultSelectableColor;
|
||||
|
||||
RectTransform handleRect = handle.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(20, 0);
|
||||
|
||||
// Setup slider component
|
||||
Slider slider = root.GetComponent<Slider>();
|
||||
slider.fillRect = fill.GetComponent<RectTransform>();
|
||||
slider.handleRect = handle.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.LeftToRight;
|
||||
SetDefaultColorTransitionValues(slider);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Scrollbar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Scrollbar
|
||||
/// - Sliding Area
|
||||
/// - Handle
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateScrollbar(Resources resources)
|
||||
{
|
||||
// Create GOs Hierarchy
|
||||
GameObject scrollbarRoot = CreateUIElementRoot("Scrollbar", s_ThinElementSize, typeof(Image), typeof(Scrollbar));
|
||||
|
||||
GameObject sliderArea = CreateUIObject("Sliding Area", scrollbarRoot, typeof(RectTransform));
|
||||
GameObject handle = CreateUIObject("Handle", sliderArea, typeof(Image));
|
||||
|
||||
Image bgImage = scrollbarRoot.GetComponent<Image>();
|
||||
bgImage.sprite = resources.background;
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = s_DefaultSelectableColor;
|
||||
|
||||
Image handleImage = handle.GetComponent<Image>();
|
||||
handleImage.sprite = resources.standard;
|
||||
handleImage.type = Image.Type.Sliced;
|
||||
handleImage.color = s_DefaultSelectableColor;
|
||||
|
||||
RectTransform sliderAreaRect = sliderArea.GetComponent<RectTransform>();
|
||||
sliderAreaRect.sizeDelta = new Vector2(-20, -20);
|
||||
sliderAreaRect.anchorMin = Vector2.zero;
|
||||
sliderAreaRect.anchorMax = Vector2.one;
|
||||
|
||||
RectTransform handleRect = handle.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(20, 20);
|
||||
|
||||
Scrollbar scrollbar = scrollbarRoot.GetComponent<Scrollbar>();
|
||||
scrollbar.handleRect = handleRect;
|
||||
scrollbar.targetGraphic = handleImage;
|
||||
SetDefaultColorTransitionValues(scrollbar);
|
||||
|
||||
return scrollbarRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Toggle.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Toggle
|
||||
/// - Background
|
||||
/// - Checkmark
|
||||
/// - Label
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateToggle(Resources resources)
|
||||
{
|
||||
// Set up hierarchy
|
||||
GameObject toggleRoot = CreateUIElementRoot("Toggle", s_ThinElementSize, typeof(Toggle));
|
||||
|
||||
GameObject background = CreateUIObject("Background", toggleRoot, typeof(Image));
|
||||
GameObject checkmark = CreateUIObject("Checkmark", background, typeof(Image));
|
||||
GameObject childLabel = CreateUIObject("Label", toggleRoot, typeof(Text));
|
||||
|
||||
// Set up components
|
||||
Toggle toggle = toggleRoot.GetComponent<Toggle>();
|
||||
toggle.isOn = true;
|
||||
|
||||
Image bgImage = background.GetComponent<Image>();
|
||||
bgImage.sprite = resources.standard;
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = s_DefaultSelectableColor;
|
||||
|
||||
Image checkmarkImage = checkmark.GetComponent<Image>();
|
||||
checkmarkImage.sprite = resources.checkmark;
|
||||
|
||||
Text label = childLabel.GetComponent<Text>();
|
||||
label.text = "Toggle";
|
||||
SetDefaultTextValues(label);
|
||||
|
||||
toggle.graphic = checkmarkImage;
|
||||
toggle.targetGraphic = bgImage;
|
||||
SetDefaultColorTransitionValues(toggle);
|
||||
|
||||
RectTransform bgRect = background.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = new Vector2(0f, 1f);
|
||||
bgRect.anchorMax = new Vector2(0f, 1f);
|
||||
bgRect.anchoredPosition = new Vector2(10f, -10f);
|
||||
bgRect.sizeDelta = new Vector2(kThinHeight, kThinHeight);
|
||||
|
||||
RectTransform checkmarkRect = checkmark.GetComponent<RectTransform>();
|
||||
checkmarkRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
checkmarkRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
checkmarkRect.anchoredPosition = Vector2.zero;
|
||||
checkmarkRect.sizeDelta = new Vector2(20f, 20f);
|
||||
|
||||
RectTransform labelRect = childLabel.GetComponent<RectTransform>();
|
||||
labelRect.anchorMin = new Vector2(0f, 0f);
|
||||
labelRect.anchorMax = new Vector2(1f, 1f);
|
||||
labelRect.offsetMin = new Vector2(23f, 1f);
|
||||
labelRect.offsetMax = new Vector2(-5f, -2f);
|
||||
|
||||
return toggleRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI input field.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// InputField
|
||||
/// - PlaceHolder
|
||||
/// - Text
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateInputField(Resources resources)
|
||||
{
|
||||
GameObject root = CreateUIElementRoot("InputField", s_ThickElementSize, typeof(Image), typeof(InputField));
|
||||
|
||||
GameObject childPlaceholder = CreateUIObject("Placeholder", root, typeof(Text));
|
||||
GameObject childText = CreateUIObject("Text", root, typeof(Text));
|
||||
|
||||
Image image = root.GetComponent<Image>();
|
||||
image.sprite = resources.inputField;
|
||||
image.type = Image.Type.Sliced;
|
||||
image.color = s_DefaultSelectableColor;
|
||||
|
||||
InputField inputField = root.GetComponent<InputField>();
|
||||
SetDefaultColorTransitionValues(inputField);
|
||||
|
||||
Text text = childText.GetComponent<Text>();
|
||||
text.text = "";
|
||||
text.supportRichText = false;
|
||||
SetDefaultTextValues(text);
|
||||
|
||||
Text placeholder = childPlaceholder.GetComponent<Text>();
|
||||
placeholder.text = "Enter text...";
|
||||
placeholder.fontStyle = FontStyle.Italic;
|
||||
// Make placeholder color half as opaque as normal text color.
|
||||
Color placeholderColor = text.color;
|
||||
placeholderColor.a *= 0.5f;
|
||||
placeholder.color = placeholderColor;
|
||||
|
||||
RectTransform textRectTransform = childText.GetComponent<RectTransform>();
|
||||
textRectTransform.anchorMin = Vector2.zero;
|
||||
textRectTransform.anchorMax = Vector2.one;
|
||||
textRectTransform.sizeDelta = Vector2.zero;
|
||||
textRectTransform.offsetMin = new Vector2(10, 6);
|
||||
textRectTransform.offsetMax = new Vector2(-10, -7);
|
||||
|
||||
RectTransform placeholderRectTransform = childPlaceholder.GetComponent<RectTransform>();
|
||||
placeholderRectTransform.anchorMin = Vector2.zero;
|
||||
placeholderRectTransform.anchorMax = Vector2.one;
|
||||
placeholderRectTransform.sizeDelta = Vector2.zero;
|
||||
placeholderRectTransform.offsetMin = new Vector2(10, 6);
|
||||
placeholderRectTransform.offsetMax = new Vector2(-10, -7);
|
||||
|
||||
inputField.textComponent = text;
|
||||
inputField.placeholder = placeholder;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI dropdown.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Dropdown
|
||||
/// - Label
|
||||
/// - Arrow
|
||||
/// - Template
|
||||
/// - Viewport
|
||||
/// - Content
|
||||
/// - Item
|
||||
/// - Item Background
|
||||
/// - Item Checkmark
|
||||
/// - Item Label
|
||||
/// - Scrollbar
|
||||
/// - Sliding Area
|
||||
/// - Handle
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateDropdown(Resources resources)
|
||||
{
|
||||
GameObject root = CreateUIElementRoot("Dropdown", s_ThickElementSize, typeof(Image), typeof(Dropdown));
|
||||
|
||||
GameObject label = CreateUIObject("Label", root, typeof(Text));
|
||||
GameObject arrow = CreateUIObject("Arrow", root, typeof(Image));
|
||||
GameObject template = CreateUIObject("Template", root, typeof(Image), typeof(ScrollRect));
|
||||
GameObject viewport = CreateUIObject("Viewport", template, typeof(Image), typeof(Mask));
|
||||
GameObject content = CreateUIObject("Content", viewport, typeof(RectTransform));
|
||||
GameObject item = CreateUIObject("Item", content, typeof(Toggle));
|
||||
GameObject itemBackground = CreateUIObject("Item Background", item, typeof(Image));
|
||||
GameObject itemCheckmark = CreateUIObject("Item Checkmark", item, typeof(Image));
|
||||
GameObject itemLabel = CreateUIObject("Item Label", item, typeof(Text));
|
||||
|
||||
// Sub controls.
|
||||
|
||||
GameObject scrollbar = CreateScrollbar(resources);
|
||||
scrollbar.name = "Scrollbar";
|
||||
SetParentAndAlign(scrollbar, template);
|
||||
|
||||
Scrollbar scrollbarScrollbar = scrollbar.GetComponent<Scrollbar>();
|
||||
scrollbarScrollbar.SetDirection(Scrollbar.Direction.BottomToTop, true);
|
||||
|
||||
RectTransform vScrollbarRT = scrollbar.GetComponent<RectTransform>();
|
||||
vScrollbarRT.anchorMin = Vector2.right;
|
||||
vScrollbarRT.anchorMax = Vector2.one;
|
||||
vScrollbarRT.pivot = Vector2.one;
|
||||
vScrollbarRT.sizeDelta = new Vector2(vScrollbarRT.sizeDelta.x, 0);
|
||||
|
||||
// Setup item UI components.
|
||||
|
||||
Text itemLabelText = itemLabel.GetComponent<Text>();
|
||||
SetDefaultTextValues(itemLabelText);
|
||||
itemLabelText.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
Image itemBackgroundImage = itemBackground.GetComponent<Image>();
|
||||
itemBackgroundImage.color = new Color32(245, 245, 245, 255);
|
||||
|
||||
Image itemCheckmarkImage = itemCheckmark.GetComponent<Image>();
|
||||
itemCheckmarkImage.sprite = resources.checkmark;
|
||||
|
||||
Toggle itemToggle = item.GetComponent<Toggle>();
|
||||
itemToggle.targetGraphic = itemBackgroundImage;
|
||||
itemToggle.graphic = itemCheckmarkImage;
|
||||
itemToggle.isOn = true;
|
||||
|
||||
// Setup template UI components.
|
||||
|
||||
Image templateImage = template.GetComponent<Image>();
|
||||
templateImage.sprite = resources.standard;
|
||||
templateImage.type = Image.Type.Sliced;
|
||||
|
||||
ScrollRect templateScrollRect = template.GetComponent<ScrollRect>();
|
||||
templateScrollRect.content = content.GetComponent<RectTransform>();
|
||||
templateScrollRect.viewport = viewport.GetComponent<RectTransform>();
|
||||
templateScrollRect.horizontal = false;
|
||||
templateScrollRect.movementType = ScrollRect.MovementType.Clamped;
|
||||
templateScrollRect.verticalScrollbar = scrollbarScrollbar;
|
||||
templateScrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
templateScrollRect.verticalScrollbarSpacing = -3;
|
||||
|
||||
Mask scrollRectMask = viewport.GetComponent<Mask>();
|
||||
scrollRectMask.showMaskGraphic = false;
|
||||
|
||||
Image viewportImage = viewport.GetComponent<Image>();
|
||||
viewportImage.sprite = resources.mask;
|
||||
viewportImage.type = Image.Type.Sliced;
|
||||
|
||||
// Setup dropdown UI components.
|
||||
|
||||
Text labelText = label.GetComponent<Text>();
|
||||
SetDefaultTextValues(labelText);
|
||||
labelText.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
Image arrowImage = arrow.GetComponent<Image>();
|
||||
arrowImage.sprite = resources.dropdown;
|
||||
|
||||
Image backgroundImage = root.GetComponent<Image>();
|
||||
backgroundImage.sprite = resources.standard;
|
||||
backgroundImage.color = s_DefaultSelectableColor;
|
||||
backgroundImage.type = Image.Type.Sliced;
|
||||
|
||||
Dropdown dropdown = root.GetComponent<Dropdown>();
|
||||
dropdown.targetGraphic = backgroundImage;
|
||||
SetDefaultColorTransitionValues(dropdown);
|
||||
dropdown.template = template.GetComponent<RectTransform>();
|
||||
dropdown.captionText = labelText;
|
||||
dropdown.itemText = itemLabelText;
|
||||
|
||||
// Setting default Item list.
|
||||
itemLabelText.text = "Option A";
|
||||
dropdown.options.Add(new Dropdown.OptionData {text = "Option A"});
|
||||
dropdown.options.Add(new Dropdown.OptionData {text = "Option B"});
|
||||
dropdown.options.Add(new Dropdown.OptionData {text = "Option C"});
|
||||
dropdown.RefreshShownValue();
|
||||
|
||||
// Set up RectTransforms.
|
||||
|
||||
RectTransform labelRT = label.GetComponent<RectTransform>();
|
||||
labelRT.anchorMin = Vector2.zero;
|
||||
labelRT.anchorMax = Vector2.one;
|
||||
labelRT.offsetMin = new Vector2(10, 6);
|
||||
labelRT.offsetMax = new Vector2(-25, -7);
|
||||
|
||||
RectTransform arrowRT = arrow.GetComponent<RectTransform>();
|
||||
arrowRT.anchorMin = new Vector2(1, 0.5f);
|
||||
arrowRT.anchorMax = new Vector2(1, 0.5f);
|
||||
arrowRT.sizeDelta = new Vector2(20, 20);
|
||||
arrowRT.anchoredPosition = new Vector2(-15, 0);
|
||||
|
||||
RectTransform templateRT = template.GetComponent<RectTransform>();
|
||||
templateRT.anchorMin = new Vector2(0, 0);
|
||||
templateRT.anchorMax = new Vector2(1, 0);
|
||||
templateRT.pivot = new Vector2(0.5f, 1);
|
||||
templateRT.anchoredPosition = new Vector2(0, 2);
|
||||
templateRT.sizeDelta = new Vector2(0, 150);
|
||||
|
||||
RectTransform viewportRT = viewport.GetComponent<RectTransform>();
|
||||
viewportRT.anchorMin = new Vector2(0, 0);
|
||||
viewportRT.anchorMax = new Vector2(1, 1);
|
||||
viewportRT.sizeDelta = new Vector2(-18, 0);
|
||||
viewportRT.pivot = new Vector2(0, 1);
|
||||
|
||||
RectTransform contentRT = content.GetComponent<RectTransform>();
|
||||
contentRT.anchorMin = new Vector2(0f, 1);
|
||||
contentRT.anchorMax = new Vector2(1f, 1);
|
||||
contentRT.pivot = new Vector2(0.5f, 1);
|
||||
contentRT.anchoredPosition = new Vector2(0, 0);
|
||||
contentRT.sizeDelta = new Vector2(0, 28);
|
||||
|
||||
RectTransform itemRT = item.GetComponent<RectTransform>();
|
||||
itemRT.anchorMin = new Vector2(0, 0.5f);
|
||||
itemRT.anchorMax = new Vector2(1, 0.5f);
|
||||
itemRT.sizeDelta = new Vector2(0, 20);
|
||||
|
||||
RectTransform itemBackgroundRT = itemBackground.GetComponent<RectTransform>();
|
||||
itemBackgroundRT.anchorMin = Vector2.zero;
|
||||
itemBackgroundRT.anchorMax = Vector2.one;
|
||||
itemBackgroundRT.sizeDelta = Vector2.zero;
|
||||
|
||||
RectTransform itemCheckmarkRT = itemCheckmark.GetComponent<RectTransform>();
|
||||
itemCheckmarkRT.anchorMin = new Vector2(0, 0.5f);
|
||||
itemCheckmarkRT.anchorMax = new Vector2(0, 0.5f);
|
||||
itemCheckmarkRT.sizeDelta = new Vector2(20, 20);
|
||||
itemCheckmarkRT.anchoredPosition = new Vector2(10, 0);
|
||||
|
||||
RectTransform itemLabelRT = itemLabel.GetComponent<RectTransform>();
|
||||
itemLabelRT.anchorMin = Vector2.zero;
|
||||
itemLabelRT.anchorMax = Vector2.one;
|
||||
itemLabelRT.offsetMin = new Vector2(20, 1);
|
||||
itemLabelRT.offsetMax = new Vector2(-10, -2);
|
||||
|
||||
template.SetActive(false);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the basic UI Scrollview.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Hierarchy:
|
||||
/// (root)
|
||||
/// Scrollview
|
||||
/// - Viewport
|
||||
/// - Content
|
||||
/// - Scrollbar Horizontal
|
||||
/// - Sliding Area
|
||||
/// - Handle
|
||||
/// - Scrollbar Vertical
|
||||
/// - Sliding Area
|
||||
/// - Handle
|
||||
/// </remarks>
|
||||
/// <param name="resources">The resources to use for creation.</param>
|
||||
/// <returns>The root GameObject of the created element.</returns>
|
||||
public static GameObject CreateScrollView(Resources resources)
|
||||
{
|
||||
GameObject root = CreateUIElementRoot("Scroll View", new Vector2(200, 200), typeof(Image), typeof(ScrollRect));
|
||||
|
||||
GameObject viewport = CreateUIObject("Viewport", root, typeof(Image), typeof(Mask));
|
||||
GameObject content = CreateUIObject("Content", viewport, typeof(RectTransform));
|
||||
|
||||
// Sub controls.
|
||||
|
||||
GameObject hScrollbar = CreateScrollbar(resources);
|
||||
hScrollbar.name = "Scrollbar Horizontal";
|
||||
SetParentAndAlign(hScrollbar, root);
|
||||
RectTransform hScrollbarRT = hScrollbar.GetComponent<RectTransform>();
|
||||
hScrollbarRT.anchorMin = Vector2.zero;
|
||||
hScrollbarRT.anchorMax = Vector2.right;
|
||||
hScrollbarRT.pivot = Vector2.zero;
|
||||
hScrollbarRT.sizeDelta = new Vector2(0, hScrollbarRT.sizeDelta.y);
|
||||
|
||||
GameObject vScrollbar = CreateScrollbar(resources);
|
||||
vScrollbar.name = "Scrollbar Vertical";
|
||||
SetParentAndAlign(vScrollbar, root);
|
||||
vScrollbar.GetComponent<Scrollbar>().SetDirection(Scrollbar.Direction.BottomToTop, true);
|
||||
RectTransform vScrollbarRT = vScrollbar.GetComponent<RectTransform>();
|
||||
vScrollbarRT.anchorMin = Vector2.right;
|
||||
vScrollbarRT.anchorMax = Vector2.one;
|
||||
vScrollbarRT.pivot = Vector2.one;
|
||||
vScrollbarRT.sizeDelta = new Vector2(vScrollbarRT.sizeDelta.x, 0);
|
||||
|
||||
// Setup RectTransforms.
|
||||
|
||||
// Make viewport fill entire scroll view.
|
||||
RectTransform viewportRT = viewport.GetComponent<RectTransform>();
|
||||
viewportRT.anchorMin = Vector2.zero;
|
||||
viewportRT.anchorMax = Vector2.one;
|
||||
viewportRT.sizeDelta = Vector2.zero;
|
||||
viewportRT.pivot = Vector2.up;
|
||||
|
||||
// Make context match viewpoprt width and be somewhat taller.
|
||||
// This will show the vertical scrollbar and not the horizontal one.
|
||||
RectTransform contentRT = content.GetComponent<RectTransform>();
|
||||
contentRT.anchorMin = Vector2.up;
|
||||
contentRT.anchorMax = Vector2.one;
|
||||
contentRT.sizeDelta = new Vector2(0, 300);
|
||||
contentRT.pivot = Vector2.up;
|
||||
|
||||
// Setup UI components.
|
||||
|
||||
ScrollRect scrollRect = root.GetComponent<ScrollRect>();
|
||||
scrollRect.content = contentRT;
|
||||
scrollRect.viewport = viewportRT;
|
||||
scrollRect.horizontalScrollbar = hScrollbar.GetComponent<Scrollbar>();
|
||||
scrollRect.verticalScrollbar = vScrollbar.GetComponent<Scrollbar>();
|
||||
scrollRect.horizontalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
scrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
scrollRect.horizontalScrollbarSpacing = -3;
|
||||
scrollRect.verticalScrollbarSpacing = -3;
|
||||
|
||||
Image rootImage = root.GetComponent<Image>();
|
||||
rootImage.sprite = resources.background;
|
||||
rootImage.type = Image.Type.Sliced;
|
||||
rootImage.color = s_PanelColor;
|
||||
|
||||
Mask viewportMask = viewport.GetComponent<Mask>();
|
||||
viewportMask.showMaskGraphic = false;
|
||||
|
||||
Image viewportImage = viewport.GetComponent<Image>();
|
||||
viewportImage.sprite = resources.mask;
|
||||
viewportImage.type = Image.Type.Sliced;
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bf87e20fb5440ec498f441167b5291f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d0b652f32a2cc243917e4028fa0f046
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,199 @@
|
|||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// Struct for storing Text generation settings.
|
||||
/// </summary>
|
||||
public class FontData : ISerializationCallbackReceiver
|
||||
{
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("font")]
|
||||
private Font m_Font;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("fontSize")]
|
||||
private int m_FontSize;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("fontStyle")]
|
||||
private FontStyle m_FontStyle;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_BestFit;
|
||||
|
||||
[SerializeField]
|
||||
private int m_MinSize;
|
||||
|
||||
[SerializeField]
|
||||
private int m_MaxSize;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("alignment")]
|
||||
private TextAnchor m_Alignment;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_AlignByGeometry;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("richText")]
|
||||
private bool m_RichText;
|
||||
|
||||
[SerializeField]
|
||||
private HorizontalWrapMode m_HorizontalOverflow;
|
||||
|
||||
[SerializeField]
|
||||
private VerticalWrapMode m_VerticalOverflow;
|
||||
|
||||
[SerializeField]
|
||||
private float m_LineSpacing;
|
||||
|
||||
/// <summary>
|
||||
/// Get a font data with sensible defaults.
|
||||
/// </summary>
|
||||
public static FontData defaultFontData
|
||||
{
|
||||
get
|
||||
{
|
||||
var fontData = new FontData
|
||||
{
|
||||
m_FontSize = 14,
|
||||
m_LineSpacing = 1f,
|
||||
m_FontStyle = FontStyle.Normal,
|
||||
m_BestFit = false,
|
||||
m_MinSize = 10,
|
||||
m_MaxSize = 40,
|
||||
m_Alignment = TextAnchor.UpperLeft,
|
||||
m_HorizontalOverflow = HorizontalWrapMode.Wrap,
|
||||
m_VerticalOverflow = VerticalWrapMode.Truncate,
|
||||
m_RichText = true,
|
||||
m_AlignByGeometry = false
|
||||
};
|
||||
return fontData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Font to use for this generated Text object.
|
||||
/// </summary>
|
||||
public Font font
|
||||
{
|
||||
get { return m_Font; }
|
||||
set { m_Font = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Font size to use for this generated Text object.
|
||||
/// </summary>
|
||||
public int fontSize
|
||||
{
|
||||
get { return m_FontSize; }
|
||||
set { m_FontSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The font style to use for this generated Text object.
|
||||
/// </summary>
|
||||
public FontStyle fontStyle
|
||||
{
|
||||
get { return m_FontStyle; }
|
||||
set { m_FontStyle = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is best fit used for this generated Text object.
|
||||
/// </summary>
|
||||
public bool bestFit
|
||||
{
|
||||
get { return m_BestFit; }
|
||||
set { m_BestFit = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The min size for this generated Text object.
|
||||
/// </summary>
|
||||
public int minSize
|
||||
{
|
||||
get { return m_MinSize; }
|
||||
set { m_MinSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The max size for this generated Text object.
|
||||
/// </summary>
|
||||
public int maxSize
|
||||
{
|
||||
get { return m_MaxSize; }
|
||||
set { m_MaxSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How is the text aligned for this generated Text object.
|
||||
/// </summary>
|
||||
public TextAnchor alignment
|
||||
{
|
||||
get { return m_Alignment; }
|
||||
set { m_Alignment = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the extents of glyph geometry to perform horizontal alignment rather than glyph metrics.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This can result in better fitting left and right alignment, but may result in incorrect positioning when attempting to overlay multiple fonts (such as a specialized outline font) on top of each other.
|
||||
/// </remarks>
|
||||
public bool alignByGeometry
|
||||
{
|
||||
get { return m_AlignByGeometry; }
|
||||
set { m_AlignByGeometry = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should rich text be used for this generated Text object.
|
||||
/// </summary>
|
||||
public bool richText
|
||||
{
|
||||
get { return m_RichText; }
|
||||
set { m_RichText = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The horizontal overflow policy for this generated Text object.
|
||||
/// </summary>
|
||||
public HorizontalWrapMode horizontalOverflow
|
||||
{
|
||||
get { return m_HorizontalOverflow; }
|
||||
set { m_HorizontalOverflow = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The vertical overflow policy for this generated Text object.
|
||||
/// </summary>
|
||||
public VerticalWrapMode verticalOverflow
|
||||
{
|
||||
get { return m_VerticalOverflow; }
|
||||
set { m_VerticalOverflow = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The line spaceing for this generated Text object.
|
||||
/// </summary>
|
||||
public float lineSpacing
|
||||
{
|
||||
get { return m_LineSpacing; }
|
||||
set { m_LineSpacing = value; }
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
||||
{}
|
||||
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
m_FontSize = Mathf.Clamp(m_FontSize, 0, 300);
|
||||
m_MinSize = Mathf.Clamp(m_MinSize, 0, m_FontSize);
|
||||
m_MaxSize = Mathf.Clamp(m_MaxSize, m_FontSize, 300);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13cd966480ec3354bb318ee1aeccff6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class that is used to help with Text update.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When Unity rebuilds a font atlas a callback is sent to the font. Using this class you can register your text as needing to be rebuilt if the font atlas is updated.
|
||||
/// </remarks>
|
||||
public static class FontUpdateTracker
|
||||
{
|
||||
static Dictionary<Font, HashSet<Text>> m_Tracked = new Dictionary<Font, HashSet<Text>>();
|
||||
|
||||
/// <summary>
|
||||
/// Register a Text element for receiving texture atlas rebuild calls.
|
||||
/// </summary>
|
||||
/// <param name="t">The Text object to track</param>
|
||||
public static void TrackText(Text t)
|
||||
{
|
||||
if (t.font == null)
|
||||
return;
|
||||
|
||||
HashSet<Text> exists;
|
||||
m_Tracked.TryGetValue(t.font, out exists);
|
||||
if (exists == null)
|
||||
{
|
||||
// The textureRebuilt event is global for all fonts, so we add our delegate the first time we register *any* Text
|
||||
if (m_Tracked.Count == 0)
|
||||
Font.textureRebuilt += RebuildForFont;
|
||||
|
||||
exists = new HashSet<Text>();
|
||||
m_Tracked.Add(t.font, exists);
|
||||
}
|
||||
exists.Add(t);
|
||||
}
|
||||
|
||||
private static void RebuildForFont(Font f)
|
||||
{
|
||||
HashSet<Text> texts;
|
||||
m_Tracked.TryGetValue(f, out texts);
|
||||
|
||||
if (texts == null)
|
||||
return;
|
||||
|
||||
foreach (var text in texts)
|
||||
text.FontTextureChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deregister a Text element from receiving texture atlas rebuild calls.
|
||||
/// </summary>
|
||||
/// <param name="t">The Text object to no longer track</param>
|
||||
public static void UntrackText(Text t)
|
||||
{
|
||||
if (t.font == null)
|
||||
return;
|
||||
|
||||
HashSet<Text> texts;
|
||||
m_Tracked.TryGetValue(t.font, out texts);
|
||||
|
||||
if (texts == null)
|
||||
return;
|
||||
|
||||
texts.Remove(t);
|
||||
|
||||
if (texts.Count == 0)
|
||||
{
|
||||
m_Tracked.Remove(t.font);
|
||||
|
||||
// There is a global textureRebuilt event for all fonts, so once the last Text reference goes away, remove our delegate
|
||||
if (m_Tracked.Count == 0)
|
||||
Font.textureRebuilt -= RebuildForFont;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 39ab466162988eb4f83443f911bbf5c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,977 @@
|
|||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI.CoroutineTween;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all UI components that should be derived from when creating new Graphic types.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[ExecuteAlways]
|
||||
/// <summary>
|
||||
/// Base class for all visual UI Component.
|
||||
/// When creating visual UI components you should inherit from this class.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// Below is a simple example that draws a colored quad inside the Rect Transform area.
|
||||
/// <code>
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.UI;
|
||||
///
|
||||
/// [ExecuteInEditMode]
|
||||
/// public class SimpleImage : Graphic
|
||||
/// {
|
||||
/// protected override void OnPopulateMesh(VertexHelper vh)
|
||||
/// {
|
||||
/// Vector2 corner1 = Vector2.zero;
|
||||
/// Vector2 corner2 = Vector2.zero;
|
||||
///
|
||||
/// corner1.x = 0f;
|
||||
/// corner1.y = 0f;
|
||||
/// corner2.x = 1f;
|
||||
/// corner2.y = 1f;
|
||||
///
|
||||
/// corner1.x -= rectTransform.pivot.x;
|
||||
/// corner1.y -= rectTransform.pivot.y;
|
||||
/// corner2.x -= rectTransform.pivot.x;
|
||||
/// corner2.y -= rectTransform.pivot.y;
|
||||
///
|
||||
/// corner1.x *= rectTransform.rect.width;
|
||||
/// corner1.y *= rectTransform.rect.height;
|
||||
/// corner2.x *= rectTransform.rect.width;
|
||||
/// corner2.y *= rectTransform.rect.height;
|
||||
///
|
||||
/// vh.Clear();
|
||||
///
|
||||
/// UIVertex vert = UIVertex.simpleVert;
|
||||
///
|
||||
/// vert.position = new Vector2(corner1.x, corner1.y);
|
||||
/// vert.color = color;
|
||||
/// vh.AddVert(vert);
|
||||
///
|
||||
/// vert.position = new Vector2(corner1.x, corner2.y);
|
||||
/// vert.color = color;
|
||||
/// vh.AddVert(vert);
|
||||
///
|
||||
/// vert.position = new Vector2(corner2.x, corner2.y);
|
||||
/// vert.color = color;
|
||||
/// vh.AddVert(vert);
|
||||
///
|
||||
/// vert.position = new Vector2(corner2.x, corner1.y);
|
||||
/// vert.color = color;
|
||||
/// vh.AddVert(vert);
|
||||
///
|
||||
/// vh.AddTriangle(0, 1, 2);
|
||||
/// vh.AddTriangle(2, 3, 0);
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public abstract class Graphic
|
||||
: UIBehaviour,
|
||||
ICanvasElement
|
||||
{
|
||||
static protected Material s_DefaultUI = null;
|
||||
static protected Texture2D s_WhiteTexture = null;
|
||||
|
||||
/// <summary>
|
||||
/// Default material used to draw UI elements if no explicit material was specified.
|
||||
/// </summary>
|
||||
|
||||
static public Material defaultGraphicMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_DefaultUI == null)
|
||||
s_DefaultUI = Canvas.GetDefaultCanvasMaterial();
|
||||
return s_DefaultUI;
|
||||
}
|
||||
}
|
||||
|
||||
// Cached and saved values
|
||||
[FormerlySerializedAs("m_Mat")]
|
||||
[SerializeField] protected Material m_Material;
|
||||
|
||||
[SerializeField] private Color m_Color = Color.white;
|
||||
|
||||
[NonSerialized] protected bool m_SkipLayoutUpdate;
|
||||
[NonSerialized] protected bool m_SkipMaterialUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Base color of the Graphic.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The builtin UI Components use this as their vertex color. Use this to fetch or change the Color of visual UI elements, such as an Image.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// //Place this script on a GameObject with a Graphic component attached e.g. a visual UI element (Image).
|
||||
///
|
||||
/// using UnityEngine;
|
||||
/// using UnityEngine.UI;
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// Graphic m_Graphic;
|
||||
/// Color m_MyColor;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// //Fetch the Graphic from the GameObject
|
||||
/// m_Graphic = GetComponent<Graphic>();
|
||||
/// //Create a new Color that starts as red
|
||||
/// m_MyColor = Color.red;
|
||||
/// //Change the Graphic Color to the new Color
|
||||
/// m_Graphic.color = m_MyColor;
|
||||
/// }
|
||||
///
|
||||
/// // Update is called once per frame
|
||||
/// void Update()
|
||||
/// {
|
||||
/// //When the mouse button is clicked, change the Graphic Color
|
||||
/// if (Input.GetKey(KeyCode.Mouse0))
|
||||
/// {
|
||||
/// //Change the Color over time between blue and red while the mouse button is pressed
|
||||
/// m_MyColor = Color.Lerp(Color.red, Color.blue, Mathf.PingPong(Time.time, 1));
|
||||
/// }
|
||||
/// //Change the Graphic Color to the new Color
|
||||
/// m_Graphic.color = m_MyColor;
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } }
|
||||
|
||||
[SerializeField] private bool m_RaycastTarget = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should this graphic be considered a target for raycasting?
|
||||
/// </summary>
|
||||
public virtual bool raycastTarget { get { return m_RaycastTarget; } set { m_RaycastTarget = value; } }
|
||||
|
||||
[NonSerialized] private RectTransform m_RectTransform;
|
||||
[NonSerialized] private CanvasRenderer m_CanvasRenderer;
|
||||
[NonSerialized] private Canvas m_Canvas;
|
||||
|
||||
[NonSerialized] private bool m_VertsDirty;
|
||||
[NonSerialized] private bool m_MaterialDirty;
|
||||
|
||||
[NonSerialized] protected UnityAction m_OnDirtyLayoutCallback;
|
||||
[NonSerialized] protected UnityAction m_OnDirtyVertsCallback;
|
||||
[NonSerialized] protected UnityAction m_OnDirtyMaterialCallback;
|
||||
|
||||
[NonSerialized] protected static Mesh s_Mesh;
|
||||
[NonSerialized] private static readonly VertexHelper s_VertexHelper = new VertexHelper();
|
||||
|
||||
[NonSerialized] protected Mesh m_CachedMesh;
|
||||
[NonSerialized] protected Vector2[] m_CachedUvs;
|
||||
// Tween controls for the Graphic
|
||||
[NonSerialized]
|
||||
private readonly TweenRunner<ColorTween> m_ColorTweenRunner;
|
||||
|
||||
protected bool useLegacyMeshGeneration { get; set; }
|
||||
|
||||
// Called by Unity prior to deserialization,
|
||||
// should not be called by users
|
||||
protected Graphic()
|
||||
{
|
||||
if (m_ColorTweenRunner == null)
|
||||
m_ColorTweenRunner = new TweenRunner<ColorTween>();
|
||||
m_ColorTweenRunner.Init(this);
|
||||
useLegacyMeshGeneration = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set all properties of the Graphic dirty and needing rebuilt.
|
||||
/// Dirties Layout, Vertices, and Materials.
|
||||
/// </summary>
|
||||
public virtual void SetAllDirty()
|
||||
{
|
||||
// Optimization: Graphic layout doesn't need recalculation if
|
||||
// the underlying Sprite is the same size with the same texture.
|
||||
// (e.g. Sprite sheet texture animation)
|
||||
|
||||
if (m_SkipLayoutUpdate)
|
||||
{
|
||||
m_SkipLayoutUpdate = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLayoutDirty();
|
||||
}
|
||||
|
||||
if (m_SkipMaterialUpdate)
|
||||
{
|
||||
m_SkipMaterialUpdate = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMaterialDirty();
|
||||
}
|
||||
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the layout as dirty and needing rebuilt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Send a OnDirtyLayoutCallback notification if any elements are registered. See RegisterDirtyLayoutCallback
|
||||
/// </remarks>
|
||||
public virtual void SetLayoutDirty()
|
||||
{
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
|
||||
|
||||
if (m_OnDirtyLayoutCallback != null)
|
||||
m_OnDirtyLayoutCallback();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the vertices as dirty and needing rebuilt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Send a OnDirtyVertsCallback notification if any elements are registered. See RegisterDirtyVerticesCallback
|
||||
/// </remarks>
|
||||
public virtual void SetVerticesDirty()
|
||||
{
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
m_VertsDirty = true;
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
|
||||
|
||||
if (m_OnDirtyVertsCallback != null)
|
||||
m_OnDirtyVertsCallback();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the material as dirty and needing rebuilt.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Send a OnDirtyMaterialCallback notification if any elements are registered. See RegisterDirtyMaterialCallback
|
||||
/// </remarks>
|
||||
public virtual void SetMaterialDirty()
|
||||
{
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
m_MaterialDirty = true;
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
|
||||
|
||||
if (m_OnDirtyMaterialCallback != null)
|
||||
m_OnDirtyMaterialCallback();
|
||||
}
|
||||
|
||||
protected override void OnRectTransformDimensionsChange()
|
||||
{
|
||||
if (gameObject.activeInHierarchy)
|
||||
{
|
||||
// prevent double dirtying...
|
||||
if (CanvasUpdateRegistry.IsRebuildingLayout())
|
||||
SetVerticesDirty();
|
||||
else
|
||||
{
|
||||
SetVerticesDirty();
|
||||
SetLayoutDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnBeforeTransformParentChanged()
|
||||
{
|
||||
GraphicRegistry.UnregisterGraphicForCanvas(canvas, this);
|
||||
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
|
||||
}
|
||||
|
||||
protected override void OnTransformParentChanged()
|
||||
{
|
||||
base.OnTransformParentChanged();
|
||||
|
||||
m_Canvas = null;
|
||||
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
CacheCanvas();
|
||||
GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Absolute depth of the graphic, used by rendering and events -- lowest to highest.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The depth is relative to the first root canvas.
|
||||
///
|
||||
/// Canvas
|
||||
/// Graphic - 1
|
||||
/// Graphic - 2
|
||||
/// Nested Canvas
|
||||
/// Graphic - 3
|
||||
/// Graphic - 4
|
||||
/// Graphic - 5
|
||||
///
|
||||
/// This value is used to determine draw and event ordering.
|
||||
/// </example>
|
||||
public int depth { get { return canvasRenderer.absoluteDepth; } }
|
||||
|
||||
/// <summary>
|
||||
/// The RectTransform component used by the Graphic. Cached for speed.
|
||||
/// </summary>
|
||||
public RectTransform rectTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
// The RectTransform is a required component that must not be destroyed. Based on this assumption, a
|
||||
// null-reference check is sufficient.
|
||||
if (ReferenceEquals(m_RectTransform, null))
|
||||
{
|
||||
m_RectTransform = GetComponent<RectTransform>();
|
||||
}
|
||||
return m_RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the Canvas this Graphic is rendering to.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the situation where the Graphic is used in a hierarchy with multiple Canvases, the Canvas closest to the root will be used.
|
||||
/// </remarks>
|
||||
public Canvas canvas
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Canvas == null)
|
||||
CacheCanvas();
|
||||
return m_Canvas;
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheCanvas()
|
||||
{
|
||||
var list = ListPool<Canvas>.Get();
|
||||
gameObject.GetComponentsInParent(false, list);
|
||||
if (list.Count > 0)
|
||||
{
|
||||
// Find the first active and enabled canvas.
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
if (list[i].isActiveAndEnabled)
|
||||
{
|
||||
m_Canvas = list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Canvas = null;
|
||||
}
|
||||
|
||||
ListPool<Canvas>.Release(list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the CanvasRenderer populated by this Graphic.
|
||||
/// </summary>
|
||||
public CanvasRenderer canvasRenderer
|
||||
{
|
||||
get
|
||||
{
|
||||
// The CanvasRenderer is a required component that must not be destroyed. Based on this assumption, a
|
||||
// null-reference check is sufficient.
|
||||
if (ReferenceEquals(m_CanvasRenderer, null))
|
||||
{
|
||||
m_CanvasRenderer = GetComponent<CanvasRenderer>();
|
||||
}
|
||||
return m_CanvasRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default material for the graphic.
|
||||
/// </summary>
|
||||
public virtual Material defaultMaterial
|
||||
{
|
||||
get { return defaultGraphicMaterial; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Material set by the user
|
||||
/// </summary>
|
||||
public virtual Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
return (m_Material != null) ? m_Material : defaultMaterial;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_Material == value)
|
||||
return;
|
||||
|
||||
m_Material = value;
|
||||
SetMaterialDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The material that will be sent for Rendering (Read only).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the material that actually gets sent to the CanvasRenderer. By default it's the same as [[Graphic.material]]. When extending Graphic you can override this to send a different material to the CanvasRenderer than the one set by Graphic.material. This is useful if you want to modify the user set material in a non destructive manner.
|
||||
/// </remarks>
|
||||
public virtual Material materialForRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
var components = ListPool<Component>.Get();
|
||||
GetComponents(typeof(IMaterialModifier), components);
|
||||
|
||||
var currentMat = material;
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
currentMat = (components[i] as IMaterialModifier).GetModifiedMaterial(currentMat);
|
||||
ListPool<Component>.Release(components);
|
||||
return currentMat;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The graphic's texture. (Read Only).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the Texture that gets passed to the CanvasRenderer, Material and then Shader _MainTex.
|
||||
///
|
||||
/// When implementing your own Graphic you can override this to control which texture goes through the UI Rendering pipeline.
|
||||
///
|
||||
/// Bear in mind that Unity tries to batch UI elements together to improve performance, so its ideal to work with atlas to reduce the number of draw calls.
|
||||
/// </remarks>
|
||||
public virtual Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
return s_WhiteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the Graphic and the canvas as having been changed.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
CacheCanvas();
|
||||
GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
GraphicRebuildTracker.TrackGraphic(this);
|
||||
#endif
|
||||
if (s_WhiteTexture == null)
|
||||
s_WhiteTexture = Texture2D.whiteTexture;
|
||||
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear references.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
GraphicRebuildTracker.UnTrackGraphic(this);
|
||||
#endif
|
||||
GraphicRegistry.UnregisterGraphicForCanvas(canvas, this);
|
||||
CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
|
||||
|
||||
if (canvasRenderer != null)
|
||||
canvasRenderer.Clear();
|
||||
|
||||
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
|
||||
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
if (m_CachedMesh)
|
||||
Destroy(m_CachedMesh);
|
||||
m_CachedMesh = null;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
protected override void OnCanvasHierarchyChanged()
|
||||
{
|
||||
// Use m_Cavas so we dont auto call CacheCanvas
|
||||
Canvas currentCanvas = m_Canvas;
|
||||
|
||||
// Clear the cached canvas. Will be fetched below if active.
|
||||
m_Canvas = null;
|
||||
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
CacheCanvas();
|
||||
|
||||
if (currentCanvas != m_Canvas)
|
||||
{
|
||||
GraphicRegistry.UnregisterGraphicForCanvas(currentCanvas, this);
|
||||
|
||||
// Only register if we are active and enabled as OnCanvasHierarchyChanged can get called
|
||||
// during object destruction and we dont want to register ourself and then become null.
|
||||
if (IsActive())
|
||||
GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method must be called when <c>CanvasRenderer.cull</c> is modified.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This can be used to perform operations that were previously skipped because the <c>Graphic</c> was culled.
|
||||
/// </remarks>
|
||||
public virtual void OnCullingChanged()
|
||||
{
|
||||
if (!canvasRenderer.cull && (m_VertsDirty || m_MaterialDirty))
|
||||
{
|
||||
/// When we were culled, we potentially skipped calls to <c>Rebuild</c>.
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the graphic geometry and its material on the PreRender cycle.
|
||||
/// </summary>
|
||||
/// <param name="update">The current step of the rendering CanvasUpdate cycle.</param>
|
||||
/// <remarks>
|
||||
/// See CanvasUpdateRegistry for more details on the canvas update cycle.
|
||||
/// </remarks>
|
||||
public virtual void Rebuild(CanvasUpdate update)
|
||||
{
|
||||
if (canvasRenderer == null || canvasRenderer.cull)
|
||||
return;
|
||||
|
||||
switch (update)
|
||||
{
|
||||
case CanvasUpdate.PreRender:
|
||||
if (m_VertsDirty)
|
||||
{
|
||||
UpdateGeometry();
|
||||
m_VertsDirty = false;
|
||||
}
|
||||
if (m_MaterialDirty)
|
||||
{
|
||||
UpdateMaterial();
|
||||
m_MaterialDirty = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void LayoutComplete()
|
||||
{}
|
||||
|
||||
public virtual void GraphicUpdateComplete()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Call to update the Material of the graphic onto the CanvasRenderer.
|
||||
/// </summary>
|
||||
protected virtual void UpdateMaterial()
|
||||
{
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
canvasRenderer.materialCount = 1;
|
||||
canvasRenderer.SetMaterial(materialForRendering, 0);
|
||||
canvasRenderer.SetTexture(mainTexture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
|
||||
/// </summary>
|
||||
protected virtual void UpdateGeometry()
|
||||
{
|
||||
if (useLegacyMeshGeneration)
|
||||
{
|
||||
DoLegacyMeshGeneration();
|
||||
}
|
||||
else
|
||||
{
|
||||
DoMeshGeneration();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoMeshGeneration()
|
||||
{
|
||||
if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0)
|
||||
OnPopulateMesh(s_VertexHelper);
|
||||
else
|
||||
s_VertexHelper.Clear(); // clear the vertex helper so invalid graphics dont draw.
|
||||
|
||||
var components = ListPool<Component>.Get();
|
||||
GetComponents(typeof(IMeshModifier), components);
|
||||
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
((IMeshModifier)components[i]).ModifyMesh(s_VertexHelper);
|
||||
|
||||
ListPool<Component>.Release(components);
|
||||
|
||||
s_VertexHelper.FillMesh(workerMesh);
|
||||
canvasRenderer.SetMesh(workerMesh);
|
||||
}
|
||||
|
||||
private void DoLegacyMeshGeneration()
|
||||
{
|
||||
if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
OnPopulateMesh(workerMesh);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
else
|
||||
{
|
||||
workerMesh.Clear();
|
||||
}
|
||||
|
||||
var components = ListPool<Component>.Get();
|
||||
GetComponents(typeof(IMeshModifier), components);
|
||||
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
#pragma warning disable 618
|
||||
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
ListPool<Component>.Release(components);
|
||||
canvasRenderer.SetMesh(workerMesh);
|
||||
}
|
||||
|
||||
protected static Mesh workerMesh
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Mesh == null)
|
||||
{
|
||||
s_Mesh = new Mesh();
|
||||
s_Mesh.name = "Shared UI Mesh";
|
||||
s_Mesh.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
return s_Mesh;
|
||||
}
|
||||
}
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
[Obsolete("Use OnPopulateMesh instead.", true)]
|
||||
protected virtual void OnFillVBO(System.Collections.Generic.List<UIVertex> vbo) {}
|
||||
|
||||
[Obsolete("Use OnPopulateMesh(VertexHelper vh) instead.", false)]
|
||||
/// <summary>
|
||||
/// Callback function when a UI element needs to generate vertices. Fills the vertex buffer data.
|
||||
/// </summary>
|
||||
/// <param name="m">Mesh to populate with UI data.</param>
|
||||
/// <remarks>
|
||||
/// Used by Text, UI.Image, and RawImage for example to generate vertices specific to their use case.
|
||||
/// </remarks>
|
||||
protected virtual void OnPopulateMesh(Mesh m)
|
||||
{
|
||||
OnPopulateMesh(s_VertexHelper);
|
||||
s_VertexHelper.FillMesh(m);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback function when a UI element needs to generate vertices. Fills the vertex buffer data.
|
||||
/// </summary>
|
||||
/// <param name="vh">VertexHelper utility.</param>
|
||||
/// <remarks>
|
||||
/// Used by Text, UI.Image, and RawImage for example to generate vertices specific to their use case.
|
||||
/// </remarks>
|
||||
protected virtual void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
var r = GetPixelAdjustedRect();
|
||||
var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);
|
||||
|
||||
Color32 color32 = color;
|
||||
vh.Clear();
|
||||
vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0f, 0f));
|
||||
vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0f, 1f));
|
||||
vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(1f, 1f));
|
||||
vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(1f, 0f));
|
||||
|
||||
vh.AddTriangle(0, 1, 2);
|
||||
vh.AddTriangle(2, 3, 0);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Editor-only callback that is issued by Unity if a rebuild of the Graphic is required.
|
||||
/// Currently sent when an asset is reimported.
|
||||
/// </summary>
|
||||
public virtual void OnRebuildRequested()
|
||||
{
|
||||
// when rebuild is requested we need to rebuild all the graphics /
|
||||
// and associated components... The correct way to do this is by
|
||||
// calling OnValidate... Because MB's don't have a common base class
|
||||
// we do this via reflection. It's nasty and ugly... Editor only.
|
||||
var mbs = gameObject.GetComponents<MonoBehaviour>();
|
||||
foreach (var mb in mbs)
|
||||
{
|
||||
if (mb == null)
|
||||
continue;
|
||||
var methodInfo = mb.GetType().GetMethod("OnValidate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (methodInfo != null)
|
||||
methodInfo.Invoke(mb, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Reset()
|
||||
{
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Call from unity if animation properties have changed
|
||||
|
||||
protected override void OnDidApplyAnimationProperties()
|
||||
{
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make the Graphic have the native size of its content.
|
||||
/// </summary>
|
||||
public virtual void SetNativeSize() {}
|
||||
|
||||
/// <summary>
|
||||
/// When a GraphicRaycaster is raycasting into the scene it does two things. First it filters the elements using their RectTransform rect. Then it uses this Raycast function to determine the elements hit by the raycast.
|
||||
/// </summary>
|
||||
/// <param name="sp">Screen point being tested</param>
|
||||
/// <param name="eventCamera">Camera that is being used for the testing.</param>
|
||||
/// <returns>True if the provided point is a valid location for GraphicRaycaster raycasts.</returns>
|
||||
public virtual bool Raycast(Vector2 sp, Camera eventCamera)
|
||||
{
|
||||
if (!isActiveAndEnabled)
|
||||
return false;
|
||||
|
||||
var t = transform;
|
||||
var components = ListPool<Component>.Get();
|
||||
|
||||
bool ignoreParentGroups = false;
|
||||
bool continueTraversal = true;
|
||||
|
||||
while (t != null)
|
||||
{
|
||||
t.GetComponents(components);
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
var canvas = components[i] as Canvas;
|
||||
if (canvas != null && canvas.overrideSorting)
|
||||
continueTraversal = false;
|
||||
|
||||
var filter = components[i] as ICanvasRaycastFilter;
|
||||
|
||||
if (filter == null)
|
||||
continue;
|
||||
|
||||
var raycastValid = true;
|
||||
|
||||
var group = components[i] as CanvasGroup;
|
||||
if (group != null)
|
||||
{
|
||||
if (ignoreParentGroups == false && group.ignoreParentGroups)
|
||||
{
|
||||
ignoreParentGroups = true;
|
||||
raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
|
||||
}
|
||||
else if (!ignoreParentGroups)
|
||||
raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
|
||||
}
|
||||
else
|
||||
{
|
||||
raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
|
||||
}
|
||||
|
||||
if (!raycastValid)
|
||||
{
|
||||
ListPool<Component>.Release(components);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t = continueTraversal ? t.parent : null;
|
||||
}
|
||||
ListPool<Component>.Release(components);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///<summary>
|
||||
///Adjusts the given pixel to be pixel perfect.
|
||||
///</summary>
|
||||
///<param name="point">Local space point.</param>
|
||||
///<returns>Pixel perfect adjusted point.</returns>
|
||||
///<remarks>
|
||||
///Note: This is only accurate if the Graphic root Canvas is in Screen Space.
|
||||
///</remarks>
|
||||
public Vector2 PixelAdjustPoint(Vector2 point)
|
||||
{
|
||||
if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect)
|
||||
return point;
|
||||
else
|
||||
{
|
||||
return RectTransformUtility.PixelAdjustPoint(point, transform, canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pixel perfect Rect closest to the Graphic RectTransform.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note: This is only accurate if the Graphic root Canvas is in Screen Space.
|
||||
/// </remarks>
|
||||
/// <returns>A Pixel perfect Rect.</returns>
|
||||
public Rect GetPixelAdjustedRect()
|
||||
{
|
||||
if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect)
|
||||
return rectTransform.rect;
|
||||
else
|
||||
return RectTransformUtility.PixelAdjustRect(rectTransform, canvas);
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Tweens the CanvasRenderer color associated with this Graphic.
|
||||
///</summary>
|
||||
///<param name="targetColor">Target color.</param>
|
||||
///<param name="duration">Tween duration.</param>
|
||||
///<param name="ignoreTimeScale">Should ignore Time.scale?</param>
|
||||
///<param name="useAlpha">Should also Tween the alpha channel?</param>
|
||||
public virtual void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha)
|
||||
{
|
||||
CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, true);
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Tweens the CanvasRenderer color associated with this Graphic.
|
||||
///</summary>
|
||||
///<param name="targetColor">Target color.</param>
|
||||
///<param name="duration">Tween duration.</param>
|
||||
///<param name="ignoreTimeScale">Should ignore Time.scale?</param>
|
||||
///<param name="useAlpha">Should also Tween the alpha channel?</param>
|
||||
/// <param name="useRGB">Should the color or the alpha be used to tween</param>
|
||||
public virtual void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha, bool useRGB)
|
||||
{
|
||||
if (canvasRenderer == null || (!useRGB && !useAlpha))
|
||||
return;
|
||||
|
||||
Color currentColor = canvasRenderer.GetColor();
|
||||
if (currentColor.Equals(targetColor))
|
||||
{
|
||||
m_ColorTweenRunner.StopTween();
|
||||
return;
|
||||
}
|
||||
|
||||
ColorTween.ColorTweenMode mode = (useRGB && useAlpha ?
|
||||
ColorTween.ColorTweenMode.All :
|
||||
(useRGB ? ColorTween.ColorTweenMode.RGB : ColorTween.ColorTweenMode.Alpha));
|
||||
|
||||
var colorTween = new ColorTween {duration = duration, startColor = canvasRenderer.GetColor(), targetColor = targetColor};
|
||||
colorTween.AddOnChangedCallback(canvasRenderer.SetColor);
|
||||
colorTween.ignoreTimeScale = ignoreTimeScale;
|
||||
colorTween.tweenMode = mode;
|
||||
m_ColorTweenRunner.StartTween(colorTween);
|
||||
}
|
||||
|
||||
static private Color CreateColorFromAlpha(float alpha)
|
||||
{
|
||||
var alphaColor = Color.black;
|
||||
alphaColor.a = alpha;
|
||||
return alphaColor;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
///Tweens the alpha of the CanvasRenderer color associated with this Graphic.
|
||||
///</summary>
|
||||
///<param name="alpha">Target alpha.</param>
|
||||
///<param name="duration">Duration of the tween in seconds.</param>
|
||||
///<param name="ignoreTimeScale">Should ignore [[Time.scale]]?</param>
|
||||
public virtual void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale)
|
||||
{
|
||||
CrossFadeColor(CreateColorFromAlpha(alpha), duration, ignoreTimeScale, true, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a listener to receive notification when the graphics layout is dirtied.
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void RegisterDirtyLayoutCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyLayoutCallback += action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a listener from receiving notifications when the graphics layout are dirtied
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void UnregisterDirtyLayoutCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyLayoutCallback -= action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a listener to receive notification when the graphics vertices are dirtied.
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void RegisterDirtyVerticesCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyVertsCallback += action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a listener from receiving notifications when the graphics vertices are dirtied
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void UnregisterDirtyVerticesCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyVertsCallback -= action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a listener to receive notification when the graphics material is dirtied.
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void RegisterDirtyMaterialCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyMaterialCallback += action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a listener from receiving notifications when the graphics material are dirtied
|
||||
/// </summary>
|
||||
/// <param name="action">The method to call when invoked.</param>
|
||||
public void UnregisterDirtyMaterialCallback(UnityAction action)
|
||||
{
|
||||
m_OnDirtyMaterialCallback -= action;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a6238e9452bfc704f82ff36791fe1a45
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,344 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("Event/Graphic Raycaster")]
|
||||
[RequireComponent(typeof(Canvas))]
|
||||
/// <summary>
|
||||
/// A derived BaseRaycaster to raycast against Graphic elements.
|
||||
/// </summary>
|
||||
public class GraphicRaycaster : BaseRaycaster
|
||||
{
|
||||
protected const int kNoEventMaskSet = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Type of raycasters to check against to check for canvas blocking elements.
|
||||
/// </summary>
|
||||
public enum BlockingObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Perform no raycasts.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Perform a 2D raycast check to check for blocking 2D elements
|
||||
/// </summary>
|
||||
TwoD = 1,
|
||||
/// <summary>
|
||||
/// Perform a 3D raycast check to check for blocking 3D elements
|
||||
/// </summary>
|
||||
ThreeD = 2,
|
||||
/// <summary>
|
||||
/// Perform a 2D and a 3D raycasts to check for blocking 2D and 3D elements.
|
||||
/// </summary>
|
||||
All = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the raycaster based upon sort order.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The sortOrder priority.
|
||||
/// </returns>
|
||||
public override int sortOrderPriority
|
||||
{
|
||||
get
|
||||
{
|
||||
// We need to return the sorting order here as distance will all be 0 for overlay.
|
||||
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
return canvas.sortingOrder;
|
||||
|
||||
return base.sortOrderPriority;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Priority of the raycaster based upon render order.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The renderOrder priority.
|
||||
/// </returns>
|
||||
public override int renderOrderPriority
|
||||
{
|
||||
get
|
||||
{
|
||||
// We need to return the sorting order here as distance will all be 0 for overlay.
|
||||
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
return canvas.rootCanvas.renderOrder;
|
||||
|
||||
return base.renderOrderPriority;
|
||||
}
|
||||
}
|
||||
|
||||
[FormerlySerializedAs("ignoreReversedGraphics")]
|
||||
[SerializeField]
|
||||
private bool m_IgnoreReversedGraphics = true;
|
||||
[FormerlySerializedAs("blockingObjects")]
|
||||
[SerializeField]
|
||||
private BlockingObjects m_BlockingObjects = BlockingObjects.None;
|
||||
|
||||
/// <summary>
|
||||
/// Whether Graphics facing away from the raycaster are checked for raycasts.
|
||||
/// </summary>
|
||||
public bool ignoreReversedGraphics { get {return m_IgnoreReversedGraphics; } set { m_IgnoreReversedGraphics = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The type of objects that are checked to determine if they block graphic raycasts.
|
||||
/// </summary>
|
||||
public BlockingObjects blockingObjects { get {return m_BlockingObjects; } set { m_BlockingObjects = value; } }
|
||||
|
||||
[SerializeField]
|
||||
protected LayerMask m_BlockingMask = kNoEventMaskSet;
|
||||
|
||||
private Canvas m_Canvas;
|
||||
|
||||
protected GraphicRaycaster()
|
||||
{}
|
||||
|
||||
private Canvas canvas
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Canvas != null)
|
||||
return m_Canvas;
|
||||
|
||||
m_Canvas = GetComponent<Canvas>();
|
||||
return m_Canvas;
|
||||
}
|
||||
}
|
||||
|
||||
[NonSerialized] private List<Graphic> m_RaycastResults = new List<Graphic>();
|
||||
|
||||
/// <summary>
|
||||
/// Perform the raycast against the list of graphics associated with the Canvas.
|
||||
/// </summary>
|
||||
/// <param name="eventData">Current event data</param>
|
||||
/// <param name="resultAppendList">List of hit objects to append new results to.</param>
|
||||
public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
|
||||
{
|
||||
if (canvas == null)
|
||||
return;
|
||||
|
||||
var canvasGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
|
||||
if (canvasGraphics == null || canvasGraphics.Count == 0)
|
||||
return;
|
||||
|
||||
int displayIndex;
|
||||
var currentEventCamera = eventCamera; // Property can call Camera.main, so cache the reference
|
||||
|
||||
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || currentEventCamera == null)
|
||||
displayIndex = canvas.targetDisplay;
|
||||
else
|
||||
displayIndex = currentEventCamera.targetDisplay;
|
||||
|
||||
var eventPosition = Display.RelativeMouseAt(eventData.position);
|
||||
if (eventPosition != Vector3.zero)
|
||||
{
|
||||
// We support multiple display and display identification based on event position.
|
||||
|
||||
int eventDisplayIndex = (int)eventPosition.z;
|
||||
|
||||
// Discard events that are not part of this display so the user does not interact with multiple displays at once.
|
||||
if (eventDisplayIndex != displayIndex)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The multiple display system is not supported on all platforms, when it is not supported the returned position
|
||||
// will be all zeros so when the returned index is 0 we will default to the event data to be safe.
|
||||
eventPosition = eventData.position;
|
||||
|
||||
// We dont really know in which display the event occured. We will process the event assuming it occured in our display.
|
||||
}
|
||||
|
||||
// Convert to view space
|
||||
Vector2 pos;
|
||||
if (currentEventCamera == null)
|
||||
{
|
||||
// Multiple display support only when not the main display. For display 0 the reported
|
||||
// resolution is always the desktops resolution since its part of the display API,
|
||||
// so we use the standard none multiple display method. (case 741751)
|
||||
float w = Screen.width;
|
||||
float h = Screen.height;
|
||||
if (displayIndex > 0 && displayIndex < Display.displays.Length)
|
||||
{
|
||||
w = Display.displays[displayIndex].systemWidth;
|
||||
h = Display.displays[displayIndex].systemHeight;
|
||||
}
|
||||
pos = new Vector2(eventPosition.x / w, eventPosition.y / h);
|
||||
}
|
||||
else
|
||||
pos = currentEventCamera.ScreenToViewportPoint(eventPosition);
|
||||
|
||||
// If it's outside the camera's viewport, do nothing
|
||||
if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f)
|
||||
return;
|
||||
|
||||
float hitDistance = float.MaxValue;
|
||||
|
||||
Ray ray = new Ray();
|
||||
|
||||
if (currentEventCamera != null)
|
||||
ray = currentEventCamera.ScreenPointToRay(eventPosition);
|
||||
|
||||
if (canvas.renderMode != RenderMode.ScreenSpaceOverlay && blockingObjects != BlockingObjects.None)
|
||||
{
|
||||
float distanceToClipPlane = 100.0f;
|
||||
|
||||
if (currentEventCamera != null)
|
||||
{
|
||||
float projectionDirection = ray.direction.z;
|
||||
distanceToClipPlane = Mathf.Approximately(0.0f, projectionDirection)
|
||||
? Mathf.Infinity
|
||||
: Mathf.Abs((currentEventCamera.farClipPlane - currentEventCamera.nearClipPlane) / projectionDirection);
|
||||
}
|
||||
#if PACKAGE_PHYSICS
|
||||
if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.raycast3D != null)
|
||||
{
|
||||
var hits = ReflectionMethodsCache.Singleton.raycast3DAll(ray, distanceToClipPlane, (int)m_BlockingMask);
|
||||
if (hits.Length > 0)
|
||||
hitDistance = hits[0].distance;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if PACKAGE_PHYSICS2D
|
||||
if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
|
||||
{
|
||||
if (ReflectionMethodsCache.Singleton.raycast2D != null)
|
||||
{
|
||||
var hits = ReflectionMethodsCache.Singleton.getRayIntersectionAll(ray, distanceToClipPlane, (int)m_BlockingMask);
|
||||
if (hits.Length > 0)
|
||||
hitDistance = hits[0].distance;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
m_RaycastResults.Clear();
|
||||
|
||||
Raycast(canvas, currentEventCamera, eventPosition, canvasGraphics, m_RaycastResults);
|
||||
|
||||
int totalCount = m_RaycastResults.Count;
|
||||
for (var index = 0; index < totalCount; index++)
|
||||
{
|
||||
var go = m_RaycastResults[index].gameObject;
|
||||
bool appendGraphic = true;
|
||||
|
||||
if (ignoreReversedGraphics)
|
||||
{
|
||||
if (currentEventCamera == null)
|
||||
{
|
||||
// If we dont have a camera we know that we should always be facing forward
|
||||
var dir = go.transform.rotation * Vector3.forward;
|
||||
appendGraphic = Vector3.Dot(Vector3.forward, dir) > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have a camera compare the direction against the cameras forward.
|
||||
var cameraForward = currentEventCamera.transform.rotation * Vector3.forward * currentEventCamera.nearClipPlane;
|
||||
appendGraphic = Vector3.Dot(go.transform.position - currentEventCamera.transform.position - cameraForward, go.transform.forward) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (appendGraphic)
|
||||
{
|
||||
float distance = 0;
|
||||
Transform trans = go.transform;
|
||||
Vector3 transForward = trans.forward;
|
||||
|
||||
if (currentEventCamera == null || canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
distance = 0;
|
||||
else
|
||||
{
|
||||
// http://geomalgorithms.com/a06-_intersect-2.html
|
||||
distance = (Vector3.Dot(transForward, trans.position - ray.origin) / Vector3.Dot(transForward, ray.direction));
|
||||
|
||||
// Check to see if the go is behind the camera.
|
||||
if (distance < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (distance >= hitDistance)
|
||||
continue;
|
||||
|
||||
var castResult = new RaycastResult
|
||||
{
|
||||
gameObject = go,
|
||||
module = this,
|
||||
distance = distance,
|
||||
screenPosition = eventPosition,
|
||||
displayIndex = displayIndex,
|
||||
index = resultAppendList.Count,
|
||||
depth = m_RaycastResults[index].depth,
|
||||
sortingLayer = canvas.sortingLayerID,
|
||||
sortingOrder = canvas.sortingOrder,
|
||||
worldPosition = ray.origin + ray.direction * distance,
|
||||
worldNormal = -transForward
|
||||
};
|
||||
resultAppendList.Add(castResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The camera that will generate rays for this raycaster.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// - Null if Camera mode is ScreenSpaceOverlay or ScreenSpaceCamera and has no camera.
|
||||
/// - canvas.worldCanvas if not null
|
||||
/// - Camera.main.
|
||||
/// </returns>
|
||||
public override Camera eventCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay || (canvas.renderMode == RenderMode.ScreenSpaceCamera && canvas.worldCamera == null))
|
||||
return null;
|
||||
|
||||
return canvas.worldCamera != null ? canvas.worldCamera : Camera.main;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a raycast into the screen and collect all graphics underneath it.
|
||||
/// </summary>
|
||||
[NonSerialized] static readonly List<Graphic> s_SortedGraphics = new List<Graphic>();
|
||||
private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, IList<Graphic> foundGraphics, List<Graphic> results)
|
||||
{
|
||||
// Necessary for the event system
|
||||
int totalCount = foundGraphics.Count;
|
||||
for (int i = 0; i < totalCount; ++i)
|
||||
{
|
||||
Graphic graphic = foundGraphics[i];
|
||||
|
||||
// -1 means it hasn't been processed by the canvas, which means it isn't actually drawn
|
||||
if (!graphic.raycastTarget || graphic.canvasRenderer.cull || graphic.depth == -1)
|
||||
continue;
|
||||
|
||||
if (!RectTransformUtility.RectangleContainsScreenPoint(graphic.rectTransform, pointerPosition, eventCamera))
|
||||
continue;
|
||||
|
||||
if (eventCamera != null && eventCamera.WorldToScreenPoint(graphic.rectTransform.position).z > eventCamera.farClipPlane)
|
||||
continue;
|
||||
|
||||
if (graphic.Raycast(pointerPosition, eventCamera))
|
||||
{
|
||||
s_SortedGraphics.Add(graphic);
|
||||
}
|
||||
}
|
||||
|
||||
s_SortedGraphics.Sort((g1, g2) => g2.depth.CompareTo(g1.depth));
|
||||
totalCount = s_SortedGraphics.Count;
|
||||
for (int i = 0; i < totalCount; ++i)
|
||||
results.Add(s_SortedGraphics[i]);
|
||||
|
||||
s_SortedGraphics.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dc42784cf147c0c48a680349fa168899
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,50 @@
|
|||
#if UNITY_EDITOR
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.UI.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// EditorOnly class for tracking all Graphics.
|
||||
/// Used when a source asset is reimported into the editor to ensure that Graphics are updated as intended.
|
||||
/// </summary>
|
||||
public static class GraphicRebuildTracker
|
||||
{
|
||||
static IndexedSet<Graphic> m_Tracked = new IndexedSet<Graphic>();
|
||||
static bool s_Initialized;
|
||||
|
||||
/// <summary>
|
||||
/// Add a Graphic to the list of tracked Graphics
|
||||
/// </summary>
|
||||
/// <param name="g">The graphic to track</param>
|
||||
public static void TrackGraphic(Graphic g)
|
||||
{
|
||||
if (!s_Initialized)
|
||||
{
|
||||
CanvasRenderer.onRequestRebuild += OnRebuildRequested;
|
||||
s_Initialized = true;
|
||||
}
|
||||
|
||||
m_Tracked.AddUnique(g);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a Graphic to the list of tracked Graphics
|
||||
/// </summary>
|
||||
/// <param name="g">The graphic to remove from tracking.</param>
|
||||
public static void UnTrackGraphic(Graphic g)
|
||||
{
|
||||
m_Tracked.Remove(g);
|
||||
}
|
||||
|
||||
static void OnRebuildRequested()
|
||||
{
|
||||
StencilMaterial.ClearAll();
|
||||
for (int i = 0; i < m_Tracked.Count; i++)
|
||||
{
|
||||
m_Tracked[i].OnRebuildRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // if UNITY_EDITOR
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 445cdcfc747eba94288b97f5869aa2fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,102 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine.UI.Collections;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Registry which maps a Graphic to the canvas it belongs to.
|
||||
/// </summary>
|
||||
public class GraphicRegistry
|
||||
{
|
||||
private static GraphicRegistry s_Instance;
|
||||
|
||||
private readonly Dictionary<Canvas, IndexedSet<Graphic>> m_Graphics = new Dictionary<Canvas, IndexedSet<Graphic>>();
|
||||
|
||||
protected GraphicRegistry()
|
||||
{
|
||||
// Avoid runtime generation of these types. Some platforms are AOT only and do not support
|
||||
// JIT. What's more we actually create a instance of the required types instead of
|
||||
// just declaring an unused variable which may be optimized away by some compilers (Mono vs MS).
|
||||
|
||||
// See: 877060
|
||||
|
||||
System.GC.KeepAlive(new Dictionary<Graphic, int>());
|
||||
System.GC.KeepAlive(new Dictionary<ICanvasElement, int>());
|
||||
System.GC.KeepAlive(new Dictionary<IClipper, int>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance of the GraphicRegistry. Creates a new instance if it does not exist.
|
||||
/// </summary>
|
||||
public static GraphicRegistry instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance == null)
|
||||
s_Instance = new GraphicRegistry();
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Associates a Graphic with a Canvas and stores this association in the registry.
|
||||
/// </summary>
|
||||
/// <param name="c">The canvas being associated with the Graphic.</param>
|
||||
/// <param name="graphic">The Graphic being associated with the Canvas.</param>
|
||||
public static void RegisterGraphicForCanvas(Canvas c, Graphic graphic)
|
||||
{
|
||||
if (c == null)
|
||||
return;
|
||||
|
||||
IndexedSet<Graphic> graphics;
|
||||
instance.m_Graphics.TryGetValue(c, out graphics);
|
||||
|
||||
if (graphics != null)
|
||||
{
|
||||
graphics.AddUnique(graphic);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dont need to AddUnique as we know its the only item in the list
|
||||
graphics = new IndexedSet<Graphic>();
|
||||
graphics.Add(graphic);
|
||||
instance.m_Graphics.Add(c, graphics);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dissociates a Graphic from a Canvas, removing this association from the registry.
|
||||
/// </summary>
|
||||
/// <param name="c">The Canvas to dissociate from the Graphic.</param>
|
||||
/// <param name="graphic">The Graphic to dissociate from the Canvas.</param>
|
||||
public static void UnregisterGraphicForCanvas(Canvas c, Graphic graphic)
|
||||
{
|
||||
if (c == null)
|
||||
return;
|
||||
|
||||
IndexedSet<Graphic> graphics;
|
||||
if (instance.m_Graphics.TryGetValue(c, out graphics))
|
||||
{
|
||||
graphics.Remove(graphic);
|
||||
|
||||
if (graphics.Count == 0)
|
||||
instance.m_Graphics.Remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<Graphic> s_EmptyList = new List<Graphic>();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of Graphics associated with a Canvas.
|
||||
/// </summary>
|
||||
/// <param name="canvas">The Canvas to search</param>
|
||||
/// <returns>Returns a list of Graphics. Returns an empty list if no Graphics are associated with the specified Canvas.</returns>
|
||||
public static IList<Graphic> GetGraphicsForCanvas(Canvas canvas)
|
||||
{
|
||||
IndexedSet<Graphic> graphics;
|
||||
if (instance.m_Graphics.TryGetValue(canvas, out graphics))
|
||||
return graphics;
|
||||
|
||||
return s_EmptyList;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 69e3979b7029e8a4da2d96b714ba5c3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[Obsolete("Not supported anymore")]
|
||||
interface IGraphicEnabledDisabled
|
||||
{
|
||||
void OnSiblingGraphicEnabledDisabled();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 928dc55e2c8c3ee4dad33b6d561cb6ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
|
||||
[Obsolete("Not supported anymore.", true)]
|
||||
public interface IMask
|
||||
{
|
||||
bool Enabled();
|
||||
RectTransform rectTransform { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ceb629fc661813d40986b4abbefe72c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// This element is capable of being masked out.
|
||||
/// </summary>
|
||||
public interface IMaskable
|
||||
{
|
||||
/// <summary>
|
||||
/// Recalculate masking for this element and all children elements.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use this to update the internal state (recreate materials etc).
|
||||
/// </remarks>
|
||||
void RecalculateMasking();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61a20120cddc53849bbc10fc805ffe3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe87c0e1cc204ed48ad3b37840f39efc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d199490a83bb2b844b9695cbf13b01ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1999349e7f492c947bb6eb70f624382e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,209 @@
|
|||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace UnityEngine.UI
|
||||
{
|
||||
[AddComponentMenu("Layout/Aspect Ratio Fitter", 142)]
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
[DisallowMultipleComponent]
|
||||
/// <summary>
|
||||
/// Resizes a RectTransform to fit a specified aspect ratio.
|
||||
/// </summary>
|
||||
public class AspectRatioFitter : UIBehaviour, ILayoutSelfController
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies a mode to use to enforce an aspect ratio.
|
||||
/// </summary>
|
||||
public enum AspectMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The aspect ratio is not enforced
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Changes the height of the rectangle to match the aspect ratio.
|
||||
/// </summary>
|
||||
WidthControlsHeight,
|
||||
/// <summary>
|
||||
/// Changes the width of the rectangle to match the aspect ratio.
|
||||
/// </summary>
|
||||
HeightControlsWidth,
|
||||
/// <summary>
|
||||
/// Sizes the rectangle such that it's fully contained within the parent rectangle.
|
||||
/// </summary>
|
||||
FitInParent,
|
||||
/// <summary>
|
||||
/// Sizes the rectangle such that the parent rectangle is fully contained within.
|
||||
/// </summary>
|
||||
EnvelopeParent
|
||||
}
|
||||
|
||||
[SerializeField] private AspectMode m_AspectMode = AspectMode.None;
|
||||
|
||||
/// <summary>
|
||||
/// The mode to use to enforce the aspect ratio.
|
||||
/// </summary>
|
||||
public AspectMode aspectMode { get { return m_AspectMode; } set { if (SetPropertyUtility.SetStruct(ref m_AspectMode, value)) SetDirty(); } }
|
||||
|
||||
[SerializeField] private float m_AspectRatio = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The aspect ratio to enforce. This means width divided by height.
|
||||
/// </summary>
|
||||
public float aspectRatio { get { return m_AspectRatio; } set { if (SetPropertyUtility.SetStruct(ref m_AspectRatio, value)) SetDirty(); } }
|
||||
|
||||
[System.NonSerialized]
|
||||
private RectTransform m_Rect;
|
||||
|
||||
// This "delayed" mechanism is required for case 1014834.
|
||||
private bool m_DelayedSetDirty = false;
|
||||
|
||||
private RectTransform rectTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Rect == null)
|
||||
m_Rect = GetComponent<RectTransform>();
|
||||
return m_Rect;
|
||||
}
|
||||
}
|
||||
|
||||
private DrivenRectTransformTracker m_Tracker;
|
||||
|
||||
protected AspectRatioFitter() {}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
m_Tracker.Clear();
|
||||
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the rect based on the delayed dirty.
|
||||
/// Got around issue of calling onValidate from OnEnable function.
|
||||
/// </summary>
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (m_DelayedSetDirty)
|
||||
{
|
||||
m_DelayedSetDirty = false;
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function called when this RectTransform or parent RectTransform has changed dimensions.
|
||||
/// </summary>
|
||||
protected override void OnRectTransformDimensionsChange()
|
||||
{
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
private void UpdateRect()
|
||||
{
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
m_Tracker.Clear();
|
||||
|
||||
switch (m_AspectMode)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
case AspectMode.None:
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
m_AspectRatio = Mathf.Clamp(rectTransform.rect.width / rectTransform.rect.height, 0.001f, 1000f);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case AspectMode.HeightControlsWidth:
|
||||
{
|
||||
m_Tracker.Add(this, rectTransform, DrivenTransformProperties.SizeDeltaX);
|
||||
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, rectTransform.rect.height * m_AspectRatio);
|
||||
break;
|
||||
}
|
||||
case AspectMode.WidthControlsHeight:
|
||||
{
|
||||
m_Tracker.Add(this, rectTransform, DrivenTransformProperties.SizeDeltaY);
|
||||
rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, rectTransform.rect.width / m_AspectRatio);
|
||||
break;
|
||||
}
|
||||
case AspectMode.FitInParent:
|
||||
case AspectMode.EnvelopeParent:
|
||||
{
|
||||
m_Tracker.Add(this, rectTransform,
|
||||
DrivenTransformProperties.Anchors |
|
||||
DrivenTransformProperties.AnchoredPosition |
|
||||
DrivenTransformProperties.SizeDeltaX |
|
||||
DrivenTransformProperties.SizeDeltaY);
|
||||
|
||||
rectTransform.anchorMin = Vector2.zero;
|
||||
rectTransform.anchorMax = Vector2.one;
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
|
||||
Vector2 sizeDelta = Vector2.zero;
|
||||
Vector2 parentSize = GetParentSize();
|
||||
if ((parentSize.y * aspectRatio < parentSize.x) ^ (m_AspectMode == AspectMode.FitInParent))
|
||||
{
|
||||
sizeDelta.y = GetSizeDeltaToProduceSize(parentSize.x / aspectRatio, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sizeDelta.x = GetSizeDeltaToProduceSize(parentSize.y * aspectRatio, 0);
|
||||
}
|
||||
rectTransform.sizeDelta = sizeDelta;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetSizeDeltaToProduceSize(float size, int axis)
|
||||
{
|
||||
return size - GetParentSize()[axis] * (rectTransform.anchorMax[axis] - rectTransform.anchorMin[axis]);
|
||||
}
|
||||
|
||||
private Vector2 GetParentSize()
|
||||
{
|
||||
RectTransform parent = rectTransform.parent as RectTransform;
|
||||
if (!parent)
|
||||
return Vector2.zero;
|
||||
return parent.rect.size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method called by the layout system. Has no effect
|
||||
/// </summary>
|
||||
public virtual void SetLayoutHorizontal() {}
|
||||
|
||||
/// <summary>
|
||||
/// Method called by the layout system. Has no effect
|
||||
/// </summary>
|
||||
public virtual void SetLayoutVertical() {}
|
||||
|
||||
/// <summary>
|
||||
/// Mark the AspectRatioFitter as dirty.
|
||||
/// </summary>
|
||||
protected void SetDirty()
|
||||
{
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
m_AspectRatio = Mathf.Clamp(m_AspectRatio, 0.001f, 1000f);
|
||||
m_DelayedSetDirty = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 86710e43de46f6f4bac7c8e50813a599
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue