CTT/Unity/Assets/ThirdParty/FairyGUI/Scripts/UI/UIPanel.cs

616 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using UnityEngine;
namespace FairyGUI
{
/// <summary>
///
/// </summary>
public enum FitScreen
{
None,
FitSize,
FitWidthAndSetMiddle,
FitHeightAndSetCenter
}
/// <summary>
///
/// </summary>
[ExecuteInEditMode]
[AddComponentMenu("FairyGUI/UI Panel")]
public class UIPanel : MonoBehaviour, EMRenderTarget
{
/// <summary>
///
/// </summary>
public Container container { get; private set; }
/// <summary>
///
/// </summary>
public string packageName;
/// <summary>
///
/// </summary>
public string componentName;
/// <summary>
///
/// </summary>
public FitScreen fitScreen;
/// <summary>
///
/// </summary>
public int sortingOrder;
[SerializeField]
string packagePath;
[SerializeField]
RenderMode renderMode = RenderMode.ScreenSpaceOverlay;
[SerializeField]
Camera renderCamera = null;
[SerializeField]
Vector3 position;
[SerializeField]
Vector3 scale = new Vector3(1, 1, 1);
[SerializeField]
Vector3 rotation = new Vector3(0, 0, 0);
[SerializeField]
bool fairyBatching = false;
[SerializeField]
bool touchDisabled = false;
[SerializeField]
Vector2 cachedUISize;
[SerializeField]
HitTestMode hitTestMode = HitTestMode.Default;
[SerializeField]
bool setNativeChildrenOrder = false;
[System.NonSerialized]
int screenSizeVer;
[System.NonSerialized]
Rect uiBounds; //Track bounds even when UI is not created, edit mode
GComponent _ui;
[NonSerialized]
bool _created;
List<Renderer> _renders;
void OnEnable()
{
if (Application.isPlaying)
{
if (this.container == null)
{
CreateContainer();
if (!string.IsNullOrEmpty(packagePath) && UIPackage.GetByName(packageName) == null)
UIPackage.AddPackage(packagePath);
}
else
this.container._disabled = false;
}
else
{
//不在播放状态时我们不在OnEnable创建因为Prefab也会调用OnEnable延迟到Update里创建Prefab不调用Update)
//每次播放前都会disable/enable一次。。。
if (container != null)//如果不为null可能是因为Prefab revert 而不是因为Assembly reload
OnDestroy();
EMRenderSupport.Add(this);
screenSizeVer = 0;
uiBounds.position = position;
uiBounds.size = cachedUISize;
if (uiBounds.size == Vector2.zero)
uiBounds.size = new Vector2(30, 30);
}
}
void OnDisable()
{
if (Application.isPlaying)
{
if (this.container != null)
this.container._disabled = true;
}
else
EMRenderSupport.Remove(this);
}
void Start()
{
if (!_created && Application.isPlaying)
CreateUI_PlayMode();
}
void Update()
{
if (screenSizeVer != StageCamera.screenSizeVer)
HandleScreenSizeChanged();
}
void OnDestroy()
{
if (container != null)
{
if (!Application.isPlaying)
EMRenderSupport.Remove(this);
if (_ui != null)
{
_ui.Dispose();
_ui = null;
}
container.Dispose();
container = null;
}
_renders = null;
}
void CreateContainer()
{
if (!Application.isPlaying)
{
Transform t = this.transform;
int cnt = t.childCount;
while (cnt > 0)
{
GameObject go = t.GetChild(cnt - 1).gameObject;
if (go.name == "UI(AutoGenerated)")
UnityEngine.Object.DestroyImmediate(go);
cnt--;
}
}
this.container = new Container(this.gameObject);
this.container.renderMode = renderMode;
this.container.renderCamera = renderCamera;
this.container.touchable = !touchDisabled;
this.container._panelOrder = sortingOrder;
this.container.fairyBatching = fairyBatching;
if (Application.isPlaying)
{
SetSortingOrder(this.sortingOrder, true);
if (this.hitTestMode == HitTestMode.Raycast)
{
ColliderHitTest hitArea = new ColliderHitTest();
hitArea.collider = this.gameObject.AddComponent<BoxCollider>();
this.container.hitArea = hitArea;
}
if (setNativeChildrenOrder)
{
CacheNativeChildrenRenderers();
this.container.onUpdate = () =>
{
int cnt = _renders.Count;
int sv = UpdateContext.current.renderingOrder++;
for (int i = 0; i < cnt; i++)
{
Renderer r = _renders[i];
if (r != null)
_renders[i].sortingOrder = sv;
}
};
}
}
}
/// <summary>
///
/// </summary>
public GComponent ui
{
get
{
if (!_created && Application.isPlaying)
{
if (!string.IsNullOrEmpty(packagePath) && UIPackage.GetByName(packageName) == null)
UIPackage.AddPackage(packagePath);
CreateUI_PlayMode();
}
return _ui;
}
}
/// <summary>
///
/// </summary>
public void CreateUI()
{
if (_ui != null)
{
_ui.Dispose();
_ui = null;
}
CreateUI_PlayMode();
}
/// <summary>
/// Change the sorting order of the panel in runtime.
/// </summary>
/// <param name="value">sorting order value</param>
/// <param name="apply">false if you dont want the default sorting behavior. e.g. call Stage.SortWorldSpacePanelsByZOrder later.</param>
public void SetSortingOrder(int value, bool apply)
{
this.sortingOrder = value;
container._panelOrder = value;
if (apply)
Stage.inst.ApplyPanelOrder(container);
}
/// <summary>
///
/// </summary>
/// <param name="value"></param>
public void SetHitTestMode(HitTestMode value)
{
if (this.hitTestMode != value)
{
this.hitTestMode = value;
BoxCollider collider = this.gameObject.GetComponent<BoxCollider>();
if (this.hitTestMode == HitTestMode.Raycast)
{
if (collider == null)
collider = this.gameObject.AddComponent<BoxCollider>();
ColliderHitTest hitArea = new ColliderHitTest();
hitArea.collider = collider;
this.container.hitArea = hitArea;
if (_ui != null)
UpdateHitArea();
}
else
{
this.container.hitArea = null;
if (collider != null)
Component.Destroy(collider);
}
}
}
/// <summary>
///
/// </summary>
public void CacheNativeChildrenRenderers()
{
if (_renders == null)
_renders = new List<Renderer>();
else
_renders.Clear();
Transform t = this.container.cachedTransform;
int cnt = t.childCount;
for (int i = 0; i < cnt; i++)
{
GameObject go = t.GetChild(i).gameObject;
if (go.name != "GComponent")
_renders.AddRange(go.GetComponentsInChildren<Renderer>(true));
}
cnt = _renders.Count;
for (int i = 0; i < cnt; i++)
{
Renderer r = _renders[i];
if ((r is SkinnedMeshRenderer) || (r is MeshRenderer))
{
//Set the object rendering in Transparent Queue as UI objects
if (r.sharedMaterial != null)
r.sharedMaterial.renderQueue = 3000;
}
}
}
void CreateUI_PlayMode()
{
_created = true;
if (string.IsNullOrEmpty(packageName) || string.IsNullOrEmpty(componentName))
return;
_ui = (GComponent)UIPackage.CreateObject(packageName, componentName);
if (_ui != null)
{
_ui.position = position;
if (scale.x != 0 && scale.y != 0)
_ui.scale = scale;
_ui.rotationX = rotation.x;
_ui.rotationY = rotation.y;
_ui.rotation = rotation.z;
if (this.container.hitArea != null)
{
UpdateHitArea();
_ui.onSizeChanged.Add(UpdateHitArea);
_ui.onPositionChanged.Add(UpdateHitArea);
}
this.container.AddChildAt(_ui.displayObject, 0);
HandleScreenSizeChanged();
}
else
Debug.LogError("Create " + packageName + "/" + componentName + " failed!");
}
void UpdateHitArea()
{
ColliderHitTest hitArea = this.container.hitArea as ColliderHitTest;
if (hitArea != null)
{
((BoxCollider)hitArea.collider).center = new Vector3(_ui.xMin + _ui.width / 2, -_ui.yMin - _ui.height / 2);
((BoxCollider)hitArea.collider).size = _ui.size;
}
}
void CreateUI_EditMode()
{
if (!EMRenderSupport.packageListReady || UIPackage.GetByName(packageName) == null)
return;
#if (UNITY_5 || UNITY_5_3_OR_NEWER)
DisplayOptions.SetEditModeHideFlags();
GObject obj = UIPackage.CreateObject(packageName, componentName);
if (obj != null && !(obj is GComponent))
{
obj.Dispose();
Debug.LogWarning("Not a GComponnet: " + packageName + "/" + componentName);
return;
}
_ui = (GComponent)obj;
if (_ui != null)
{
_ui.displayObject.gameObject.hideFlags |= HideFlags.HideInHierarchy;
_ui.gameObjectName = "UI(AutoGenerated)";
_ui.position = position;
if (scale.x != 0 && scale.y != 0)
_ui.scale = scale;
_ui.rotationX = rotation.x;
_ui.rotationY = rotation.y;
_ui.rotation = rotation.z;
this.container.AddChildAt(_ui.displayObject, 0);
cachedUISize = _ui.size;
uiBounds.size = cachedUISize;
HandleScreenSizeChanged();
}
#else
PackageItem pi = UIPackage.GetByName(packageName).GetItemByName(componentName);
if (pi != null)
{
cachedUISize = new Vector2(pi.width, pi.height);
uiBounds.size = cachedUISize;
HandleScreenSizeChanged();
}
#endif
}
void HandleScreenSizeChanged()
{
if (!Application.isPlaying)
DisplayOptions.SetEditModeHideFlags();
screenSizeVer = StageCamera.screenSizeVer;
if (this.container != null)
{
if (this.container.renderMode != RenderMode.WorldSpace)
this.container.scale = new Vector2(StageCamera.UnitsPerPixel * UIContentScaler.scaleFactor, StageCamera.UnitsPerPixel * UIContentScaler.scaleFactor);
}
int width = Mathf.CeilToInt(Screen.width / UIContentScaler.scaleFactor);
int height = Mathf.CeilToInt(Screen.height / UIContentScaler.scaleFactor);
if (this._ui != null)
{
switch (fitScreen)
{
case FitScreen.FitSize:
this._ui.SetSize(width, height);
this._ui.SetXY(0, 0, true);
break;
case FitScreen.FitWidthAndSetMiddle:
this._ui.SetSize(width, this._ui.sourceHeight);
this._ui.SetXY(0, (int)((height - this._ui.sourceHeight) / 2), true);
break;
case FitScreen.FitHeightAndSetCenter:
this._ui.SetSize(this._ui.sourceWidth, height);
this._ui.SetXY((int)((width - this._ui.sourceWidth) / 2), 0, true);
break;
}
UpdateHitArea();
}
else
{
switch (fitScreen)
{
case FitScreen.FitSize:
uiBounds.position = new Vector2(0, 0);
uiBounds.size = new Vector2(width, height);
break;
case FitScreen.FitWidthAndSetMiddle:
uiBounds.position = new Vector2(0, (int)((height - cachedUISize.y) / 2));
uiBounds.size = new Vector2(width, cachedUISize.y);
break;
case FitScreen.FitHeightAndSetCenter:
uiBounds.position = new Vector2((int)((width - cachedUISize.x) / 2), 0);
uiBounds.size = new Vector2(cachedUISize.x, height);
break;
}
}
}
#region edit mode functions
void OnUpdateSource(object[] data)
{
if (Application.isPlaying)
return;
this.packageName = (string)data[0];
this.packagePath = (string)data[1];
this.componentName = (string)data[2];
if ((bool)data[3])
{
if (container == null)
return;
if (_ui != null)
{
_ui.Dispose();
_ui = null;
}
}
}
public void ApplyModifiedProperties(bool sortingOrderChanged, bool fitScreenChanged)
{
if (container != null)
{
container.renderMode = renderMode;
container.renderCamera = renderCamera;
if (sortingOrderChanged)
{
container._panelOrder = sortingOrder;
if (Application.isPlaying)
SetSortingOrder(sortingOrder, true);
else
EMRenderSupport.orderChanged = true;
}
container.fairyBatching = fairyBatching;
}
if (_ui != null)
{
if (fitScreen == FitScreen.None)
_ui.position = position;
if (scale.x != 0 && scale.y != 0)
_ui.scale = scale;
_ui.rotationX = rotation.x;
_ui.rotationY = rotation.y;
_ui.rotation = rotation.z;
}
if (fitScreen == FitScreen.None)
uiBounds.position = position;
screenSizeVer = 0;//force HandleScreenSizeChanged be called
if (fitScreenChanged && this.fitScreen == FitScreen.None)
{
if (this._ui != null)
this._ui.SetSize(this._ui.sourceWidth, this._ui.sourceHeight);
uiBounds.size = cachedUISize;
}
}
public void MoveUI(Vector3 delta)
{
if (fitScreen != FitScreen.None)
return;
this.position += delta;
if (_ui != null)
_ui.position = position;
uiBounds.position = position;
}
public Vector3 GetUIWorldPosition()
{
if (_ui != null)
return _ui.displayObject.cachedTransform.position;
else
return this.container.cachedTransform.TransformPoint(uiBounds.position);
}
void OnDrawGizmos()
{
if (Application.isPlaying || this.container == null)
return;
Vector3 pos, size;
if (this._ui != null)
{
Gizmos.matrix = this._ui.displayObject.cachedTransform.localToWorldMatrix;
pos = new Vector3(this._ui.width / 2, -this._ui.height / 2, 0);
size = new Vector3(this._ui.width, this._ui.height, 0);
}
else
{
Gizmos.matrix = this.container.cachedTransform.localToWorldMatrix;
pos = new Vector3(uiBounds.x + uiBounds.width / 2, -uiBounds.y - uiBounds.height / 2, 0);
size = new Vector3(uiBounds.width, uiBounds.height, 0);
}
Gizmos.color = new Color(0, 0, 0, 0);
Gizmos.DrawCube(pos, size);
Gizmos.color = Color.white;
Gizmos.DrawWireCube(pos, size);
}
public int EM_sortingOrder
{
get { return sortingOrder; }
}
public void EM_BeforeUpdate()
{
if (container == null)
CreateContainer();
if (packageName != null && componentName != null && _ui == null)
CreateUI_EditMode();
if (screenSizeVer != StageCamera.screenSizeVer)
HandleScreenSizeChanged();
}
public void EM_Update(UpdateContext context)
{
DisplayOptions.SetEditModeHideFlags();
container.Update(context);
if (setNativeChildrenOrder)
{
CacheNativeChildrenRenderers();
int cnt = _renders.Count;
int sv = context.renderingOrder++;
for (int i = 0; i < cnt; i++)
{
Renderer r = _renders[i];
if (r != null)
r.sortingOrder = sv;
}
}
}
public void EM_Reload()
{
if (_ui != null)
{
_ui.Dispose();
_ui = null;
}
}
#endregion
}
}