1959 lines
46 KiB
C#
1959 lines
46 KiB
C#
//----------------------------------------------
|
||
// NGUI: Next-Gen UI kit
|
||
// Copyright © 2011-2015 Tasharen Entertainment
|
||
//----------------------------------------------
|
||
#define FUNCELL_MODIFIED
|
||
|
||
using UnityEngine;
|
||
using System.Collections.Generic;
|
||
|
||
/// <summary>
|
||
/// Base class for all UI components that should be derived from when creating new widget types.
|
||
/// </summary>
|
||
|
||
[ExecuteInEditMode]
|
||
[AddComponentMenu("NGUI/UI/NGUI Widget")]
|
||
public class UIWidget : UIRect
|
||
{
|
||
public enum Pivot
|
||
{
|
||
TopLeft,
|
||
Top,
|
||
TopRight,
|
||
Left,
|
||
Center,
|
||
Right,
|
||
BottomLeft,
|
||
Bottom,
|
||
BottomRight,
|
||
}
|
||
|
||
// Cached and saved values
|
||
[HideInInspector][SerializeField] protected Color mColor = Color.white;
|
||
#if FUNCELL_MODIFIED
|
||
//保存上一帧的alhpa值,用于判断改变后计算alpha
|
||
private float _oldAlpha = -1f;
|
||
[System.NonSerialized] public bool IsOnlyWidget = false;
|
||
#endif
|
||
[HideInInspector][SerializeField] public bool useGradient = false;
|
||
[HideInInspector][SerializeField] public Color ltColor = Color.white;
|
||
[HideInInspector][SerializeField] public Color lbColor = Color.white;
|
||
[HideInInspector][SerializeField] public Color rtColor = Color.white;
|
||
[HideInInspector][SerializeField] public Color rbColor = Color.white;
|
||
|
||
[HideInInspector][SerializeField] protected Pivot mPivot = Pivot.Center;
|
||
[HideInInspector][SerializeField] protected int mWidth = 100;
|
||
[HideInInspector][SerializeField] protected int mHeight = 100;
|
||
[HideInInspector][SerializeField] protected int mDepth = 0;
|
||
[HideInInspector][SerializeField] protected Vector2 lbOffset = Vector2.zero;
|
||
[HideInInspector][SerializeField] protected Vector2 ltOffset = Vector2.zero;
|
||
[HideInInspector][SerializeField] protected Vector2 rbOffset = Vector2.zero;
|
||
[HideInInspector][SerializeField] protected Vector2 rtOffset = Vector2.zero;
|
||
|
||
public delegate void OnDimensionsChanged ();
|
||
public delegate void OnPostFillCallback (UIWidget widget, int bufferOffset, BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols);
|
||
|
||
/// <summary>
|
||
/// Notification triggered when the widget's dimensions or position changes.
|
||
/// </summary>
|
||
|
||
public OnDimensionsChanged onChange;
|
||
|
||
/// <summary>
|
||
/// Notification triggered after the widget's buffer has been filled.
|
||
/// </summary>
|
||
|
||
public OnPostFillCallback onPostFill;
|
||
|
||
/// <summary>
|
||
/// Callback triggered when the widget is about to be renderered (OnWillRenderObject).
|
||
/// NOTE: This property is only exposed for the sake of speed to avoid property execution.
|
||
/// In most cases you will want to use UIWidget.onRender instead.
|
||
/// </summary>
|
||
|
||
public UIDrawCall.OnRenderCallback mOnRender;
|
||
|
||
/// <summary>
|
||
/// Set the callback that will be triggered when the widget is being rendered (OnWillRenderObject).
|
||
/// This is where you would set material properties and shader values.
|
||
/// </summary>
|
||
|
||
public UIDrawCall.OnRenderCallback onRender
|
||
{
|
||
get
|
||
{
|
||
return mOnRender;
|
||
}
|
||
set
|
||
{
|
||
#if UNITY_FLASH
|
||
if (!(mOnRender == value))
|
||
#else
|
||
if (mOnRender != value)
|
||
#endif
|
||
{
|
||
#if !UNITY_FLASH
|
||
if (drawCall != null && drawCall.onRender != null && mOnRender != null)
|
||
drawCall.onRender -= mOnRender;
|
||
#endif
|
||
mOnRender = value;
|
||
if (drawCall != null) drawCall.onRender += value;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// If set to 'true', the box collider's dimensions will be adjusted to always match the widget whenever it resizes.
|
||
/// </summary>
|
||
|
||
public bool autoResizeBoxCollider = false;
|
||
|
||
/// <summary>
|
||
/// Hide the widget if it happens to be off-screen.
|
||
/// </summary>
|
||
|
||
public bool hideIfOffScreen = false;
|
||
|
||
public enum AspectRatioSource
|
||
{
|
||
Free,
|
||
BasedOnWidth,
|
||
BasedOnHeight,
|
||
}
|
||
|
||
/// <summary>
|
||
/// Whether the rectangle will attempt to maintain a specific aspect ratio.
|
||
/// </summary>
|
||
|
||
public AspectRatioSource keepAspectRatio = AspectRatioSource.Free;
|
||
|
||
/// <summary>
|
||
/// If you want the anchored rectangle to keep a specific aspect ratio, set this value.
|
||
/// </summary>
|
||
|
||
public float aspectRatio = 1f;
|
||
|
||
public delegate bool HitCheck (Vector3 worldPos);
|
||
|
||
/// <summary>
|
||
/// Custom hit check function. If set, all hit checks (including events) will call this function,
|
||
/// passing the world position. Return 'true' if it's within the bounds of your choice, 'false' otherwise.
|
||
/// </summary>
|
||
|
||
public HitCheck hitCheck;
|
||
|
||
/// <summary>
|
||
/// Panel that's managing this widget.
|
||
/// </summary>
|
||
|
||
[System.NonSerialized] public UIPanel panel;
|
||
//当前Panel的ID
|
||
private int _panelInstID = 0;
|
||
|
||
/// <summary>
|
||
/// Widget's generated geometry.
|
||
/// </summary>
|
||
|
||
[System.NonSerialized] public UIGeometry geometry = new UIGeometry();
|
||
|
||
/// <summary>
|
||
/// If set to 'false', the widget's OnFill function will not be called, letting you define custom geometry at will.
|
||
/// </summary>
|
||
|
||
[System.NonSerialized] public bool fillGeometry = true;
|
||
[System.NonSerialized] protected bool mPlayMode = true;
|
||
[System.NonSerialized] protected Vector4 mDrawRegion = new Vector4(0f, 0f, 1f, 1f);
|
||
[System.NonSerialized] Matrix4x4 mLocalToPanel;
|
||
[System.NonSerialized] bool mIsVisibleByAlpha = true;
|
||
[System.NonSerialized] bool mIsVisibleByPanel = true;
|
||
[System.NonSerialized] bool mIsInFront = true;
|
||
[System.NonSerialized] float mLastAlpha = 0f;
|
||
[System.NonSerialized] bool mMoved = false;
|
||
|
||
/// <summary>
|
||
/// Internal usage -- draw call that's drawing the widget.
|
||
/// </summary>
|
||
|
||
[System.NonSerialized] public UIDrawCall drawCall;
|
||
[System.NonSerialized] protected Vector3[] mCorners = new Vector3[4];
|
||
|
||
#if FUNCELL_MODIFIED
|
||
//是否为灰色
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private bool _isGray = false;
|
||
public bool IsGray
|
||
{
|
||
get
|
||
{
|
||
return _isGray;
|
||
}
|
||
set
|
||
{
|
||
if (_isGray != value)
|
||
{
|
||
_isGray = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
//是否为流光
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private bool _isFlowLight = false;
|
||
public bool IsFlowLight
|
||
{
|
||
get
|
||
{
|
||
return _isFlowLight;
|
||
}
|
||
set
|
||
{
|
||
if (_isFlowLight != value)
|
||
{
|
||
_isFlowLight = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
//流光的颜色--这里使用整形,容易比较(很坑的是Color32不能比较,所以选择这个值)
|
||
//这里使用int来表示float,有效数字为10000.
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private Vector3Int _flowColor = new Vector3Int(3000, 3000, 3000);
|
||
public Vector3Int FlowColor
|
||
{
|
||
get
|
||
{
|
||
return _flowColor;
|
||
}
|
||
set
|
||
{
|
||
if (_flowColor != value)
|
||
{
|
||
_flowColor = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
//流光的参数 v1:宽度[0,10000] v2:速度, 光在UI上流过的速度 v3:滚动的位置[0,10000]
|
||
//这里使用int来表示float,有效数字为10000.
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private Vector3Int _flowParam = new Vector3Int(5000, 0, 0);
|
||
public Vector3Int FlowParam
|
||
{
|
||
get
|
||
{
|
||
return _flowParam;
|
||
}
|
||
|
||
set
|
||
{
|
||
if (_flowParam != value)
|
||
{
|
||
_flowParam = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
public int FlowWidth
|
||
{
|
||
get
|
||
{
|
||
return _flowParam.x;
|
||
}
|
||
|
||
set
|
||
{
|
||
if (_flowParam.x != value)
|
||
{
|
||
_flowParam.x = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
public int FlowSpeed
|
||
{
|
||
get
|
||
{
|
||
return _flowParam.y;
|
||
}
|
||
|
||
set
|
||
{
|
||
if (_flowParam.y != value)
|
||
{
|
||
_flowParam.y = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
public int FlowValue
|
||
{
|
||
get
|
||
{
|
||
return _flowParam.z;
|
||
}
|
||
|
||
set
|
||
{
|
||
if (_flowParam.z != value)
|
||
{
|
||
_flowParam.z = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private bool _isAutoFlow = false;
|
||
public bool IsAutoFlow
|
||
{
|
||
get
|
||
{
|
||
return _isAutoFlow;
|
||
}
|
||
|
||
set
|
||
{
|
||
if (_isAutoFlow != value)
|
||
{
|
||
_isAutoFlow = value;
|
||
if (_isAutoFlow)
|
||
{
|
||
_flowParam.y = 15000;
|
||
}
|
||
else
|
||
{
|
||
_flowParam.y = 0;
|
||
}
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
//是否为叠加
|
||
[HideInInspector]
|
||
[SerializeField]
|
||
private bool _isOverlay = false;
|
||
public bool IsOverlay
|
||
{
|
||
get
|
||
{
|
||
return _isOverlay;
|
||
}
|
||
set
|
||
{
|
||
if (_isOverlay != value)
|
||
{
|
||
_isOverlay = value;
|
||
OnReDrawWidget();
|
||
}
|
||
}
|
||
}
|
||
|
||
//重新刷新Widget
|
||
private void OnReDrawWidget()
|
||
{
|
||
if (panel != null) panel.RemoveWidget(this);
|
||
|
||
if (panel != null)
|
||
{
|
||
panel.AddWidget(this);
|
||
|
||
if (!Application.isPlaying)
|
||
{
|
||
panel.SortWidgets();
|
||
panel.RebuildAllDrawCalls();
|
||
}
|
||
}
|
||
#if UNITY_EDITOR
|
||
NGUITools.SetDirty(this);
|
||
#endif
|
||
}
|
||
|
||
#endif
|
||
/// <summary>
|
||
/// Draw region alters how the widget looks without modifying the widget's rectangle.
|
||
/// A region is made up of 4 relative values (0-1 range). The order is Left (X), Bottom (Y), Right (Z) and Top (W).
|
||
/// To have a widget's left edge be 30% from the left side, set X to 0.3. To have the widget's right edge be 30%
|
||
/// from the right hand side, set Z to 0.7.
|
||
/// </summary>
|
||
|
||
public Vector4 drawRegion
|
||
{
|
||
get
|
||
{
|
||
return mDrawRegion;
|
||
}
|
||
set
|
||
{
|
||
if (mDrawRegion != value)
|
||
{
|
||
mDrawRegion = value;
|
||
if (autoResizeBoxCollider) ResizeCollider();
|
||
MarkAsChanged();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Pivot offset in relative coordinates. Bottom-left is (0, 0). Top-right is (1, 1).
|
||
/// </summary>
|
||
|
||
public Vector2 pivotOffset { get { return NGUIMath.GetPivotOffset(pivot); } }
|
||
|
||
/// <summary>
|
||
/// Widget's width in pixels.
|
||
/// </summary>
|
||
|
||
public int width
|
||
{
|
||
get
|
||
{
|
||
return mWidth;
|
||
}
|
||
set
|
||
{
|
||
int min = minWidth;
|
||
if (value < min) value = min;
|
||
|
||
if (mWidth != value && keepAspectRatio != AspectRatioSource.BasedOnHeight)
|
||
{
|
||
if (isAnchoredHorizontally)
|
||
{
|
||
if (leftAnchor.target != null && rightAnchor.target != null)
|
||
{
|
||
if (mPivot == Pivot.BottomLeft || mPivot == Pivot.Left || mPivot == Pivot.TopLeft)
|
||
{
|
||
NGUIMath.AdjustWidget(this, 0f, 0f, value - mWidth, 0f);
|
||
}
|
||
else if (mPivot == Pivot.BottomRight || mPivot == Pivot.Right || mPivot == Pivot.TopRight)
|
||
{
|
||
NGUIMath.AdjustWidget(this, mWidth - value, 0f, 0f, 0f);
|
||
}
|
||
else
|
||
{
|
||
int diff = value - mWidth;
|
||
diff = diff - (diff & 1);
|
||
if (diff != 0) NGUIMath.AdjustWidget(this, -diff * 0.5f, 0f, diff * 0.5f, 0f);
|
||
}
|
||
}
|
||
else if (leftAnchor.target != null)
|
||
{
|
||
NGUIMath.AdjustWidget(this, 0f, 0f, value - mWidth, 0f);
|
||
}
|
||
else NGUIMath.AdjustWidget(this, mWidth - value, 0f, 0f, 0f);
|
||
}
|
||
else SetDimensions(value, mHeight);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Widget's height in pixels.
|
||
/// </summary>
|
||
|
||
public int height
|
||
{
|
||
get
|
||
{
|
||
return mHeight;
|
||
}
|
||
set
|
||
{
|
||
int min = minHeight;
|
||
if (value < min) value = min;
|
||
|
||
if (mHeight != value && keepAspectRatio != AspectRatioSource.BasedOnWidth)
|
||
{
|
||
if (isAnchoredVertically)
|
||
{
|
||
if (bottomAnchor.target != null && topAnchor.target != null)
|
||
{
|
||
if (mPivot == Pivot.BottomLeft || mPivot == Pivot.Bottom || mPivot == Pivot.BottomRight)
|
||
{
|
||
NGUIMath.AdjustWidget(this, 0f, 0f, 0f, value - mHeight);
|
||
}
|
||
else if (mPivot == Pivot.TopLeft || mPivot == Pivot.Top || mPivot == Pivot.TopRight)
|
||
{
|
||
NGUIMath.AdjustWidget(this, 0f, mHeight - value, 0f, 0f);
|
||
}
|
||
else
|
||
{
|
||
int diff = value - mHeight;
|
||
diff = diff - (diff & 1);
|
||
if (diff != 0) NGUIMath.AdjustWidget(this, 0f, -diff * 0.5f, 0f, diff * 0.5f);
|
||
}
|
||
}
|
||
else if (bottomAnchor.target != null)
|
||
{
|
||
NGUIMath.AdjustWidget(this, 0f, 0f, 0f, value - mHeight);
|
||
}
|
||
else NGUIMath.AdjustWidget(this, 0f, mHeight - value, 0f, 0f);
|
||
}
|
||
else SetDimensions(mWidth, value);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Color used by the widget.
|
||
/// </summary>
|
||
|
||
public Color color
|
||
{
|
||
get
|
||
{
|
||
return mColor;
|
||
}
|
||
set
|
||
{
|
||
if (mColor != value)
|
||
{
|
||
bool alphaChange = (mColor.a != value.a);
|
||
mColor = value;
|
||
Invalidate(alphaChange);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Widget's alpha -- a convenience method.
|
||
/// </summary>
|
||
|
||
public override float alpha
|
||
{
|
||
get
|
||
{
|
||
return mColor.a;
|
||
}
|
||
set
|
||
{
|
||
float val = Mathf.Clamp01(value);
|
||
if (mColor.a != val)
|
||
{
|
||
mColor.a = val;
|
||
Invalidate(true, true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Whether the widget is currently visible.
|
||
/// </summary>
|
||
|
||
public bool isVisible { get { return mIsVisibleByPanel && mIsVisibleByAlpha && mIsInFront && finalAlpha > 0.001f && NGUITools.GetActive(this); } }
|
||
|
||
/// <summary>
|
||
/// Whether the widget has vertices to draw.
|
||
/// </summary>
|
||
|
||
public bool hasVertices { get { return geometry != null && geometry.hasVertices; } }
|
||
|
||
/// <summary>
|
||
/// Change the pivot point and do not attempt to keep the widget in the same place by adjusting its transform.
|
||
/// </summary>
|
||
|
||
public Pivot rawPivot
|
||
{
|
||
get
|
||
{
|
||
return mPivot;
|
||
}
|
||
set
|
||
{
|
||
if (mPivot != value)
|
||
{
|
||
mPivot = value;
|
||
if (autoResizeBoxCollider) ResizeCollider();
|
||
MarkAsChanged();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Set or get the value that specifies where the widget's pivot point should be.
|
||
/// </summary>
|
||
|
||
public Pivot pivot
|
||
{
|
||
get
|
||
{
|
||
return mPivot;
|
||
}
|
||
set
|
||
{
|
||
if (mPivot != value)
|
||
{
|
||
Vector3 before = worldCorners[0];
|
||
|
||
mPivot = value;
|
||
mChanged = true;
|
||
|
||
Vector3 after = worldCorners[0];
|
||
|
||
Transform t = cachedTransform;
|
||
Vector3 pos = t.position;
|
||
float z = t.localPosition.z;
|
||
pos.x += (before.x - after.x);
|
||
pos.y += (before.y - after.y);
|
||
cachedTransform.position = pos;
|
||
|
||
pos = cachedTransform.localPosition;
|
||
pos.x = Mathf.Round(pos.x);
|
||
pos.y = Mathf.Round(pos.y);
|
||
pos.z = z;
|
||
cachedTransform.localPosition = pos;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Depth controls the rendering order -- lowest to highest.
|
||
/// </summary>
|
||
|
||
public int depth
|
||
{
|
||
get
|
||
{
|
||
// Experiment with a transform-based depth, uGUI style
|
||
//if (mDepth == int.MinValue)
|
||
//{
|
||
// int val = cachedTransform.GetSiblingIndex();
|
||
// UIWidget pt = parent as UIWidget;
|
||
// if (pt != null) val += pt.depth;
|
||
// return val;
|
||
//}
|
||
return mDepth;
|
||
}
|
||
set
|
||
{
|
||
if (mDepth != value)
|
||
{
|
||
if (panel != null) panel.RemoveWidget(this);
|
||
mDepth = value;
|
||
|
||
if (panel != null)
|
||
{
|
||
panel.AddWidget(this);
|
||
|
||
if (!Application.isPlaying)
|
||
{
|
||
panel.SortWidgets();
|
||
panel.RebuildAllDrawCalls();
|
||
}
|
||
}
|
||
#if UNITY_EDITOR
|
||
NGUITools.SetDirty(this);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Raycast depth order on widgets takes the depth of their panel into consideration.
|
||
/// This functionality is used to determine the "final" depth of the widget for drawing and raycasts.
|
||
/// </summary>
|
||
|
||
public int raycastDepth
|
||
{
|
||
get
|
||
{
|
||
if (panel == null) CreatePanel();
|
||
return (panel != null) ? mDepth + panel.depth * 10000 : mDepth;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Local space corners of the widget. The order is bottom-left, top-left, top-right, bottom-right.
|
||
/// </summary>
|
||
|
||
public override Vector3[] localCorners
|
||
{
|
||
get
|
||
{
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
|
||
mCorners[0] = new Vector3(x0, y0);
|
||
mCorners[1] = new Vector3(x0, y1);
|
||
mCorners[2] = new Vector3(x1, y1);
|
||
mCorners[3] = new Vector3(x1, y0);
|
||
|
||
return mCorners;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Local width and height of the widget in pixels.
|
||
/// </summary>
|
||
|
||
public virtual Vector2 localSize
|
||
{
|
||
get
|
||
{
|
||
Vector3[] cr = localCorners;
|
||
return cr[2] - cr[0];
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Widget's center in local coordinates. Don't forget to transform by the widget's transform.
|
||
/// </summary>
|
||
|
||
public Vector3 localCenter
|
||
{
|
||
get
|
||
{
|
||
Vector3[] cr = localCorners;
|
||
return Vector3.Lerp(cr[0], cr[2], 0.5f);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// World-space corners of the widget. The order is bottom-left, top-left, top-right, bottom-right.
|
||
/// </summary>
|
||
|
||
public override Vector3[] worldCorners
|
||
{
|
||
get
|
||
{
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
|
||
Transform wt = cachedTransform;
|
||
|
||
mCorners[0] = wt.TransformPoint(x0, y0, 0f);
|
||
mCorners[1] = wt.TransformPoint(x0, y1, 0f);
|
||
mCorners[2] = wt.TransformPoint(x1, y1, 0f);
|
||
mCorners[3] = wt.TransformPoint(x1, y0, 0f);
|
||
|
||
return mCorners;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// World-space center of the widget.
|
||
/// </summary>
|
||
|
||
public Vector3 worldCenter { get { return cachedTransform.TransformPoint(localCenter); } }
|
||
|
||
/// <summary>
|
||
/// Local space region where the actual drawing will take place.
|
||
/// X = left, Y = bottom, Z = right, W = top.
|
||
/// </summary>
|
||
|
||
public virtual Vector4 drawingDimensions
|
||
{
|
||
get
|
||
{
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
|
||
return new Vector4(
|
||
mDrawRegion.x == 0f ? x0 : Mathf.Lerp(x0, x1, mDrawRegion.x),
|
||
mDrawRegion.y == 0f ? y0 : Mathf.Lerp(y0, y1, mDrawRegion.y),
|
||
mDrawRegion.z == 1f ? x1 : Mathf.Lerp(x0, x1, mDrawRegion.z),
|
||
mDrawRegion.w == 1f ? y1 : Mathf.Lerp(y0, y1, mDrawRegion.w));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Material used by the widget.
|
||
/// </summary>
|
||
|
||
public virtual Material material
|
||
{
|
||
get
|
||
{
|
||
return null;
|
||
}
|
||
set
|
||
{
|
||
throw new System.NotImplementedException(GetType() + " has no material setter");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Texture used by the widget.
|
||
/// </summary>
|
||
|
||
public virtual Texture mainTexture
|
||
{
|
||
get
|
||
{
|
||
Material mat = material;
|
||
return (mat != null) ? mat.mainTexture : null;
|
||
}
|
||
set
|
||
{
|
||
throw new System.NotImplementedException(GetType() + " has no mainTexture setter");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Shader is used to create a dynamic material if the widget has no material to work with.
|
||
/// </summary>
|
||
|
||
public virtual Shader shader
|
||
{
|
||
get
|
||
{
|
||
Material mat = material;
|
||
return (mat != null) ? mat.shader : null;
|
||
}
|
||
set
|
||
{
|
||
throw new System.NotImplementedException(GetType() + " has no shader setter");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Do not use this, it's obsolete.
|
||
/// </summary>
|
||
|
||
[System.Obsolete("There is no relative scale anymore. Widgets now have width and height instead")]
|
||
public Vector2 relativeSize { get { return Vector2.one; } }
|
||
|
||
/// <summary>
|
||
/// Convenience function that returns 'true' if the widget has a box collider.
|
||
/// </summary>
|
||
|
||
public bool hasBoxCollider
|
||
{
|
||
get
|
||
{
|
||
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7
|
||
BoxCollider box = collider as BoxCollider;
|
||
#else
|
||
BoxCollider box = GetComponent<Collider>() as BoxCollider;
|
||
#endif
|
||
if (box != null) return true;
|
||
return GetComponent<BoxCollider2D>() != null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Adjust the widget's dimensions without going through the anchor validation logic.
|
||
/// </summary>
|
||
|
||
public void SetDimensions (int w, int h)
|
||
{
|
||
if (mWidth != w || mHeight != h)
|
||
{
|
||
mWidth = w;
|
||
mHeight = h;
|
||
|
||
if (keepAspectRatio == AspectRatioSource.BasedOnWidth)
|
||
mHeight = Mathf.RoundToInt(mWidth / aspectRatio);
|
||
else if (keepAspectRatio == AspectRatioSource.BasedOnHeight)
|
||
mWidth = Mathf.RoundToInt(mHeight * aspectRatio);
|
||
else if (keepAspectRatio == AspectRatioSource.Free)
|
||
aspectRatio = mWidth / (float)mHeight;
|
||
|
||
mMoved = true;
|
||
if (autoResizeBoxCollider) ResizeCollider();
|
||
MarkAsChanged();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get the sides of the rectangle relative to the specified transform.
|
||
/// The order is left, top, right, bottom.
|
||
/// </summary>
|
||
|
||
public override Vector3[] GetSides (Transform relativeTo)
|
||
{
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
float cx = (x0 + x1) * 0.5f;
|
||
float cy = (y0 + y1) * 0.5f;
|
||
|
||
Transform trans = cachedTransform;
|
||
mCorners[0] = trans.TransformPoint(x0, cy, 0f);
|
||
mCorners[1] = trans.TransformPoint(cx, y1, 0f);
|
||
mCorners[2] = trans.TransformPoint(x1, cy, 0f);
|
||
mCorners[3] = trans.TransformPoint(cx, y0, 0f);
|
||
|
||
if (relativeTo != null)
|
||
{
|
||
for (int i = 0; i < 4; ++i)
|
||
mCorners[i] = relativeTo.InverseTransformPoint(mCorners[i]);
|
||
}
|
||
return mCorners;
|
||
}
|
||
|
||
[System.NonSerialized] int mAlphaFrameID = -1;
|
||
|
||
#if FUNCELL_MODIFIED
|
||
public override void SelfCalculateFinalAlpha(float parentAlpha)
|
||
{
|
||
finalAlpha = parentAlpha * mColor.a;
|
||
for(int i = 0; i < mChildren.size; ++i)
|
||
{
|
||
mChildren[i].SelfCalculateFinalAlpha(finalAlpha);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// Widget's final alpha, after taking the panel's alpha into account.
|
||
/// </summary>
|
||
///
|
||
|
||
public override float CalculateFinalAlpha (int frameID)
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (mAlphaFrameID != frameID || !Application.isPlaying)
|
||
#else
|
||
if (mAlphaFrameID != frameID)
|
||
#endif
|
||
{
|
||
mAlphaFrameID = frameID;
|
||
UpdateFinalAlpha(frameID);
|
||
}
|
||
return finalAlpha;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Force-calculate the final alpha value.
|
||
/// </summary>
|
||
|
||
protected void UpdateFinalAlpha (int frameID)
|
||
{
|
||
if (!mIsVisibleByAlpha || !mIsInFront)
|
||
{
|
||
finalAlpha = 0f;
|
||
}
|
||
else
|
||
{
|
||
UIRect pt = parent;
|
||
finalAlpha = (pt != null) ? pt.CalculateFinalAlpha(frameID) * mColor.a : mColor.a;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Update the widget's visibility and final alpha.
|
||
/// </summary>
|
||
|
||
public override void Invalidate (bool includeChildren, bool onlyAlphaChange = false)
|
||
{
|
||
if(!onlyAlphaChange)
|
||
{
|
||
mChanged = true;
|
||
}
|
||
mAlphaFrameID = -1;
|
||
|
||
if (panel != null)
|
||
{
|
||
bool vis = (hideIfOffScreen || panel.hasCumulativeClipping) ? panel.IsVisible(this) : true;
|
||
UpdateVisibility(CalculateCumulativeAlpha(Time.frameCount) > 0.001f, vis);
|
||
UpdateFinalAlpha(Time.frameCount);
|
||
if (includeChildren) base.Invalidate(true, onlyAlphaChange);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Same as final alpha, except it doesn't take own visibility into consideration. Used by panels.
|
||
/// </summary>
|
||
|
||
public float CalculateCumulativeAlpha (int frameID)
|
||
{
|
||
UIRect pt = parent;
|
||
return (pt != null) ? pt.CalculateFinalAlpha(frameID) * mColor.a : mColor.a;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Set the widget's rectangle.
|
||
/// </summary>
|
||
|
||
public override void SetRect (float x, float y, float width, float height)
|
||
{
|
||
Vector2 po = pivotOffset;
|
||
|
||
float fx = Mathf.Lerp(x, x + width, po.x);
|
||
float fy = Mathf.Lerp(y, y + height, po.y);
|
||
|
||
int finalWidth = Mathf.FloorToInt(width + 0.5f);
|
||
int finalHeight = Mathf.FloorToInt(height + 0.5f);
|
||
|
||
if (po.x == 0.5f) finalWidth = ((finalWidth >> 1) << 1);
|
||
if (po.y == 0.5f) finalHeight = ((finalHeight >> 1) << 1);
|
||
|
||
Transform t = cachedTransform;
|
||
Vector3 pos = t.localPosition;
|
||
pos.x = Mathf.Floor(fx + 0.5f);
|
||
pos.y = Mathf.Floor(fy + 0.5f);
|
||
|
||
if (finalWidth < minWidth) finalWidth = minWidth;
|
||
if (finalHeight < minHeight) finalHeight = minHeight;
|
||
|
||
t.localPosition = pos;
|
||
this.width = finalWidth;
|
||
this.height = finalHeight;
|
||
|
||
if (isAnchored)
|
||
{
|
||
t = t.parent;
|
||
|
||
if (leftAnchor.target) leftAnchor.SetHorizontal(t, x);
|
||
if (rightAnchor.target) rightAnchor.SetHorizontal(t, x + width);
|
||
if (bottomAnchor.target) bottomAnchor.SetVertical(t, y);
|
||
if (topAnchor.target) topAnchor.SetVertical(t, y + height);
|
||
#if UNITY_EDITOR
|
||
NGUITools.SetDirty(this);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Adjust the widget's collider size to match the widget's dimensions.
|
||
/// </summary>
|
||
|
||
public void ResizeCollider () { if (this.enabled) NGUITools.UpdateWidgetCollider(gameObject); }
|
||
|
||
/// <summary>
|
||
/// Static widget comparison function used for depth sorting.
|
||
/// </summary>
|
||
|
||
[System.Diagnostics.DebuggerHidden]
|
||
[System.Diagnostics.DebuggerStepThrough]
|
||
static public int FullCompareFunc (UIWidget left, UIWidget right)
|
||
{
|
||
int val = UIPanel.CompareFunc(left.panel, right.panel);
|
||
return (val == 0) ? PanelCompareFunc(left, right) : val;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Static widget comparison function used for inter-panel depth sorting.
|
||
/// </summary>
|
||
|
||
[System.Diagnostics.DebuggerHidden]
|
||
[System.Diagnostics.DebuggerStepThrough]
|
||
static public int PanelCompareFunc (UIWidget left, UIWidget right)
|
||
{
|
||
if (left.mDepth < right.mDepth) return -1;
|
||
if (left.mDepth > right.mDepth) return 1;
|
||
|
||
Material leftMat = left.material;
|
||
Material rightMat = right.material;
|
||
|
||
if (leftMat == rightMat) return 0;
|
||
if (leftMat == null) return 1;
|
||
if (rightMat == null) return -1;
|
||
|
||
#if FUNCELL_MODIFIED
|
||
bool leftGray = left.IsGray;
|
||
bool rightGray = right.IsGray;
|
||
|
||
if (leftGray == rightGray) return 0;
|
||
if (leftGray) return 1;
|
||
if (rightGray) return -1;
|
||
|
||
bool leftFlow = left.IsFlowLight;
|
||
bool rightFlow = right.IsFlowLight;
|
||
|
||
if (leftFlow == rightFlow) return 0;
|
||
if (leftFlow) return 1;
|
||
if (rightFlow) return -1;
|
||
|
||
bool leftOverlay = left.IsOverlay;
|
||
bool rightOverlay = right.IsOverlay;
|
||
|
||
if (leftOverlay == rightOverlay) return 0;
|
||
if (leftOverlay) return 1;
|
||
if (rightOverlay) return -1;
|
||
#endif
|
||
|
||
return (leftMat.GetHashCode() < rightMat.GetHashCode()) ? -1 : 1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Calculate the widget's bounds, optionally making them relative to the specified transform.
|
||
/// </summary>
|
||
|
||
public Bounds CalculateBounds () { return CalculateBounds(null); }
|
||
|
||
/// <summary>
|
||
/// Calculate the widget's bounds, optionally making them relative to the specified transform.
|
||
/// </summary>
|
||
|
||
public Bounds CalculateBounds (Transform relativeParent)
|
||
{
|
||
if (relativeParent == null)
|
||
{
|
||
Vector3[] corners = localCorners;
|
||
Bounds b = new Bounds(corners[0], Vector3.zero);
|
||
for (int j = 1; j < 4; ++j) b.Encapsulate(corners[j]);
|
||
return b;
|
||
}
|
||
else
|
||
{
|
||
Matrix4x4 toLocal = relativeParent.worldToLocalMatrix;
|
||
Vector3[] corners = worldCorners;
|
||
Bounds b = new Bounds(toLocal.MultiplyPoint3x4(corners[0]), Vector3.zero);
|
||
for (int j = 1; j < 4; ++j) b.Encapsulate(toLocal.MultiplyPoint3x4(corners[j]));
|
||
return b;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Mark the widget as changed so that the geometry can be rebuilt.
|
||
/// </summary>
|
||
|
||
public void SetDirty ()
|
||
{
|
||
if (drawCall != null)
|
||
{
|
||
drawCall.isDirty = true;
|
||
}
|
||
else if (isVisible && hasVertices)
|
||
{
|
||
CreatePanel();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Remove this widget from the panel.
|
||
/// </summary>
|
||
|
||
public void RemoveFromPanel ()
|
||
{
|
||
if (panel != null)
|
||
{
|
||
panel.RemoveWidget(this);
|
||
panel = null;
|
||
_panelInstID = 0;
|
||
}
|
||
drawCall = null;
|
||
#if UNITY_EDITOR
|
||
mOldTex = null;
|
||
mOldShader = null;
|
||
#endif
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
[System.NonSerialized] Texture mOldTex;
|
||
[System.NonSerialized] Shader mOldShader;
|
||
|
||
/// <summary>
|
||
/// This callback is sent inside the editor notifying us that some property has changed.
|
||
/// </summary>
|
||
|
||
protected override void OnValidate()
|
||
{
|
||
if (NGUITools.GetActive(this))
|
||
{
|
||
base.OnValidate();
|
||
|
||
// Prior to NGUI 2.7.0 width and height was specified as transform's local scale
|
||
if ((mWidth == 100 || mWidth == minWidth) &&
|
||
(mHeight == 100 || mHeight == minHeight) && cachedTransform.localScale.magnitude > 8f)
|
||
{
|
||
UpgradeFrom265();
|
||
cachedTransform.localScale = Vector3.one;
|
||
}
|
||
|
||
if (mWidth < minWidth) mWidth = minWidth;
|
||
if (mHeight < minHeight) mHeight = minHeight;
|
||
if (autoResizeBoxCollider) ResizeCollider();
|
||
|
||
// If the texture is changing, we need to make sure to rebuild the draw calls
|
||
if (mOldTex != mainTexture || mOldShader != shader)
|
||
{
|
||
mOldTex = mainTexture;
|
||
mOldShader = shader;
|
||
}
|
||
|
||
aspectRatio = (keepAspectRatio == AspectRatioSource.Free) ?
|
||
(float)mWidth / mHeight : Mathf.Max(0.01f, aspectRatio);
|
||
|
||
if (keepAspectRatio == AspectRatioSource.BasedOnHeight)
|
||
{
|
||
mWidth = Mathf.RoundToInt(mHeight * aspectRatio);
|
||
}
|
||
else if (keepAspectRatio == AspectRatioSource.BasedOnWidth)
|
||
{
|
||
mHeight = Mathf.RoundToInt(mWidth / aspectRatio);
|
||
}
|
||
|
||
if (!Application.isPlaying)
|
||
{
|
||
if (panel != null)
|
||
{
|
||
panel.RemoveWidget(this);
|
||
panel = null;
|
||
_panelInstID = 0;
|
||
}
|
||
CreatePanel();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (mWidth < minWidth) mWidth = minWidth;
|
||
if (mHeight < minHeight) mHeight = minHeight;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// Tell the panel responsible for the widget that something has changed and the buffers need to be rebuilt.
|
||
/// </summary>
|
||
|
||
public virtual void MarkAsChanged ()
|
||
{
|
||
if (NGUITools.GetActive(this))
|
||
{
|
||
mChanged = true;
|
||
#if UNITY_EDITOR
|
||
NGUITools.SetDirty(this);
|
||
#endif
|
||
// If we're in the editor, update the panel right away so its geometry gets updated.
|
||
if (panel != null && enabled && NGUITools.GetActive(gameObject) && !mPlayMode)
|
||
{
|
||
SetDirty();
|
||
CheckLayer();
|
||
#if UNITY_EDITOR
|
||
// Mark the panel as dirty so it gets updated
|
||
if (material != null) NGUITools.SetDirty(panel.gameObject);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
#if FUNCELL_MODIFIED
|
||
/// <summary>
|
||
/// Ensure we have a panel referencing this widget.
|
||
/// </summary>
|
||
public bool CreatePanel ()
|
||
{
|
||
try
|
||
{
|
||
bool isActive = false;
|
||
try
|
||
{
|
||
isActive = NGUITools.GetActive(gameObject);
|
||
}
|
||
catch (System.Exception ex0)
|
||
{
|
||
Debug.LogError("NGUITools.GetActive::::::" + ID.ToString() + "::::" + ex0.Message);
|
||
Debug.LogException(ex0);
|
||
return false;
|
||
}
|
||
if (mStarted && panel == null && enabled && isActive)
|
||
{
|
||
|
||
panel = UIPanel.Find(cachedTransform, true, cachedGameObject.layer);
|
||
if (panel != null)
|
||
{
|
||
mParentFound = false;
|
||
panel.AddWidget(this);
|
||
CheckLayer();
|
||
Invalidate(true);
|
||
}
|
||
|
||
}
|
||
}
|
||
catch (System.Exception ex1)
|
||
{
|
||
Debug.LogError("CreatePanel::::::" + ID.ToString() + "::::" + ex1.Message);
|
||
Debug.LogException(ex1);
|
||
return false;
|
||
}
|
||
_panelInstID = 0;
|
||
if (panel) _panelInstID = panel.GetInstanceID();
|
||
return true;
|
||
}
|
||
|
||
#else
|
||
/// <summary>
|
||
/// Ensure we have a panel referencing this widget.
|
||
/// </summary>
|
||
|
||
public UIPanel CreatePanel ()
|
||
{
|
||
if (mStarted && panel == null && enabled && NGUITools.GetActive(gameObject))
|
||
{
|
||
panel = UIPanel.Find(cachedTransform, true, cachedGameObject.layer);
|
||
|
||
if (panel != null)
|
||
{
|
||
mParentFound = false;
|
||
panel.AddWidget(this);
|
||
CheckLayer();
|
||
Invalidate(true);
|
||
}
|
||
}
|
||
if (panel) _panelInstID = panel.GetInstanceID();
|
||
return panel;
|
||
}
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// Check to ensure that the widget resides on the same layer as its panel.
|
||
/// </summary>
|
||
|
||
public void CheckLayer ()
|
||
{
|
||
if (panel != null && panel.gameObject.layer != gameObject.layer)
|
||
{
|
||
#if UNITY_EDITOR
|
||
Debug.LogWarning("You can't place widgets on a layer different than the UIPanel that manages them.\n" +
|
||
"If you want to move widgets to a different layer, parent them to a new panel instead.", this);
|
||
#endif
|
||
gameObject.layer = panel.gameObject.layer;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Checks to ensure that the widget is still parented to the right panel.
|
||
/// </summary>
|
||
|
||
public override void ParentHasChanged ()
|
||
{
|
||
base.ParentHasChanged();
|
||
|
||
if (panel != null)
|
||
{
|
||
UIPanel p = UIPanel.Find(cachedTransform, true, cachedGameObject.layer);
|
||
|
||
if (panel != p)
|
||
{
|
||
RemoveFromPanel();
|
||
CreatePanel();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Remember whether we're in play mode.
|
||
/// </summary>
|
||
|
||
protected override void Awake ()
|
||
{
|
||
base.Awake();
|
||
mPlayMode = Application.isPlaying;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Mark the widget and the panel as having been changed.
|
||
/// </summary>
|
||
|
||
protected override void OnInit ()
|
||
{
|
||
base.OnInit();
|
||
RemoveFromPanel();
|
||
mMoved = true;
|
||
|
||
// Prior to NGUI 2.7.0 width and height was specified as transform's local scale
|
||
if (mWidth == 100 && mHeight == 100 && cachedTransform.localScale.magnitude > 8f)
|
||
{
|
||
UpgradeFrom265();
|
||
cachedTransform.localScale = Vector3.one;
|
||
#if UNITY_EDITOR
|
||
NGUITools.SetDirty(this);
|
||
#endif
|
||
}
|
||
#if FUNCELL_MODIFIED
|
||
SelfUpdate();
|
||
#else
|
||
Update();
|
||
#endif
|
||
}
|
||
|
||
/// <summary>
|
||
/// Facilitates upgrading from NGUI 2.6.5 or earlier versions.
|
||
/// </summary>
|
||
|
||
protected virtual void UpgradeFrom265 ()
|
||
{
|
||
Vector3 scale = cachedTransform.localScale;
|
||
mWidth = Mathf.Abs(Mathf.RoundToInt(scale.x));
|
||
mHeight = Mathf.Abs(Mathf.RoundToInt(scale.y));
|
||
NGUITools.UpdateWidgetCollider(gameObject, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Virtual Start() functionality for widgets.
|
||
/// </summary>
|
||
|
||
protected override void OnStart ()
|
||
{
|
||
#if UNITY_EDITOR
|
||
if (GetComponent<UIPanel>() != null)
|
||
{
|
||
Debug.LogError("Widgets and panels should not be on the same object! Widget must be a child of the panel.", this);
|
||
}
|
||
else if (!Application.isPlaying && GetComponents<UIWidget>().Length > 1)
|
||
{
|
||
Debug.LogError("You should not place more than one widget on the same object. Weird stuff will happen!", this);
|
||
}
|
||
#endif
|
||
CreatePanel();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Update the anchored edges and ensure the widget is registered with a panel.
|
||
/// </summary>
|
||
|
||
protected override void OnAnchor ()
|
||
{
|
||
float lt, bt, rt, tt;
|
||
Transform trans = cachedTransform;
|
||
Transform parent = trans.parent;
|
||
Vector3 pos = trans.localPosition;
|
||
Vector2 pvt = pivotOffset;
|
||
|
||
// Attempt to fast-path if all anchors match
|
||
if (leftAnchor.target == bottomAnchor.target &&
|
||
leftAnchor.target == rightAnchor.target &&
|
||
leftAnchor.target == topAnchor.target)
|
||
{
|
||
Vector3[] sides = leftAnchor.GetSides(parent);
|
||
|
||
if (sides != null)
|
||
{
|
||
lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
|
||
rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute;
|
||
bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute;
|
||
tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute;
|
||
mIsInFront = true;
|
||
}
|
||
else
|
||
{
|
||
// Anchored to a single transform
|
||
Vector3 lp = GetLocalPos(leftAnchor, parent);
|
||
lt = lp.x + leftAnchor.absolute;
|
||
bt = lp.y + bottomAnchor.absolute;
|
||
rt = lp.x + rightAnchor.absolute;
|
||
tt = lp.y + topAnchor.absolute;
|
||
mIsInFront = (!hideIfOffScreen || lp.z >= 0f);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
mIsInFront = true;
|
||
|
||
// Left anchor point
|
||
if (leftAnchor.target)
|
||
{
|
||
Vector3[] sides = leftAnchor.GetSides(parent);
|
||
|
||
if (sides != null)
|
||
{
|
||
lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute;
|
||
}
|
||
else
|
||
{
|
||
lt = GetLocalPos(leftAnchor, parent).x + leftAnchor.absolute;
|
||
}
|
||
}
|
||
else lt = pos.x - pvt.x * mWidth;
|
||
|
||
// Right anchor point
|
||
if (rightAnchor.target)
|
||
{
|
||
Vector3[] sides = rightAnchor.GetSides(parent);
|
||
|
||
if (sides != null)
|
||
{
|
||
rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute;
|
||
}
|
||
else
|
||
{
|
||
rt = GetLocalPos(rightAnchor, parent).x + rightAnchor.absolute;
|
||
}
|
||
}
|
||
else rt = pos.x - pvt.x * mWidth + mWidth;
|
||
|
||
// Bottom anchor point
|
||
if (bottomAnchor.target)
|
||
{
|
||
Vector3[] sides = bottomAnchor.GetSides(parent);
|
||
|
||
if (sides != null)
|
||
{
|
||
bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute;
|
||
}
|
||
else
|
||
{
|
||
bt = GetLocalPos(bottomAnchor, parent).y + bottomAnchor.absolute;
|
||
}
|
||
}
|
||
else bt = pos.y - pvt.y * mHeight;
|
||
|
||
// Top anchor point
|
||
if (topAnchor.target)
|
||
{
|
||
Vector3[] sides = topAnchor.GetSides(parent);
|
||
|
||
if (sides != null)
|
||
{
|
||
tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute;
|
||
}
|
||
else
|
||
{
|
||
tt = GetLocalPos(topAnchor, parent).y + topAnchor.absolute;
|
||
}
|
||
}
|
||
else tt = pos.y - pvt.y * mHeight + mHeight;
|
||
}
|
||
|
||
// Calculate the new position, width and height
|
||
Vector3 newPos = new Vector3(Mathf.Lerp(lt, rt, pvt.x), Mathf.Lerp(bt, tt, pvt.y), pos.z);
|
||
newPos.x = Mathf.Round(newPos.x);
|
||
newPos.y = Mathf.Round(newPos.y);
|
||
|
||
int w = Mathf.FloorToInt(rt - lt + 0.5f);
|
||
int h = Mathf.FloorToInt(tt - bt + 0.5f);
|
||
|
||
// Maintain the aspect ratio if requested and possible
|
||
if (keepAspectRatio != AspectRatioSource.Free && aspectRatio != 0f)
|
||
{
|
||
if (keepAspectRatio == AspectRatioSource.BasedOnHeight)
|
||
{
|
||
w = Mathf.RoundToInt(h * aspectRatio);
|
||
}
|
||
else h = Mathf.RoundToInt(w / aspectRatio);
|
||
}
|
||
|
||
// Don't let the width and height get too small
|
||
if (w < minWidth) w = minWidth;
|
||
if (h < minHeight) h = minHeight;
|
||
|
||
// Update the position if it has changed
|
||
if (Vector3.SqrMagnitude(pos - newPos) > 0.001f)
|
||
{
|
||
cachedTransform.localPosition = newPos;
|
||
if (mIsInFront) mChanged = true;
|
||
}
|
||
|
||
// Update the width and height if it has changed
|
||
if (mWidth != w || mHeight != h)
|
||
{
|
||
mWidth = w;
|
||
mHeight = h;
|
||
if (mIsInFront) mChanged = true;
|
||
if (autoResizeBoxCollider) ResizeCollider();
|
||
}
|
||
if (AnchorChanged != null)
|
||
{
|
||
AnchorChanged(cachedTransform);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Ensure we have a panel to work with.
|
||
/// </summary>
|
||
|
||
protected override bool OnUpdate ()
|
||
{
|
||
bool result = true;
|
||
#if FUNCELL_MODIFIED
|
||
|
||
//updatealpha
|
||
if (_oldAlpha != mColor.a)
|
||
{
|
||
var frame = Time.frameCount;
|
||
_oldAlpha = mColor.a;
|
||
var parentAlpha = 1f;
|
||
if(parent != null)
|
||
{
|
||
parentAlpha = parent.finalAlpha;
|
||
}
|
||
SelfCalculateFinalAlpha(parentAlpha);
|
||
}
|
||
|
||
#endif
|
||
|
||
/*
|
||
if (panel == null) result = CreatePanel();
|
||
#if UNITY_EDITOR
|
||
else if (!mPlayMode) ParentHasChanged();
|
||
#endif
|
||
*/
|
||
//这里把panel是否为空的判断,修改为通过InstID和异常来判断
|
||
try
|
||
{
|
||
if (_panelInstID == 0)
|
||
{
|
||
result = CreatePanel();
|
||
}
|
||
|
||
if (_panelInstID != 0)
|
||
{
|
||
_panelInstID = panel.GetInstanceID();
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
if (!mPlayMode) ParentHasChanged();
|
||
#endif
|
||
}
|
||
catch
|
||
{
|
||
result = CreatePanel();
|
||
}
|
||
return result;
|
||
|
||
}
|
||
|
||
#if !UNITY_EDITOR
|
||
/// <summary>
|
||
/// Mark the UI as changed when returning from paused state.
|
||
/// </summary>
|
||
|
||
void OnApplicationPause (bool paused) { if (!paused) MarkAsChanged(); }
|
||
#endif
|
||
|
||
/// <summary>
|
||
/// Clear references.
|
||
/// </summary>
|
||
|
||
protected override void OnDisable ()
|
||
{
|
||
geometry.FreeCache();
|
||
RemoveFromPanel();
|
||
base.OnDisable();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Unregister this widget.
|
||
/// </summary>
|
||
|
||
//void OnDestroy () { RemoveFromPanel(); }
|
||
#if FUNCELL_MODIFIED
|
||
//优化NGUI GC
|
||
protected override void OnDestroy()
|
||
{
|
||
geometry.FreeCache();
|
||
RemoveFromPanel();
|
||
base.OnDestroy();
|
||
}
|
||
#else
|
||
void OnDestroy ()
|
||
{
|
||
geometry.FreeCache();
|
||
RemoveFromPanel();
|
||
}
|
||
#endif
|
||
//优化NGUI GC
|
||
//void OnDestroy() { RemoveFromPanel(); }
|
||
|
||
#if UNITY_EDITOR
|
||
static int mHandles = -1;
|
||
|
||
/// <summary>
|
||
/// Whether widgets will show handles with the Move Tool, or just the View Tool.
|
||
/// </summary>
|
||
|
||
static public bool showHandlesWithMoveTool
|
||
{
|
||
get
|
||
{
|
||
if (mHandles == -1)
|
||
{
|
||
mHandles = UnityEditor.EditorPrefs.GetInt("NGUI Handles", 1);
|
||
}
|
||
return (mHandles == 1);
|
||
}
|
||
set
|
||
{
|
||
int val = value ? 1 : 0;
|
||
|
||
if (mHandles != val)
|
||
{
|
||
mHandles = val;
|
||
UnityEditor.EditorPrefs.SetInt("NGUI Handles", mHandles);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Whether the widget should have some form of handles shown.
|
||
/// </summary>
|
||
|
||
static public bool showHandles
|
||
{
|
||
get
|
||
{
|
||
#if UNITY_4_3 || UNITY_4_5
|
||
if (showHandlesWithMoveTool)
|
||
{
|
||
return UnityEditor.Tools.current == UnityEditor.Tool.Move;
|
||
}
|
||
return UnityEditor.Tools.current == UnityEditor.Tool.View;
|
||
#else
|
||
return UnityEditor.Tools.current == UnityEditor.Tool.Rect;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Draw some selectable gizmos.
|
||
/// </summary>
|
||
|
||
void OnDrawGizmos ()
|
||
{
|
||
if (isVisible && NGUITools.GetActive(this))
|
||
{
|
||
if (UnityEditor.Selection.activeGameObject == gameObject && showHandles) return;
|
||
|
||
Color outline = new Color(1f, 1f, 1f, 0.2f);
|
||
|
||
float adjustment = (root != null) ? 0.05f : 0.001f;
|
||
Vector2 offset = pivotOffset;
|
||
Vector3 center = new Vector3(mWidth * (0.5f - offset.x), mHeight * (0.5f - offset.y), -mDepth * adjustment);
|
||
Vector3 size = new Vector3(mWidth, mHeight, 1f);
|
||
|
||
// Draw the gizmo
|
||
Gizmos.matrix = cachedTransform.localToWorldMatrix;
|
||
Gizmos.color = (UnityEditor.Selection.activeGameObject == cachedTransform) ? Color.white : outline;
|
||
Gizmos.DrawWireCube(center, size);
|
||
|
||
// Make the widget selectable
|
||
size.z = 0.01f;
|
||
Gizmos.color = Color.clear;
|
||
Gizmos.DrawCube(center, size);
|
||
}
|
||
}
|
||
#endif // UNITY_EDITOR
|
||
|
||
/// <summary>
|
||
/// Update the widget's visibility state.
|
||
/// </summary>
|
||
|
||
public bool UpdateVisibility (bool visibleByAlpha, bool visibleByPanel)
|
||
{
|
||
if (mIsVisibleByAlpha != visibleByAlpha || mIsVisibleByPanel != visibleByPanel)
|
||
{
|
||
mChanged = true;
|
||
mIsVisibleByAlpha = visibleByAlpha;
|
||
mIsVisibleByPanel = visibleByPanel;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
int mMatrixFrame = -1;
|
||
Vector3 mOldV0;
|
||
Vector3 mOldV1;
|
||
|
||
/// <summary>
|
||
/// Check to see if the widget has moved relative to the panel that manages it
|
||
/// </summary>
|
||
|
||
public bool UpdateTransform (int frame)
|
||
{
|
||
Transform trans = cachedTransform;
|
||
|
||
#if UNITY_EDITOR
|
||
mPlayMode = Application.isPlaying;
|
||
if (mMoved || !mPlayMode)
|
||
#else
|
||
mPlayMode = true;
|
||
if (mMoved)
|
||
#endif
|
||
{
|
||
mMoved = true;
|
||
mMatrixFrame = -1;
|
||
trans.hasChanged = false;
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
|
||
mOldV0 = panel.worldToLocal.MultiplyPoint3x4(trans.TransformPoint(x0, y0, 0f));
|
||
mOldV1 = panel.worldToLocal.MultiplyPoint3x4(trans.TransformPoint(x1, y1, 0f));
|
||
}
|
||
else if (!panel.widgetsAreStatic && trans.hasChanged)
|
||
{
|
||
mMatrixFrame = -1;
|
||
trans.hasChanged = false;
|
||
Vector2 offset = pivotOffset;
|
||
|
||
float x0 = -offset.x * mWidth;
|
||
float y0 = -offset.y * mHeight;
|
||
float x1 = x0 + mWidth;
|
||
float y1 = y0 + mHeight;
|
||
|
||
Vector3 v0 = panel.worldToLocal.MultiplyPoint3x4(trans.TransformPoint(x0, y0, 0f));
|
||
Vector3 v1 = panel.worldToLocal.MultiplyPoint3x4(trans.TransformPoint(x1, y1, 0f));
|
||
|
||
if (Vector3.SqrMagnitude(mOldV0 - v0) > 0.000001f ||
|
||
Vector3.SqrMagnitude(mOldV1 - v1) > 0.000001f)
|
||
{
|
||
mMoved = true;
|
||
mOldV0 = v0;
|
||
mOldV1 = v1;
|
||
}
|
||
}
|
||
|
||
// Notify the listeners
|
||
if (mMoved && onChange != null) onChange();
|
||
return mMoved || mChanged;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Update the widget and fill its geometry if necessary. Returns whether something was changed.
|
||
/// </summary>
|
||
|
||
public bool UpdateGeometry (int frame)
|
||
{
|
||
// Has the alpha changed?
|
||
#if FUNCELL_MODIFIED
|
||
float finalAlpha = this.finalAlpha;
|
||
#else
|
||
float finalAlpha = CalculateFinalAlpha(frame);
|
||
#endif
|
||
var alphaChanged = false;
|
||
if (mIsVisibleByAlpha && mLastAlpha != finalAlpha)
|
||
{
|
||
alphaChanged = true;
|
||
}
|
||
mLastAlpha = finalAlpha;
|
||
|
||
if (mChanged)
|
||
{
|
||
if (mIsVisibleByAlpha && finalAlpha > 0.001f && shader != null)
|
||
{
|
||
bool hadVertices = geometry.hasVertices;
|
||
|
||
if (fillGeometry)
|
||
{
|
||
geometry.Clear();
|
||
OnFill(geometry.verts, geometry.uvs, geometry.cols);
|
||
}
|
||
|
||
if (geometry.hasVertices)
|
||
{
|
||
// Want to see what's being filled? Uncomment this line.
|
||
//Debug.Log("Fill " + name + " (" + Time.frameCount + ")");
|
||
|
||
if (mMatrixFrame != frame)
|
||
{
|
||
mLocalToPanel = panel.worldToLocal * cachedTransform.localToWorldMatrix;
|
||
mMatrixFrame = frame;
|
||
}
|
||
geometry.ApplyTransform(mLocalToPanel, panel.generateNormals,height,width);
|
||
mMoved = false;
|
||
mChanged = false;
|
||
return true;
|
||
}
|
||
|
||
mChanged = false;
|
||
return hadVertices;
|
||
}
|
||
else if (geometry.hasVertices)
|
||
{
|
||
if (fillGeometry) geometry.Clear();
|
||
mMoved = false;
|
||
mChanged = false;
|
||
return true;
|
||
}
|
||
}
|
||
else if (mMoved && geometry.hasVertices)
|
||
{
|
||
// Want to see what's being moved? Uncomment this line.
|
||
//Debug.Log("Moving " + name + " (" + Time.frameCount + ")");
|
||
|
||
if (mMatrixFrame != frame)
|
||
{
|
||
mLocalToPanel = panel.worldToLocal * cachedTransform.localToWorldMatrix;
|
||
mMatrixFrame = frame;
|
||
}
|
||
geometry.ApplyTransform(mLocalToPanel, panel.generateNormals,height,width);
|
||
mMoved = false;
|
||
mChanged = false;
|
||
return true;
|
||
}
|
||
else if(alphaChanged && geometry.hasVertices)
|
||
{
|
||
mMoved = false;
|
||
mChanged = false;
|
||
return true;
|
||
}
|
||
mMoved = false;
|
||
mChanged = false;
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Append the local geometry buffers to the specified ones.
|
||
/// </summary>
|
||
|
||
public void WriteToBuffers (BetterList<Vector3> v, BetterList<Vector2> u, BetterList<Color32> c, BetterList<Vector3> n, BetterList<Vector4> t)
|
||
{
|
||
geometry.WriteToBuffers(v, u, c, n, t, finalAlpha);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Make the widget pixel-perfect.
|
||
/// </summary>
|
||
|
||
virtual public void MakePixelPerfect ()
|
||
{
|
||
Vector3 pos = cachedTransform.localPosition;
|
||
pos.z = Mathf.Round(pos.z);
|
||
pos.x = Mathf.Round(pos.x);
|
||
pos.y = Mathf.Round(pos.y);
|
||
cachedTransform.localPosition = pos;
|
||
|
||
Vector3 ls = cachedTransform.localScale;
|
||
cachedTransform.localScale = new Vector3(Mathf.Sign(ls.x), Mathf.Sign(ls.y), 1f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Minimum allowed width for this widget.
|
||
/// </summary>
|
||
|
||
virtual public int minWidth { get { return 2; } }
|
||
|
||
/// <summary>
|
||
/// Minimum allowed height for this widget.
|
||
/// </summary>
|
||
|
||
virtual public int minHeight { get { return 2; } }
|
||
|
||
/// <summary>
|
||
/// Dimensions of the sprite's border, if any.
|
||
/// </summary>
|
||
|
||
virtual public Vector4 border { get { return Vector4.zero; } set { } }
|
||
|
||
/// <summary>
|
||
/// Virtual function called by the UIPanel that fills the buffers.
|
||
/// </summary>
|
||
|
||
virtual public void OnFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
|
||
{
|
||
// Call this in your derived classes:
|
||
//if (onPostFill != null)
|
||
// onPostFill(this, verts.size, verts, uvs, cols);
|
||
}
|
||
}
|