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;
using UnityEngine.Pool;
namespace UnityEngine.UI
{
///
/// Base class for all UI components that should be derived from when creating new Graphic types.
///
[DisallowMultipleComponent]
[RequireComponent(typeof(RectTransform))]
[ExecuteAlways]
///
/// Base class for all visual UI Component.
/// When creating visual UI components you should inherit from this class.
///
///
/// Below is a simple example that draws a colored quad inside the Rect Transform area.
///
///
///
///
public abstract class Graphic
: UIBehaviour,
ICanvasElement
{
static protected Material s_DefaultUI = null;
static protected Texture2D s_WhiteTexture = null;
///
/// Default material used to draw UI elements if no explicit material was specified.
///
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;
///
/// Base color of the Graphic.
///
///
/// 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.
///
///
///
/// ();
/// //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;
/// }
/// }
/// ]]>
///
///
public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } }
[SerializeField] private bool m_RaycastTarget = true;
private bool m_RaycastTargetCache = true;
///
/// Should this graphic be considered a target for raycasting?
///
public virtual bool raycastTarget
{
get
{
return m_RaycastTarget;
}
set
{
if (value != m_RaycastTarget)
{
if (m_RaycastTarget)
GraphicRegistry.UnregisterRaycastGraphicForCanvas(canvas, this);
m_RaycastTarget = value;
if (m_RaycastTarget && isActiveAndEnabled)
GraphicRegistry.RegisterRaycastGraphicForCanvas(canvas, this);
}
m_RaycastTargetCache = value;
}
}
[SerializeField]
private Vector4 m_RaycastPadding = new Vector4();
///
/// Padding to be applied to the masking
/// X = Left
/// Y = Bottom
/// Z = Right
/// W = Top
///
public Vector4 raycastPadding
{
get { return m_RaycastPadding; }
set
{
m_RaycastPadding = 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 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();
m_ColorTweenRunner.Init(this);
useLegacyMeshGeneration = true;
}
///
/// Set all properties of the Graphic dirty and needing rebuilt.
/// Dirties Layout, Vertices, and Materials.
///
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();
SetRaycastDirty();
}
///
/// Mark the layout as dirty and needing rebuilt.
///
///
/// Send a OnDirtyLayoutCallback notification if any elements are registered. See RegisterDirtyLayoutCallback
///
public virtual void SetLayoutDirty()
{
if (!IsActive())
return;
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
if (m_OnDirtyLayoutCallback != null)
m_OnDirtyLayoutCallback();
}
///
/// Mark the vertices as dirty and needing rebuilt.
///
///
/// Send a OnDirtyVertsCallback notification if any elements are registered. See RegisterDirtyVerticesCallback
///
public virtual void SetVerticesDirty()
{
if (!IsActive())
return;
m_VertsDirty = true;
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
if (m_OnDirtyVertsCallback != null)
m_OnDirtyVertsCallback();
}
///
/// Mark the material as dirty and needing rebuilt.
///
///
/// Send a OnDirtyMaterialCallback notification if any elements are registered. See RegisterDirtyMaterialCallback
///
public virtual void SetMaterialDirty()
{
if (!IsActive())
return;
m_MaterialDirty = true;
CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
if (m_OnDirtyMaterialCallback != null)
m_OnDirtyMaterialCallback();
}
public void SetRaycastDirty()
{
if (m_RaycastTargetCache != m_RaycastTarget)
{
if (m_RaycastTarget && isActiveAndEnabled)
GraphicRegistry.RegisterRaycastGraphicForCanvas(canvas, this);
else if (!m_RaycastTarget)
GraphicRegistry.UnregisterRaycastGraphicForCanvas(canvas, this);
}
m_RaycastTargetCache = m_RaycastTarget;
}
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();
}
///
/// Absolute depth of the graphic, used by rendering and events -- lowest to highest.
///
///
/// 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.
///
public int depth { get { return canvasRenderer.absoluteDepth; } }
///
/// The RectTransform component used by the Graphic. Cached for speed.
///
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();
}
return m_RectTransform;
}
}
///
/// A reference to the Canvas this Graphic is rendering to.
///
///
/// In the situation where the Graphic is used in a hierarchy with multiple Canvases, the Canvas closest to the root will be used.
///
public Canvas canvas
{
get
{
if (m_Canvas == null)
CacheCanvas();
return m_Canvas;
}
}
private void CacheCanvas()
{
var list = ListPool