//------------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2019 Tasharen Entertainment Inc //------------------------------------------------- using UnityEngine; using System; using System.Collections.Generic; using System.IO; using System.Reflection; public class DoNotObfuscateNGUI : Attribute { } /// /// Helper class containing generic functions used throughout the UI library. /// static public class NGUITools { [System.NonSerialized] static AudioListener mListener; /// /// Audio source used to play UI sounds. NGUI will create one for you automatically, but you can specify it yourself as well if you like. /// [System.NonSerialized] static public AudioSource audioSource; static bool mLoaded = false; static float mGlobalVolume = 1f; /// /// Globally accessible volume affecting all sounds played via NGUITools.PlaySound(). /// static public float soundVolume { get { if (!mLoaded) { mLoaded = true; mGlobalVolume = PlayerPrefs.GetFloat("Sound", 1f); } return mGlobalVolume; } set { if (mGlobalVolume != value) { mLoaded = true; mGlobalVolume = value; PlayerPrefs.SetFloat("Sound", value); } } } /// /// Helper function -- whether the disk access is allowed. /// static public bool fileAccess { get { #if !UNITY_4_7 if (Application.platform == RuntimePlatform.WebGLPlayer) return false; #endif #if UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3 return Application.platform != RuntimePlatform.WindowsWebPlayer && Application.platform != RuntimePlatform.OSXWebPlayer; #else return true; #endif } } /// /// Play the specified audio clip. /// static public AudioSource PlaySound (AudioClip clip) { return PlaySound(clip, 1f, 1f); } /// /// Play the specified audio clip with the specified volume. /// static public AudioSource PlaySound (AudioClip clip, float volume,bool bInGame = false) { return PlaySound(clip, volume, 1f, bInGame); } static float mLastTimestamp = 0f; static AudioClip mLastClip; /// /// Play the specified audio clip with the specified volume and pitch. /// static public AudioSource PlaySound (AudioClip clip, float volume, float pitch, bool bInGame = false) { //if (!OptionManager.Instance.m_Sound) return null; //if (bInGame && SoundManager.Instance.bMenu) //return null; float time = RealTime.time; if (mLastClip == clip && mLastTimestamp + 0.1f > time) return null; mLastClip = clip; mLastTimestamp = time; volume *= soundVolume; if (clip != null && volume > 0.01f) { if (mListener == null || !NGUITools.GetActive(mListener)) { AudioListener[] listeners = GameObject.FindObjectsOfType(typeof(AudioListener)) as AudioListener[]; if (listeners != null) { for (int i = 0; i < listeners.Length; ++i) { if (NGUITools.GetActive(listeners[i])) { mListener = listeners[i]; break; } } } if (mListener == null) { #if W2 var cam = MainCamera.instance; #else var cam = Camera.main; #endif if (cam == null) cam = GameObject.FindObjectOfType(typeof(Camera)) as Camera; if (cam != null) mListener = cam.gameObject.AddComponent(); } } if (mListener != null && mListener.enabled && NGUITools.GetActive(mListener.gameObject)) { if (!audioSource) { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 audioSource = mListener.audio; #else audioSource = mListener.GetComponent(); #endif if (audioSource == null) audioSource = mListener.gameObject.AddComponent(); } #if !UNITY_FLASH audioSource.priority = 50; audioSource.pitch = pitch; #endif audioSource.PlayOneShot(clip, volume); return audioSource; } } return null; } /// /// New WWW call can fail if the crossdomain policy doesn't check out. Exceptions suck. It's much more elegant to check for null instead. /// // static public WWW OpenURL (string url) // { //#if UNITY_FLASH // Debug.LogError("WWW is not yet implemented in Flash"); // return null; //#else // WWW www = null; // try { www = new WWW(url); } // catch (System.Exception ex) { Debug.LogError(ex.Message); } // return www; //#endif // } // /// // /// New WWW call can fail if the crossdomain policy doesn't check out. Exceptions suck. It's much more elegant to check for null instead. // /// // static public WWW OpenURL (string url, WWWForm form) // { // if (form == null) return OpenURL(url); //#if UNITY_FLASH // Debug.LogError("WWW is not yet implemented in Flash"); // return null; //#else // WWW www = null; // try { www = new WWW(url, form); } // catch (System.Exception ex) { Debug.LogError(ex != null ? ex.Message : ""); } // return www; //#endif // } /// /// Same as Random.Range, but the returned value is between min and max, inclusive. /// Unity's Random.Range is less than max instead, unless min == max. /// This means Range(0,1) produces 0 instead of 0 or 1. That's unacceptable. /// static public int RandomRange (int min, int max) { if (min == max) return min; return UnityEngine.Random.Range(min, max + 1); } /// /// Returns the hierarchy of the object in a human-readable format. /// static public string GetHierarchy (GameObject obj) { if (obj == null) return ""; string path = obj.name; while (obj.transform.parent != null) { obj = obj.transform.parent.gameObject; path = obj.name + "\\" + path; } return path; } /// /// Find all active objects of specified type. /// static public T[] FindActive () where T : Component { return GameObject.FindObjectsOfType(typeof(T)) as T[]; } /// /// Find the camera responsible for drawing the objects on the specified layer. /// static public Camera FindCameraForLayer (int layer) { int layerMask = 1 << layer; Camera cam; for (int i = 0; i < UICamera.list.size; ++i) { cam = UICamera.list.buffer[i].cachedCamera; if (cam && (cam.cullingMask & layerMask) != 0) return cam; } #if W2 cam = MainCamera.instance; #else cam = Camera.main; #endif if (cam && (cam.cullingMask & layerMask) != 0) return cam; #if UNITY_4_3 || UNITY_FLASH Camera[] cameras = NGUITools.FindActive(); for (int i = 0, imax = cameras.Length; i < imax; ++i) #else Camera[] cameras = new Camera[Camera.allCamerasCount]; int camerasFound = Camera.GetAllCameras(cameras); for (int i = 0; i < camerasFound; ++i) #endif { cam = cameras[i]; if (cam && cam.enabled && (cam.cullingMask & layerMask) != 0) return cam; } return null; } /// /// Add a collider to the game object containing one or more widgets. /// static public void AddWidgetCollider (GameObject go) { AddWidgetCollider(go, false); } /// /// Add a collider to the game object containing one or more widgets. /// static public void AddWidgetCollider (GameObject go, bool considerInactive) { if (go != null) { // 3D collider Collider col = go.GetComponent(); BoxCollider box = col as BoxCollider; if (box != null) { UpdateWidgetCollider(box, considerInactive); return; } // Is there already another collider present? If so, do nothing. if (col != null) return; // 2D collider BoxCollider2D box2 = go.GetComponent(); if (box2 != null) { UpdateWidgetCollider(box2, considerInactive); return; } UICamera ui = UICamera.FindCameraForLayer(go.layer); if (ui != null && (ui.eventType == UICamera.EventType.World_2D || ui.eventType == UICamera.EventType.UI_2D)) { box2 = go.AddComponent(); box2.isTrigger = true; #if UNITY_EDITOR UnityEditor.Undo.RegisterCreatedObjectUndo(box2, "Add Collider"); #endif UIWidget widget = go.GetComponent(); if (widget != null) widget.autoResizeBoxCollider = true; UpdateWidgetCollider(box2, considerInactive); return; } else { box = go.AddComponent(); #if UNITY_EDITOR UnityEditor.Undo.RegisterCreatedObjectUndo(box, "Add Collider"); #endif box.isTrigger = true; UIWidget widget = go.GetComponent(); if (widget != null) widget.autoResizeBoxCollider = true; UpdateWidgetCollider(box, considerInactive); } } return; } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (GameObject go) { UpdateWidgetCollider(go, false); } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (GameObject go, bool considerInactive) { if (go != null) { BoxCollider bc = go.GetComponent(); if (bc != null) { UpdateWidgetCollider(bc, considerInactive); return; } BoxCollider2D box2 = go.GetComponent(); if (box2 != null) UpdateWidgetCollider(box2, considerInactive); } } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (BoxCollider box, bool considerInactive) { if (box != null) { var go = box.gameObject; var w = go.GetComponent(); if (w != null) { var dr = w.drawRegion; if (dr.x != 0f || dr.y != 0f || dr.z != 1f || dr.w != 1f) { var region = w.drawingDimensions; box.center = new Vector3((region.x + region.z) * 0.5f, (region.y + region.w) * 0.5f); box.size = new Vector3(region.z - region.x, region.w - region.y); } else { var corners = w.localCorners; box.center = Vector3.Lerp(corners[0], corners[2], 0.5f); box.size = corners[2] - corners[0]; } } else { var b = NGUIMath.CalculateRelativeWidgetBounds(go.transform, considerInactive); box.center = b.center; box.size = new Vector3(b.size.x, b.size.y, 0f); } #if UNITY_EDITOR NGUITools.SetDirty(box); #endif } } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (UIWidget w) { if (w == null) return; var bc = w.GetComponent(); if (bc != null) UpdateWidgetCollider(w, bc); else UpdateWidgetCollider(w, w.GetComponent()); } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (UIWidget w, BoxCollider box) { if (box != null && w != null) { var dr = w.drawRegion; if (dr.x != 0f || dr.y != 0f || dr.z != 1f || dr.w != 1f) { var region = w.drawingDimensions; var c = new Vector3((region.x + region.z) * 0.5f, (region.y + region.w) * 0.5f); var s = new Vector3(region.z - region.x, region.w - region.y); if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } } else { var corners = w.localCorners; var c = Vector3.Lerp(corners[0], corners[2], 0.5f); var s = corners[2] - corners[0]; if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } } } } // /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (UIWidget w, BoxCollider2D box) { if (box != null && w != null) { var dr = w.drawRegion; if (dr.x != 0f || dr.y != 0f || dr.z != 1f || dr.w != 1f) { var region = w.drawingDimensions; var c = new Vector2((region.x + region.z) * 0.5f, (region.y + region.w) * 0.5f); var s = new Vector2(region.z - region.x, region.w - region.y); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } #else if (c != box.offset || s != box.size) { box.offset = c; box.size = s; NGUITools.SetDirty(box); } #endif } else { var corners = w.localCorners; var c = Vector2.Lerp(corners[0], corners[2], 0.5f); var s = (Vector2)(corners[2] - corners[0]); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } #else if (c != box.offset || s != box.size) { box.offset = c; box.size = s; NGUITools.SetDirty(box); } #endif } #if UNITY_EDITOR NGUITools.SetDirty(box); #endif } } /// /// Adjust the widget's collider based on the depth of the widgets, as well as the widget's dimensions. /// static public void UpdateWidgetCollider (BoxCollider2D box, bool considerInactive) { if (box != null) { GameObject go = box.gameObject; UIWidget w = go.GetComponent(); if (w != null) { var dr = w.drawRegion; if (dr.x != 0f || dr.y != 0f || dr.z != 1f || dr.w != 1f) { var region = w.drawingDimensions; var c = new Vector2((region.x + region.z) * 0.5f, (region.y + region.w) * 0.5f); var s = new Vector2(region.z - region.x, region.w - region.y); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } #else if (c != box.offset || s != box.size) { box.offset = c; box.size = s; NGUITools.SetDirty(box); } #endif } else { var corners = w.localCorners; var c = Vector2.Lerp(corners[0], corners[2], 0.5f); var s = (Vector2)(corners[2] - corners[0]); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (c != box.center || s != box.size) { box.center = c; box.size = s; NGUITools.SetDirty(box); } #else if (c != box.offset || s != box.size) { box.offset = c; box.size = s; NGUITools.SetDirty(box); } #endif } } else { Bounds b = NGUIMath.CalculateRelativeWidgetBounds(go.transform, considerInactive); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 box.center = b.center; #else box.offset = b.center; #endif box.size = new Vector2(b.size.x, b.size.y); } #if UNITY_EDITOR NGUITools.SetDirty(box); #endif } } /// /// Helper function that returns the string name of the type. /// static public string GetTypeName () { string s = typeof(T).ToString(); if (s.StartsWith("UI")) s = s.Substring(2); else if (s.StartsWith("UnityEngine.")) s = s.Substring(12); return s; } /// /// Helper function that returns the string name of the type. /// static public string GetTypeName (UnityEngine.Object obj) { if (obj == null) return "Null"; string s = obj.GetType().ToString(); if (s.StartsWith("UI")) s = s.Substring(2); else if (s.StartsWith("UnityEngine.")) s = s.Substring(12); return s; } /// /// Convenience method that works without warnings in both Unity 3 and 4. /// static public void RegisterUndo (UnityEngine.Object obj, string name) { #if UNITY_EDITOR UnityEditor.Undo.RecordObject(obj, name); NGUITools.SetDirty(obj); #endif } /// /// Convenience function that marks the specified object as dirty in the Unity Editor. /// static public void SetDirty (UnityEngine.Object obj, string undoName = "last change") { #if UNITY_EDITOR #if UNITY_2018_3_OR_NEWER if (obj) { UnityEditor.EditorUtility.SetDirty(obj); if (!UnityEditor.AssetDatabase.Contains(obj) && !Application.isPlaying) { if (obj is Component) { var component = (Component)obj; UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(component.gameObject.scene); } else if (!(obj is UnityEditor.EditorWindow || obj is ScriptableObject)) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); } } } #else if (obj) UnityEditor.EditorUtility.SetDirty(obj); #endif #endif } static public void CheckForPrefabStage (GameObject gameObject) { #if UNITY_EDITOR && UNITY_2018_3_OR_NEWER var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage (gameObject); if (prefabStage == null) return; var rootsInParents = gameObject.GetComponentsInParent (true); var panelsInParents = gameObject.GetComponentsInParent (true); bool missingRoot = rootsInParents.Length == 0; bool missingPanel = panelsInParents.Length == 0; if (!missingRoot && !missingPanel) return; // Since this function is called from Awake/OnEnable, utilities like PrefabStage.prefabContentsRoot // or Scene.GetRootGameObjects () aren't available at this point var instanceRoot = gameObject.transform; while (instanceRoot.parent != null) instanceRoot = instanceRoot.parent; GameObject container = UnityEditor.EditorUtility.CreateGameObjectWithHideFlags ("UIRoot (Environment)", HideFlags.DontSave); container.layer = instanceRoot.gameObject.layer; if (missingRoot) container.AddComponent (); if (missingPanel) container.AddComponent (); UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene (container, prefabStage.scene); instanceRoot.SetParent (container.transform, false); #endif } /// /// Add a new child game object. /// static public GameObject AddChild (GameObject parent) { return AddChild(parent, true, -1); } /// /// Add a new child game object. /// static public GameObject AddChild (this GameObject parent, int layer) { return AddChild(parent, true, layer); } /// /// Add a new child game object. /// static public GameObject AddChild (this GameObject parent, bool undo) { return AddChild(parent, undo, -1); } /// /// Add a new child game object. /// static public GameObject AddChild (this GameObject parent, bool undo, int layer) { var go = new GameObject(); #if UNITY_EDITOR if (undo && !Application.isPlaying) UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Create Object"); #endif if (parent != null) { Transform t = go.transform; t.parent = parent.transform; t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; if (layer == -1) go.layer = parent.layer; else if (layer > -1 && layer < 32) go.layer = layer; } return go; } #if UNITY_5_5_OR_NEWER /// /// Instantiate an object and add it to the specified parent. /// static public GameObject AddChild (this Transform parent, GameObject prefab) { var go = UnityEngine.Object.Instantiate(prefab, parent.transform); var t = go.transform; t.parent = parent; t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; go.SetActive(true); return go; } #endif /// /// Instantiate an object and add it to the specified parent. /// static public GameObject AddChild (this GameObject parent, GameObject prefab) { return parent.AddChild(prefab, -1); } /// /// Instantiate an object and add it to the specified parent. /// static public GameObject AddChild (this GameObject parent, GameObject prefab, int layer) { #if UNITY_5_5_OR_NEWER var go = UnityEngine.Object.Instantiate(prefab, parent.transform); #if UNITY_EDITOR if (!Application.isPlaying) UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Create Object"); #endif if (go != null) { var t = go.transform; go.name = prefab.name; if (parent != null) { if (layer == -1) go.layer = parent.layer; else if (layer > -1 && layer < 32) go.layer = layer; } t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; go.SetActive(true); } return go; #else var go = GameObject.Instantiate(prefab) as GameObject; #if UNITY_EDITOR if (!Application.isPlaying) UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Create Object"); #endif if (go != null) { Transform t = go.transform; go.name = prefab.name; if (parent != null) { t.parent = parent.transform; if (layer == -1) go.layer = parent.layer; else if (layer > -1 && layer < 32) go.layer = layer; } t.localPosition = Vector3.zero; t.localRotation = Quaternion.identity; t.localScale = Vector3.one; go.SetActive(true); } return go; #endif } /// /// Calculate the game object's depth based on the widgets within, and also taking panel depth into consideration. /// static public int CalculateRaycastDepth (GameObject go) { #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); #else Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); #endif var w = go.GetComponent(); if (w != null) { #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.EndSample(); #else Profiler.EndSample(); #endif return w.raycastDepth; } var widgets = go.GetComponentsInChildren(); #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.EndSample(); #else Profiler.EndSample(); #endif if (widgets.Length == 0) return 0; int depth = int.MaxValue; for (int i = 0, imax = widgets.Length; i < imax; ++i) { if (widgets[i].enabled) depth = Mathf.Min(depth, widgets[i].raycastDepth); } return depth; } /// /// Gathers all widgets and calculates the depth for the next widget. /// static public int CalculateNextDepth (GameObject go) { if (go) { int depth = -1; UIWidget[] widgets = go.GetComponentsInChildren(); for (int i = 0, imax = widgets.Length; i < imax; ++i) depth = Mathf.Max(depth, widgets[i].depth); return depth + 1; } return 0; } /// /// Gathers all widgets and calculates the depth for the next widget. /// static public int CalculateNextDepth (GameObject go, bool ignoreChildrenWithColliders) { if (go && ignoreChildrenWithColliders) { int depth = -1; UIWidget[] widgets = go.GetComponentsInChildren(); for (int i = 0, imax = widgets.Length; i < imax; ++i) { UIWidget w = widgets[i]; #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (w.cachedGameObject != go && (w.collider != null || w.GetComponent() != null)) continue; #else if (w.cachedGameObject != go && (w.GetComponent() != null || w.GetComponent() != null)) continue; #endif depth = Mathf.Max(depth, w.depth); } return depth + 1; } return CalculateNextDepth(go); } /// /// Adjust the widgets' depth by the specified value. /// Returns '0' if nothing was adjusted, '1' if panels were adjusted, and '2' if widgets were adjusted. /// static public int AdjustDepth (GameObject go, int adjustment) { if (go != null) { UIPanel panel = go.GetComponent(); if (panel != null) { UIPanel[] panels = go.GetComponentsInChildren(true); for (int i = 0; i < panels.Length; ++i) { UIPanel p = panels[i]; #if UNITY_EDITOR RegisterUndo(p, "Depth Change"); #endif p.depth = p.depth + adjustment; } return 1; } else { panel = FindInParents(go); if (panel == null) return 0; UIWidget[] widgets = go.GetComponentsInChildren(true); for (int i = 0, imax = widgets.Length; i < imax; ++i) { UIWidget w = widgets[i]; if (w.panel != panel) continue; #if UNITY_EDITOR RegisterUndo(w, "Depth Change"); #endif w.depth = w.depth + adjustment; } return 2; } } return 0; } /// /// Bring all of the widgets on the specified object forward. /// static public void BringForward (GameObject go) { int val = AdjustDepth(go, 1000); if (val == 1) NormalizePanelDepths(); else if (val == 2) NormalizeWidgetDepths(); } /// /// Push all of the widgets on the specified object back, making them appear behind everything else. /// static public void PushBack (GameObject go) { int val = AdjustDepth(go, -1000); if (val == 1) NormalizePanelDepths(); else if (val == 2) NormalizeWidgetDepths(); } /// /// Normalize the depths of all the widgets and panels in the scene, making them start from 0 and remain in order. /// static public void NormalizeDepths () { NormalizeWidgetDepths(); NormalizePanelDepths(); } /// /// Normalize the depths of all the widgets in the scene, making them start from 0 and remain in order. /// static public void NormalizeWidgetDepths () { NormalizeWidgetDepths(FindActive()); } /// /// Normalize the depths of all the widgets in the scene, making them start from 0 and remain in order. /// static public void NormalizeWidgetDepths (GameObject go) { NormalizeWidgetDepths(go.GetComponentsInChildren()); } /// /// Normalize the depths of all the widgets in the scene, making them start from 0 and remain in order. /// static public void NormalizeWidgetDepths (UIWidget[] list) { int size = list.Length; if (size > 0) { Array.Sort(list, UIWidget.FullCompareFunc); int start = 0; int current = list[0].depth; for (int i = 0; i < size; ++i) { UIWidget w = list[i]; if (w.depth == current) { w.depth = start; } else { current = w.depth; w.depth = ++start; } } } } /// /// Normalize the depths of all the panels in the scene, making them start from 0 and remain in order. /// static public void NormalizePanelDepths () { UIPanel[] list = FindActive(); int size = list.Length; if (size > 0) { Array.Sort(list, UIPanel.CompareFunc); int start = 0; int current = list[0].depth; for (int i = 0; i < size; ++i) { UIPanel p = list[i]; if (p.depth == current) { p.depth = start; } else { current = p.depth; p.depth = ++start; } } } } /// /// Create a new UI. /// static public UIPanel CreateUI (bool advanced3D) { return CreateUI(null, advanced3D, -1); } /// /// Create a new UI. /// static public UIPanel CreateUI (bool advanced3D, int layer) { return CreateUI(null, advanced3D, layer); } /// /// Create a new UI. /// static public UIPanel CreateUI (Transform trans, bool advanced3D, int layer) { // Find the existing UI Root UIRoot root = (trans != null) ? NGUITools.FindInParents(trans.gameObject) : null; if (root == null && UIRoot.list.Count > 0) { foreach (UIRoot r in UIRoot.list) { if (r.gameObject.layer == layer) { root = r; break; } } } // Try to find an existing panel if (root == null) { for (int i = 0, imax = UIPanel.list.Count; i < imax; ++i) { UIPanel p = UIPanel.list[i]; GameObject go = p.gameObject; if (go.hideFlags == HideFlags.None && go.layer == layer) { trans.parent = p.transform; trans.localScale = Vector3.one; return p; } } } // If we are working with a different UI type, we need to treat it as a brand-new one instead if (root != null) { UICamera cam = root.GetComponentInChildren(); #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (cam != null && cam.camera.isOrthoGraphic == advanced3D) #else if (cam != null && cam.GetComponent().orthographic == advanced3D) #endif { trans = null; root = null; } } // If no root found, create one if (root == null) { GameObject go = NGUITools.AddChild(null, false); root = go.AddComponent(); // Automatically find the layers if none were specified if (layer == -1) layer = LayerMask.NameToLayer("UI"); if (layer == -1) layer = LayerMask.NameToLayer("2D UI"); go.layer = layer; if (advanced3D) { go.name = "UI Root (3D)"; root.scalingStyle = UIRoot.Scaling.Constrained; } else { go.name = "UI Root"; root.scalingStyle = UIRoot.Scaling.Flexible; } root.UpdateScale(); } // Find the first panel UIPanel panel = root.GetComponentInChildren(); if (panel == null) { // Find other active cameras in the scene Camera[] cameras = NGUITools.FindActive(); float depth = -1f; bool colorCleared = false; int mask = (1 << root.gameObject.layer); for (int i = 0; i < cameras.Length; ++i) { Camera c = cameras[i]; // If the color is being cleared, we won't need to if (c.clearFlags == CameraClearFlags.Color || c.clearFlags == CameraClearFlags.Skybox) colorCleared = true; // Choose the maximum depth depth = Mathf.Max(depth, c.depth); // Make sure this camera can't see the UI c.cullingMask = (c.cullingMask & (~mask)); } // Create a camera that will draw the UI Camera cam = NGUITools.AddChild(root.gameObject, false); cam.gameObject.AddComponent(); cam.clearFlags = colorCleared ? CameraClearFlags.Depth : CameraClearFlags.Color; cam.backgroundColor = Color.grey; cam.cullingMask = mask; cam.depth = depth + 1f; if (advanced3D) { cam.nearClipPlane = 0.1f; cam.farClipPlane = 4f; cam.transform.localPosition = new Vector3(0f, 0f, -700f); } else { cam.orthographic = true; cam.orthographicSize = 1; cam.nearClipPlane = -10; cam.farClipPlane = 10; } // Make sure there is an audio listener present AudioListener[] listeners = NGUITools.FindActive(); if (listeners == null || listeners.Length == 0) cam.gameObject.AddComponent(); // Add a panel to the root panel = root.gameObject.AddComponent(); #if UNITY_EDITOR if (!Application.isPlaying) UnityEditor.Selection.activeGameObject = panel.gameObject; #endif } if (trans != null) { // Find the root object while (trans.parent != null) trans = trans.parent; if (NGUITools.IsChild(trans, panel.transform)) { // Odd hierarchy -- can't reparent panel = trans.gameObject.AddComponent(); } else { // Reparent this root object to be a child of the panel trans.parent = panel.transform; trans.localScale = Vector3.one; trans.localPosition = Vector3.zero; SetChildLayer(panel.cachedTransform, panel.cachedGameObject.layer); } } return panel; } /// /// Helper function that recursively sets all children with widgets' game objects layers to the specified value. /// static public void SetChildLayer (this Transform t, int layer) { for (int i = 0; i < t.childCount; ++i) { Transform child = t.GetChild(i); child.gameObject.layer = layer; SetChildLayer(child, layer); } } static Dictionary mTypeNames = new Dictionary(); /// /// Add a child object to the specified parent and attaches the specified script to it. /// static public T AddChild (this GameObject parent) where T : Component { GameObject go = AddChild(parent); string name; if (!mTypeNames.TryGetValue(typeof(T), out name) || name == null) { name = GetTypeName(); mTypeNames[typeof(T)] = name; } go.name = name; return go.AddComponent(); } /// /// Add a child object to the specified parent and attaches the specified script to it. /// static public T AddChild (this GameObject parent, bool undo) where T : Component { GameObject go = AddChild(parent, undo); string name; if (!mTypeNames.TryGetValue(typeof(T), out name) || name == null) { name = GetTypeName(); mTypeNames[typeof(T)] = name; } go.name = name; return go.AddComponent(); } /// /// Add a new widget of specified type. /// static public T AddWidget (this GameObject go, int depth = int.MaxValue) where T : UIWidget { if (depth == int.MaxValue) depth = CalculateNextDepth(go); // Create the widget and place it above other widgets T widget = AddChild(go); widget.width = 100; widget.height = 100; widget.depth = depth; return widget; } /// /// Add a sprite appropriate for the specified atlas sprite. /// It will be sliced if the sprite has an inner rect, and a regular sprite otherwise. /// static public UISprite AddSprite (this GameObject go, INGUIAtlas atlas, string spriteName, int depth = int.MaxValue) { UISpriteData sp = (atlas != null) ? atlas.GetSprite(spriteName) : null; UISprite sprite = AddWidget(go, depth); sprite.type = (sp == null || !sp.hasBorder) ? UISprite.Type.Simple : UISprite.Type.Sliced; sprite.atlas = atlas; sprite.spriteName = spriteName; return sprite; } /// /// Get the rootmost object of the specified game object. /// static public GameObject GetRoot (GameObject go) { Transform t = go.transform; for (; ; ) { Transform parent = t.parent; if (parent == null) break; t = parent; } return t.gameObject; } /// /// Finds the specified component on the game object or one of its parents. /// This function has become obsolete with Unity 4.3. /// static public T FindInParents (GameObject go) where T : Component { if (go == null) return null; #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); var comp = go.GetComponentInParent(); UnityEngine.Profiling.Profiler.EndSample(); #else Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); var comp = go.GetComponentInParent(); Profiler.EndSample(); #endif #if UNITY_FLASH return (T)comp; #else return comp; #endif } /// /// Finds the specified component on the game object or one of its parents. /// This function has become obsolete with Unity 4.3. /// static public T FindInParents (Transform trans) where T : Component { if (trans == null) return null; #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); var comp = trans.GetComponentInParent(); UnityEngine.Profiling.Profiler.EndSample(); #else Profiler.BeginSample("Editor-only GC allocation (GetComponent)"); var comp = trans.GetComponentInParent(); Profiler.EndSample(); #endif #if UNITY_FLASH return (T)comp; #else return comp; #endif } /// /// Destroy the specified object, immediately if in edit mode. /// static public void Destroy (UnityEngine.Object obj) { if (obj) { if (obj is Transform) { var t = (obj as Transform); var go = t.gameObject; if (Application.isPlaying) { go.SetActive(false); t.parent = null; UnityEngine.Object.Destroy(go); } else UnityEngine.Object.DestroyImmediate(go); } else if (obj is GameObject) { var go = obj as GameObject; var t = go.transform; if (Application.isPlaying) { go.SetActive(false); t.parent = null; UnityEngine.Object.Destroy(go); } else UnityEngine.Object.DestroyImmediate(go); } else if (Application.isPlaying) UnityEngine.Object.Destroy(obj); else UnityEngine.Object.DestroyImmediate(obj); } } /// /// Convenience extension that destroys all children of the transform. /// static public void DestroyChildren (this Transform t) { bool isPlaying = Application.isPlaying; while (t.childCount != 0) { Transform child = t.GetChild(0); if (isPlaying) { child.parent = null; UnityEngine.Object.Destroy(child.gameObject); } else UnityEngine.Object.DestroyImmediate(child.gameObject); } } /// /// Destroy the specified object immediately, unless not in the editor, in which case the regular Destroy is used instead. /// static public void DestroyImmediate (UnityEngine.Object obj) { if (obj != null) { if (Application.isEditor) UnityEngine.Object.DestroyImmediate(obj); else UnityEngine.Object.Destroy(obj); } } /// /// Call the specified function on all objects in the scene. /// static public void Broadcast (string funcName) { GameObject[] gos = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[]; for (int i = 0, imax = gos.Length; i < imax; ++i) gos[i].SendMessage(funcName, SendMessageOptions.DontRequireReceiver); } /// /// Call the specified function on all objects in the scene. /// static public void Broadcast (string funcName, object param) { GameObject[] gos = GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[]; for (int i = 0, imax = gos.Length; i < imax; ++i) gos[i].SendMessage(funcName, param, SendMessageOptions.DontRequireReceiver); } /// /// Determines whether the 'parent' contains a 'child' in its hierarchy. /// static public bool IsChild (Transform parent, Transform child) { return child.IsChildOf(parent); // Legacy way of doing it prior to Unity adding IsChildOf //if (parent == null || child == null) return false; //while (child != null) //{ // if (child == parent) return true; // child = child.parent; //} //return false; } /// /// Activate the specified object and all of its children. /// static void Activate (Transform t) { Activate(t, false); } /// /// Activate the specified object and all of its children. /// static void Activate (Transform t, bool compatibilityMode) { SetActiveSelf(t.gameObject, true); if (compatibilityMode) { // If there is even a single enabled child, then we're using a Unity 4.0-based nested active state scheme. for (int i = 0, imax = t.childCount; i < imax; ++i) { var child = t.GetChild(i); if (child.gameObject.activeSelf) return; } // If this point is reached, then all the children are disabled, so we must be using a Unity 3.5-based active state scheme. for (int i = 0, imax = t.childCount; i < imax; ++i) { var child = t.GetChild(i); Activate(child, true); } } } /// /// Deactivate the specified object and all of its children. /// static void Deactivate (Transform t) { SetActiveSelf(t.gameObject, false); } /// /// SetActiveRecursively enables children before parents. This is a problem when a widget gets re-enabled /// and it tries to find a panel on its parent. /// static public void SetActive (GameObject go, bool state) { SetActive(go, state, true); } /// /// SetActiveRecursively enables children before parents. This is a problem when a widget gets re-enabled /// and it tries to find a panel on its parent. /// static public void SetActive (GameObject go, bool state, bool compatibilityMode) { if (go) { if (state) { Activate(go.transform, compatibilityMode); #if UNITY_EDITOR if (Application.isPlaying) #endif CallCreatePanel(go.transform); } else Deactivate(go.transform); } } /// /// Ensure that all widgets have had their panels created, forcing the update right away rather than on the following frame. /// [System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerStepThrough] static void CallCreatePanel (Transform t) { var w = t.GetComponent(); if (w != null) w.CreatePanel(); for (int i = 0, imax = t.childCount; i < imax; ++i) CallCreatePanel(t.GetChild(i)); } /// /// Activate or deactivate children of the specified game object without changing the active state of the object itself. /// static public void SetActiveChildren (GameObject go, bool state) { Transform t = go.transform; if (state) { for (int i = 0, imax = t.childCount; i < imax; ++i) { Transform child = t.GetChild(i); Activate(child); } } else { for (int i = 0, imax = t.childCount; i < imax; ++i) { Transform child = t.GetChild(i); Deactivate(child); } } } /// /// Helper function that returns whether the specified MonoBehaviour is active. /// [System.Obsolete("Use NGUITools.GetActive instead")] static public bool IsActive (Behaviour mb) { return mb != null && mb.enabled && mb.gameObject.activeInHierarchy; } /// /// Helper function that returns whether the specified MonoBehaviour is active. /// [System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerStepThrough] static public bool GetActive (Behaviour mb) { return mb && mb.enabled && mb.gameObject.activeInHierarchy; } /// /// Unity4 has changed GameObject.active to GameObject.activeself. /// [System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerStepThrough] static public bool GetActive (GameObject go) { return go && go.activeInHierarchy; } /// /// Unity4 has changed GameObject.active to GameObject.SetActive. /// [System.Diagnostics.DebuggerHidden] [System.Diagnostics.DebuggerStepThrough] static public void SetActiveSelf (GameObject go, bool state) { go.SetActive(state); } /// /// Recursively set the game object's layer. /// static public void SetLayer (GameObject go, int layer) { go.layer = layer; Transform t = go.transform; for (int i = 0, imax = t.childCount; i < imax; ++i) { Transform child = t.GetChild(i); SetLayer(child.gameObject, layer); } } /// /// Helper function used to make the vector use integer numbers. /// static public Vector3 Round (Vector3 v) { v.x = Mathf.Round(v.x); v.y = Mathf.Round(v.y); v.z = Mathf.Round(v.z); return v; } /// /// Make the specified selection pixel-perfect. /// static public void MakePixelPerfect (Transform t) { UIWidget w = t.GetComponent(); if (w != null) w.MakePixelPerfect(); if (t.GetComponent() == null && t.GetComponent() == null) { #if UNITY_EDITOR RegisterUndo(t, "Make Pixel-Perfect"); #endif t.localPosition = Round(t.localPosition); t.localScale = Round(t.localScale); } // Recurse into children for (int i = 0, imax = t.childCount; i < imax; ++i) MakePixelPerfect(t.GetChild(i)); } /// /// Given the root widget, adjust its position so that it fits on the screen. /// static public void FitOnScreen (this Camera cam, Transform t, bool considerInactive = false, bool considerChildren = true) { var bounds = NGUIMath.CalculateRelativeWidgetBounds(t, t, considerInactive, considerChildren); var sp = cam.WorldToScreenPoint(t.position); var min = sp + bounds.min; var max = sp + bounds.max; var sw = Screen.width; var sh = Screen.height; var offset = Vector2.zero; if (min.x < 0f) offset.x = -min.x; else if (max.x > sw) offset.x = sw - max.x; if (min.y < 0f) offset.y = -min.y; else if (max.y > sh) offset.y = sh - max.y; if (offset.sqrMagnitude > 0f) t.localPosition += new Vector3(offset.x, offset.y, 0f); } /// /// Fit the specified NGUI hierarchy on the screen. /// Example: uiCamera.FitOnScreen(contentObjectTransform, UICamera.lastEventPosition); /// static public void FitOnScreen (this Camera cam, Transform transform, Vector3 pos) { cam.FitOnScreen(transform, transform, pos); } /// /// Fit the specified NGUI hierarchy on the screen. /// Example: uiCamera.FitOnScreen(rootObjectTransform, contentObjectTransform, UICamera.lastEventPosition); /// static public void FitOnScreen (this Camera cam, Transform transform, Transform content, Vector3 pos, bool considerInactive = false) { Bounds b; cam.FitOnScreen(transform, content, pos, out b, considerInactive); } /// /// Fit the specified NGUI hierarchy on the screen. /// Example: uiCamera.FitOnScreen(rootObjectTransform, contentObjectTransform, UICamera.lastEventPosition); /// static public void FitOnScreen (this Camera cam, Transform transform, Transform content, Vector3 pos, out Bounds bounds, bool considerInactive = false) { bounds = NGUIMath.CalculateRelativeWidgetBounds(transform, content, considerInactive); Vector3 min = bounds.min; Vector3 max = bounds.max; Vector3 size = bounds.size; size.x += min.x; size.y -= max.y; if (cam != null) { // Since the screen can be of different than expected size, we want to convert // mouse coordinates to view space, then convert that to world position. pos.x = Mathf.Clamp01(pos.x / Screen.width); pos.y = Mathf.Clamp01(pos.y / Screen.height); // Calculate the ratio of the camera's target orthographic size to current screen size float activeSize = cam.orthographicSize / transform.parent.lossyScale.y; float ratio = (Screen.height * 0.5f) / activeSize; // Calculate the maximum on-screen size of the tooltip window max = new Vector2(ratio * size.x / Screen.width, ratio * size.y / Screen.height); // Limit the tooltip to always be visible pos.x = Mathf.Min(pos.x, 1f - max.x); pos.y = Mathf.Max(pos.y, max.y); // Update the absolute position and save the local one transform.position = cam.ViewportToWorldPoint(pos); pos = transform.localPosition; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); } else { // Don't let the tooltip leave the screen area if (pos.x + size.x > Screen.width) pos.x = Screen.width - size.x; if (pos.y - size.y < 0f) pos.y = size.y; // Simple calculation that assumes that the camera is of fixed size pos.x -= Screen.width * 0.5f; pos.y -= Screen.height * 0.5f; } transform.localPosition = pos; } /// /// Save the specified binary data into the specified file. /// static public bool Save (string fileName, byte[] bytes) { #if UNITY_WEBPLAYER || UNITY_FLASH || UNITY_METRO || UNITY_WP8 || UNITY_WP_8_1 return false; #else if (!NGUITools.fileAccess) return false; string path = Application.persistentDataPath + "/" + fileName; if (bytes == null) { if (File.Exists(path)) File.Delete(path); return true; } FileStream file = null; try { file = File.Create(path); } catch (System.Exception ex) { Debug.LogError(ex.Message); return false; } file.Write(bytes, 0, bytes.Length); file.Close(); return true; #endif } /// /// Load all binary data from the specified file. /// static public byte[] Load (string fileName) { #if UNITY_WEBPLAYER || UNITY_FLASH || UNITY_METRO || UNITY_WP8 || UNITY_WP_8_1 return null; #else if (!NGUITools.fileAccess) return null; string path = Application.persistentDataPath + "/" + fileName; if (File.Exists(path)) { return File.ReadAllBytes(path); } return null; #endif } /// /// Pre-multiply shaders result in a black outline if this operation is done in the shader. It's better to do it outside. /// static public Color ApplyPMA (Color c) { if (c.a != 1f) { c.r *= c.a; c.g *= c.a; c.b *= c.a; } return c; } /// /// Inform all widgets underneath the specified object that the parent has changed. /// static public void MarkParentAsChanged (GameObject go) { UIRect[] rects = go.GetComponentsInChildren(); for (int i = 0, imax = rects.Length; i < imax; ++i) rects[i].ParentHasChanged(); } /// /// Access to the clipboard via undocumented APIs. /// static public string clipboard { get { TextEditor te = new TextEditor(); te.Paste(); #if UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 return te.content.text; #else return te.text; #endif } set { TextEditor te = new TextEditor(); #if UNITY_4_6 || UNITY_4_7 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 te.content = new GUIContent(value); #else te.text = value; #endif te.OnFocus(); te.Copy(); } } [System.Obsolete("Use NGUIText.EncodeColor instead")] static public string EncodeColor (Color c) { return NGUIText.EncodeColor24(c); } [System.Obsolete("Use NGUIText.ParseColor instead")] static public Color ParseColor (string text, int offset) { return NGUIText.ParseColor24(text, offset); } [System.Obsolete("Use NGUIText.StripSymbols instead")] static public string StripSymbols (string text) { return NGUIText.StripSymbols(text); } /// /// Extension for the game object that checks to see if the component already exists before adding a new one. /// If the component is already present it will be returned instead. /// static public T AddMissingComponent (this GameObject go) where T : Component { #if UNITY_FLASH object comp = go.GetComponent(); #else T comp = go.GetComponent(); #endif if (comp == null) { #if UNITY_EDITOR if (!Application.isPlaying) RegisterUndo(go, "Add " + typeof(T)); #endif comp = go.AddComponent(); } #if UNITY_FLASH return (T)comp; #else return comp; #endif } // Temporary variable to avoid GC allocation static Vector3[] mSides = new Vector3[4]; /// /// Get sides relative to the specified camera. The order is left, top, right, bottom. /// static public Vector3[] GetSides (this Camera cam) { return cam.GetSides(Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f), null); } /// /// Get sides relative to the specified camera. The order is left, top, right, bottom. /// static public Vector3[] GetSides (this Camera cam, float depth) { return cam.GetSides(depth, null); } /// /// Get sides relative to the specified camera. The order is left, top, right, bottom. /// static public Vector3[] GetSides (this Camera cam, Transform relativeTo) { return cam.GetSides(Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f), relativeTo); } /// /// Get sides relative to the specified camera. The order is left, top, right, bottom. /// static public Vector3[] GetSides (this Camera cam, float depth, Transform relativeTo) { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (cam.isOrthoGraphic) #else if (cam.orthographic) #endif { float os = cam.orthographicSize; float x0 = -os; float x1 = os; float y0 = -os; float y1 = os; Rect rect = cam.rect; Vector2 size = screenSize; float aspect = size.x / size.y; aspect *= rect.width / rect.height; x0 *= aspect; x1 *= aspect; // We want to ignore the scale, as scale doesn't affect the camera's view region in Unity Transform t = cam.transform; Quaternion rot = t.rotation; Vector3 pos = t.position; int w = Mathf.RoundToInt(size.x); int h = Mathf.RoundToInt(size.y); if ((w & 1) == 1) pos.x -= 1f / size.x; if ((h & 1) == 1) pos.y += 1f / size.y; mSides[0] = rot * (new Vector3(x0, 0f, depth)) + pos; mSides[1] = rot * (new Vector3(0f, y1, depth)) + pos; mSides[2] = rot * (new Vector3(x1, 0f, depth)) + pos; mSides[3] = rot * (new Vector3(0f, y0, depth)) + pos; } else { mSides[0] = cam.ViewportToWorldPoint(new Vector3(0f, 0.5f, depth)); mSides[1] = cam.ViewportToWorldPoint(new Vector3(0.5f, 1f, depth)); mSides[2] = cam.ViewportToWorldPoint(new Vector3(1f, 0.5f, depth)); mSides[3] = cam.ViewportToWorldPoint(new Vector3(0.5f, 0f, depth)); } if (relativeTo != null) { for (int i = 0; i < 4; ++i) mSides[i] = relativeTo.InverseTransformPoint(mSides[i]); } return mSides; } /// /// Get the camera's world-space corners. The order is bottom-left, top-left, top-right, bottom-right. /// static public Vector3[] GetWorldCorners (this Camera cam) { float depth = Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f); return cam.GetWorldCorners(depth, null); } /// /// Get the camera's world-space corners. The order is bottom-left, top-left, top-right, bottom-right. /// static public Vector3[] GetWorldCorners (this Camera cam, float depth) { return cam.GetWorldCorners(depth, null); } /// /// Get the camera's world-space corners. The order is bottom-left, top-left, top-right, bottom-right. /// static public Vector3[] GetWorldCorners (this Camera cam, Transform relativeTo) { return cam.GetWorldCorners(Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f), relativeTo); } /// /// Get the camera's world-space corners. The order is bottom-left, top-left, top-right, bottom-right. /// static public Vector3[] GetWorldCorners (this Camera cam, float depth, Transform relativeTo) { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 if (cam.isOrthoGraphic) #else if (cam.orthographic) #endif { float os = cam.orthographicSize; float x0 = -os; float x1 = os; float y0 = -os; float y1 = os; Rect rect = cam.rect; Vector2 size = screenSize; float aspect = size.x / size.y; aspect *= rect.width / rect.height; x0 *= aspect; x1 *= aspect; // We want to ignore the scale, as scale doesn't affect the camera's view region in Unity Transform t = cam.transform; Quaternion rot = t.rotation; Vector3 pos = t.position; mSides[0] = rot * (new Vector3(x0, y0, depth)) + pos; mSides[1] = rot * (new Vector3(x0, y1, depth)) + pos; mSides[2] = rot * (new Vector3(x1, y1, depth)) + pos; mSides[3] = rot * (new Vector3(x1, y0, depth)) + pos; } else { mSides[0] = cam.ViewportToWorldPoint(new Vector3(0f, 0f, depth)); mSides[1] = cam.ViewportToWorldPoint(new Vector3(0f, 1f, depth)); mSides[2] = cam.ViewportToWorldPoint(new Vector3(1f, 1f, depth)); mSides[3] = cam.ViewportToWorldPoint(new Vector3(1f, 0f, depth)); } if (relativeTo != null) { for (int i = 0; i < 4; ++i) mSides[i] = relativeTo.InverseTransformPoint(mSides[i]); } return mSides; } /// /// Convenience function that converts Class + Function combo into Class.Function representation. /// static public string GetFuncName (object obj, string method) { if (obj == null) return ""; string type = obj.GetType().ToString(); int period = type.LastIndexOf('/'); if (period > 0) type = type.Substring(period + 1); return string.IsNullOrEmpty(method) ? type : type + "/" + method; } #if UNITY_EDITOR || !UNITY_FLASH /// /// Execute the specified function on the target game object. /// static public void Execute (GameObject go, string funcName) where T : Component { T[] comps = go.GetComponents(); foreach (T comp in comps) { #if !UNITY_EDITOR && (UNITY_WEBPLAYER || UNITY_FLASH || UNITY_METRO || UNITY_WP8 || UNITY_WP_8_1) comp.SendMessage(funcName, SendMessageOptions.DontRequireReceiver); #else MethodInfo method = comp.GetType().GetMethod(funcName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) method.Invoke(comp, null); #endif } } /// /// Execute the specified function on the target game object and all of its children. /// static public void ExecuteAll (GameObject root, string funcName) where T : Component { Execute(root, funcName); Transform t = root.transform; for (int i = 0, imax = t.childCount; i < imax; ++i) ExecuteAll(t.GetChild(i).gameObject, funcName); } /// /// Immediately start, update, and create all the draw calls from newly instantiated UI. /// This is useful if you plan on doing something like immediately taking a screenshot then destroying the UI. /// static public void ImmediatelyCreateDrawCalls (GameObject root) { ExecuteAll(root, "Start"); ExecuteAll(root, "Start"); ExecuteAll(root, "Update"); ExecuteAll(root, "Update"); ExecuteAll(root, "LateUpdate"); } #endif #if UNITY_EDITOR static int mSizeFrame = -1; static Func s_GetSizeOfMainGameView; [System.NonSerialized] static Vector2 mGameSize = Vector2.one; [System.NonSerialized] static bool mCheckedMainViewFunc = false; /// /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden. /// static public Vector2 screenSize { get { int frame = Time.frameCount; if (mSizeFrame != frame || !Application.isPlaying) { #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.BeginSample("Editor-only GC allocation (NGUITools.screenSize)"); #else Profiler.BeginSample("Editor-only GC allocation (NGUITools.screenSize)"); #endif mSizeFrame = frame; if (s_GetSizeOfMainGameView == null && !mCheckedMainViewFunc) { mCheckedMainViewFunc = true; System.Type type = System.Type.GetType("UnityEditor.GameView,UnityEditor"); // Post-Unity 5.4 var methodInfo = type.GetMethod("GetMainGameViewTargetSize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); // Pre-Unity 5.4 if (methodInfo == null) methodInfo = type.GetMethod("GetSizeOfMainGameView", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); // Create the delegate if (methodInfo != null) { s_GetSizeOfMainGameView = (Func)Delegate.CreateDelegate(typeof(Func), methodInfo); } else Debug.LogWarning("Unable to get the main game view size function"); } if (s_GetSizeOfMainGameView != null) { //#if UNITY_EDITOR_OSX // There seems to be a Unity 5.4 bug that returns invalid screen size when the mouse is clicked (wtf?) on OSX //if (mGameSize.x == 1f && mGameSize.y == 1f) mGameSize = s_GetSizeOfMainGameView(); //#else mGameSize = s_GetSizeOfMainGameView(); //#endif } else mGameSize = new Vector2(Screen.width, Screen.height); #if UNITY_5_5_OR_NEWER UnityEngine.Profiling.Profiler.EndSample(); #else Profiler.EndSample(); #endif #if UNITY_EDITOR && W2 if (mGameSize.magnitude > 4000f) Debug.LogWarning(mGameSize); #endif } return mGameSize; } } #else /// /// Size of the game view cannot be retrieved from Screen.width and Screen.height when the game view is hidden. /// static public Vector2 screenSize { get { return new Vector2(Screen.width, Screen.height); } } #endif /// /// List of keys that can be checked. /// static public KeyCode[] keys = new KeyCode[] { KeyCode.Backspace, // 8, KeyCode.Tab, // 9, KeyCode.Clear, // 12, KeyCode.Return, // 13, KeyCode.Pause, // 19, KeyCode.Escape, // 27, KeyCode.Space, // 32, KeyCode.Exclaim, // 33, KeyCode.DoubleQuote, // 34, KeyCode.Hash, // 35, KeyCode.Dollar, // 36, KeyCode.Ampersand, // 38, KeyCode.Quote, // 39, KeyCode.LeftParen, // 40, KeyCode.RightParen, // 41, KeyCode.Asterisk, // 42, KeyCode.Plus, // 43, KeyCode.Comma, // 44, KeyCode.Minus, // 45, KeyCode.Period, // 46, KeyCode.Slash, // 47, KeyCode.Alpha0, // 48, KeyCode.Alpha1, // 49, KeyCode.Alpha2, // 50, KeyCode.Alpha3, // 51, KeyCode.Alpha4, // 52, KeyCode.Alpha5, // 53, KeyCode.Alpha6, // 54, KeyCode.Alpha7, // 55, KeyCode.Alpha8, // 56, KeyCode.Alpha9, // 57, KeyCode.Colon, // 58, KeyCode.Semicolon, // 59, KeyCode.Less, // 60, KeyCode.Equals, // 61, KeyCode.Greater, // 62, KeyCode.Question, // 63, KeyCode.At, // 64, KeyCode.LeftBracket, // 91, KeyCode.Backslash, // 92, KeyCode.RightBracket, // 93, KeyCode.Caret, // 94, KeyCode.Underscore, // 95, KeyCode.BackQuote, // 96, KeyCode.A, // 97, KeyCode.B, // 98, KeyCode.C, // 99, KeyCode.D, // 100, KeyCode.E, // 101, KeyCode.F, // 102, KeyCode.G, // 103, KeyCode.H, // 104, KeyCode.I, // 105, KeyCode.J, // 106, KeyCode.K, // 107, KeyCode.L, // 108, KeyCode.M, // 109, KeyCode.N, // 110, KeyCode.O, // 111, KeyCode.P, // 112, KeyCode.Q, // 113, KeyCode.R, // 114, KeyCode.S, // 115, KeyCode.T, // 116, KeyCode.U, // 117, KeyCode.V, // 118, KeyCode.W, // 119, KeyCode.X, // 120, KeyCode.Y, // 121, KeyCode.Z, // 122, KeyCode.Delete, // 127, KeyCode.Keypad0, // 256, KeyCode.Keypad1, // 257, KeyCode.Keypad2, // 258, KeyCode.Keypad3, // 259, KeyCode.Keypad4, // 260, KeyCode.Keypad5, // 261, KeyCode.Keypad6, // 262, KeyCode.Keypad7, // 263, KeyCode.Keypad8, // 264, KeyCode.Keypad9, // 265, KeyCode.KeypadPeriod, // 266, KeyCode.KeypadDivide, // 267, KeyCode.KeypadMultiply, // 268, KeyCode.KeypadMinus, // 269, KeyCode.KeypadPlus, // 270, KeyCode.KeypadEnter, // 271, KeyCode.KeypadEquals, // 272, KeyCode.UpArrow, // 273, KeyCode.DownArrow, // 274, KeyCode.RightArrow, // 275, KeyCode.LeftArrow, // 276, KeyCode.Insert, // 277, KeyCode.Home, // 278, KeyCode.End, // 279, KeyCode.PageUp, // 280, KeyCode.PageDown, // 281, KeyCode.F1, // 282, KeyCode.F2, // 283, KeyCode.F3, // 284, KeyCode.F4, // 285, KeyCode.F5, // 286, KeyCode.F6, // 287, KeyCode.F7, // 288, KeyCode.F8, // 289, KeyCode.F9, // 290, KeyCode.F10, // 291, KeyCode.F11, // 292, KeyCode.F12, // 293, KeyCode.F13, // 294, KeyCode.F14, // 295, KeyCode.F15, // 296, KeyCode.Numlock, // 300, KeyCode.CapsLock, // 301, KeyCode.ScrollLock, // 302, KeyCode.RightShift, // 303, KeyCode.LeftShift, // 304, KeyCode.RightControl, // 305, KeyCode.LeftControl, // 306, KeyCode.RightAlt, // 307, KeyCode.LeftAlt, // 308, //KeyCode.Mouse0, // 323, //KeyCode.Mouse1, // 324, //KeyCode.Mouse2, // 325, KeyCode.Mouse3, // 326, KeyCode.Mouse4, // 327, KeyCode.Mouse5, // 328, KeyCode.Mouse6, // 329, KeyCode.JoystickButton0, // 330, KeyCode.JoystickButton1, // 331, KeyCode.JoystickButton2, // 332, KeyCode.JoystickButton3, // 333, KeyCode.JoystickButton4, // 334, KeyCode.JoystickButton5, // 335, KeyCode.JoystickButton6, // 336, KeyCode.JoystickButton7, // 337, KeyCode.JoystickButton8, // 338, KeyCode.JoystickButton9, // 339, KeyCode.JoystickButton10, // 340, KeyCode.JoystickButton11, // 341, KeyCode.JoystickButton12, // 342, KeyCode.JoystickButton13, // 343, KeyCode.JoystickButton14, // 344, KeyCode.JoystickButton15, // 345, KeyCode.JoystickButton16, // 346, KeyCode.JoystickButton17, // 347, KeyCode.JoystickButton18, // 348, KeyCode.JoystickButton19, // 349, }; /// /// Helper function that converts the specified key to a 3-character key identifier for captions. /// static public string KeyToCaption (KeyCode key) { switch (key) { case KeyCode.None: return null; case KeyCode.Backspace: return "Backspace"; case KeyCode.Tab: return "Tab"; case KeyCode.Clear: return "Clear"; case KeyCode.Return: return "Return"; case KeyCode.Pause: return "PS"; case KeyCode.Escape: return "Esc"; case KeyCode.Space: return "Space"; case KeyCode.Exclaim: return "!"; case KeyCode.DoubleQuote: return "''"; case KeyCode.Hash: return "#"; case KeyCode.Dollar: return "$"; case KeyCode.Ampersand: return "&"; case KeyCode.Quote: return "'"; case KeyCode.LeftParen: return "("; case KeyCode.RightParen: return ")"; case KeyCode.Asterisk: return "*"; case KeyCode.Plus: return "+"; case KeyCode.Comma: return ","; case KeyCode.Minus: return "-"; case KeyCode.Period: return "."; case KeyCode.Slash: return "/"; case KeyCode.Alpha0: return "0"; case KeyCode.Alpha1: return "1"; case KeyCode.Alpha2: return "2"; case KeyCode.Alpha3: return "3"; case KeyCode.Alpha4: return "4"; case KeyCode.Alpha5: return "5"; case KeyCode.Alpha6: return "6"; case KeyCode.Alpha7: return "7"; case KeyCode.Alpha8: return "8"; case KeyCode.Alpha9: return "9"; case KeyCode.Colon: return ":"; case KeyCode.Semicolon: return ";"; case KeyCode.Less: return "<"; case KeyCode.Equals: return "="; case KeyCode.Greater: return ">"; case KeyCode.Question: return "?"; case KeyCode.At: return "@"; case KeyCode.LeftBracket: return "["; case KeyCode.Backslash: return "\\"; case KeyCode.RightBracket: return "]"; case KeyCode.Caret: return "^"; case KeyCode.Underscore: return "_"; case KeyCode.BackQuote: return "`"; case KeyCode.A: return "A"; case KeyCode.B: return "B"; case KeyCode.C: return "C"; case KeyCode.D: return "D"; case KeyCode.E: return "E"; case KeyCode.F: return "F"; case KeyCode.G: return "G"; case KeyCode.H: return "H"; case KeyCode.I: return "I"; case KeyCode.J: return "J"; case KeyCode.K: return "K"; case KeyCode.L: return "L"; case KeyCode.M: return "M"; case KeyCode.N: return "N"; case KeyCode.O: return "O"; case KeyCode.P: return "P"; case KeyCode.Q: return "Q"; case KeyCode.R: return "R"; case KeyCode.S: return "S"; case KeyCode.T: return "T"; case KeyCode.U: return "U"; case KeyCode.V: return "V"; case KeyCode.W: return "W"; case KeyCode.X: return "X"; case KeyCode.Y: return "Y"; case KeyCode.Z: return "Z"; case KeyCode.Delete: return "Del"; case KeyCode.Keypad0: return "K0"; case KeyCode.Keypad1: return "K1"; case KeyCode.Keypad2: return "K2"; case KeyCode.Keypad3: return "K3"; case KeyCode.Keypad4: return "K4"; case KeyCode.Keypad5: return "K5"; case KeyCode.Keypad6: return "K6"; case KeyCode.Keypad7: return "K7"; case KeyCode.Keypad8: return "K8"; case KeyCode.Keypad9: return "K9"; case KeyCode.KeypadPeriod: return "K."; case KeyCode.KeypadDivide: return "K/"; case KeyCode.KeypadMultiply: return "K*"; case KeyCode.KeypadMinus: return "K-"; case KeyCode.KeypadPlus: return "K+"; case KeyCode.KeypadEnter: return "KE"; case KeyCode.KeypadEquals: return "KQ"; case KeyCode.UpArrow: return "UP"; case KeyCode.DownArrow: return "DN"; case KeyCode.RightArrow: return "LT"; case KeyCode.LeftArrow: return "RT"; case KeyCode.Insert: return "Ins"; case KeyCode.Home: return "Home"; case KeyCode.End: return "End"; case KeyCode.PageUp: return "PU"; case KeyCode.PageDown: return "PD"; case KeyCode.F1: return "F1"; case KeyCode.F2: return "F2"; case KeyCode.F3: return "F3"; case KeyCode.F4: return "F4"; case KeyCode.F5: return "F5"; case KeyCode.F6: return "F6"; case KeyCode.F7: return "F7"; case KeyCode.F8: return "F8"; case KeyCode.F9: return "F9"; case KeyCode.F10: return "F10"; case KeyCode.F11: return "F11"; case KeyCode.F12: return "F12"; case KeyCode.F13: return "F13"; case KeyCode.F14: return "F14"; case KeyCode.F15: return "F15"; case KeyCode.Numlock: return "Num"; case KeyCode.CapsLock: return "Cap"; case KeyCode.ScrollLock: return "Scr"; case KeyCode.RightShift: return "RS"; case KeyCode.LeftShift: return "LS"; case KeyCode.RightControl: return "RC"; case KeyCode.LeftControl: return "LC"; case KeyCode.RightAlt: return "RA"; case KeyCode.LeftAlt: return "LA"; case KeyCode.Mouse0: return "M0"; case KeyCode.Mouse1: return "M1"; case KeyCode.Mouse2: return "M2"; case KeyCode.Mouse3: return "M3"; case KeyCode.Mouse4: return "M4"; case KeyCode.Mouse5: return "M5"; case KeyCode.Mouse6: return "M6"; case KeyCode.JoystickButton0: return "(A)"; case KeyCode.JoystickButton1: return "(B)"; case KeyCode.JoystickButton2: return "(X)"; case KeyCode.JoystickButton3: return "(Y)"; case KeyCode.JoystickButton4: return "(RB)"; case KeyCode.JoystickButton5: return "(LB)"; case KeyCode.JoystickButton6: return "(Back)"; case KeyCode.JoystickButton7: return "(Start)"; case KeyCode.JoystickButton8: return "(LS)"; case KeyCode.JoystickButton9: return "(RS)"; case KeyCode.JoystickButton10: return "J10"; case KeyCode.JoystickButton11: return "J11"; case KeyCode.JoystickButton12: return "J12"; case KeyCode.JoystickButton13: return "J13"; case KeyCode.JoystickButton14: return "J14"; case KeyCode.JoystickButton15: return "J15"; case KeyCode.JoystickButton16: return "J16"; case KeyCode.JoystickButton17: return "J17"; case KeyCode.JoystickButton18: return "J18"; case KeyCode.JoystickButton19: return "J19"; } return null; } /// /// The opposite of KeyToCaption() function that converts the string representation to its KeyCode value. /// static public KeyCode CaptionToKey (string caption) { if (string.IsNullOrEmpty(caption)) return KeyCode.None; if (caption == "Backspace") return KeyCode.Backspace; if (caption == "Tab") return KeyCode.Tab; if (caption == "Clear") return KeyCode.Clear; if (caption == "Return") return KeyCode.Return; if (caption == "Pause") return KeyCode.Pause; if (caption == "Esc") return KeyCode.Escape; if (caption == "Space") return KeyCode.Space; if (caption == "!") return KeyCode.Exclaim; if (caption == "''") return KeyCode.DoubleQuote; if (caption == "#") return KeyCode.Hash; if (caption == "$") return KeyCode.Dollar; if (caption == "&") return KeyCode.Ampersand; if (caption == "'") return KeyCode.Quote; if (caption == "(") return KeyCode.LeftParen; if (caption == ")") return KeyCode.RightParen; if (caption == "*") return KeyCode.Asterisk; if (caption == "+") return KeyCode.Plus; if (caption == ",") return KeyCode.Comma; if (caption == "-") return KeyCode.Minus; if (caption == ".") return KeyCode.Period; if (caption == "/") return KeyCode.Slash; if (caption == "0") return KeyCode.Alpha0; if (caption == "1") return KeyCode.Alpha1; if (caption == "2") return KeyCode.Alpha2; if (caption == "3") return KeyCode.Alpha3; if (caption == "4") return KeyCode.Alpha4; if (caption == "5") return KeyCode.Alpha5; if (caption == "6") return KeyCode.Alpha6; if (caption == "7") return KeyCode.Alpha7; if (caption == "8") return KeyCode.Alpha8; if (caption == "9") return KeyCode.Alpha9; if (caption == ";//") return KeyCode.Colon; if (caption == ";") return KeyCode.Semicolon; if (caption == "<") return KeyCode.Less; if (caption == "=") return KeyCode.Equals; if (caption == ">") return KeyCode.Greater; if (caption == "?") return KeyCode.Question; if (caption == "@") return KeyCode.At; if (caption == "[") return KeyCode.LeftBracket; if (caption == "\\") return KeyCode.Backslash; if (caption == "]") return KeyCode.RightBracket; if (caption == "^") return KeyCode.Caret; if (caption == "_") return KeyCode.Underscore; if (caption == "`") return KeyCode.BackQuote; if (caption == "A") return KeyCode.A; if (caption == "B") return KeyCode.B; if (caption == "C") return KeyCode.C; if (caption == "D") return KeyCode.D; if (caption == "E") return KeyCode.E; if (caption == "F") return KeyCode.F; if (caption == "G") return KeyCode.G; if (caption == "H") return KeyCode.H; if (caption == "I") return KeyCode.I; if (caption == "J") return KeyCode.J; if (caption == "K") return KeyCode.K; if (caption == "L") return KeyCode.L; if (caption == "M") return KeyCode.M; if (caption == "N") return KeyCode.N; if (caption == "O") return KeyCode.O; if (caption == "P") return KeyCode.P; if (caption == "Q") return KeyCode.Q; if (caption == "R") return KeyCode.R; if (caption == "S") return KeyCode.S; if (caption == "T") return KeyCode.T; if (caption == "U") return KeyCode.U; if (caption == "V") return KeyCode.V; if (caption == "W") return KeyCode.W; if (caption == "X") return KeyCode.X; if (caption == "Y") return KeyCode.Y; if (caption == "Z") return KeyCode.Z; if (caption == "Del") return KeyCode.Delete; if (caption == "K0") return KeyCode.Keypad0; if (caption == "K1") return KeyCode.Keypad1; if (caption == "K2") return KeyCode.Keypad2; if (caption == "K3") return KeyCode.Keypad3; if (caption == "K4") return KeyCode.Keypad4; if (caption == "K5") return KeyCode.Keypad5; if (caption == "K6") return KeyCode.Keypad6; if (caption == "K7") return KeyCode.Keypad7; if (caption == "K8") return KeyCode.Keypad8; if (caption == "K9") return KeyCode.Keypad9; if (caption == "K.") return KeyCode.KeypadPeriod; if (caption == "K/") return KeyCode.KeypadDivide; if (caption == "K*") return KeyCode.KeypadMultiply; if (caption == "K-") return KeyCode.KeypadMinus; if (caption == "K+") return KeyCode.KeypadPlus; if (caption == "KE") return KeyCode.KeypadEnter; if (caption == "KQ") return KeyCode.KeypadEquals; if (caption == "UP") return KeyCode.UpArrow; if (caption == "DN") return KeyCode.DownArrow; if (caption == "LT") return KeyCode.RightArrow; if (caption == "RT") return KeyCode.LeftArrow; if (caption == "Ins") return KeyCode.Insert; if (caption == "Home") return KeyCode.Home; if (caption == "End") return KeyCode.End; if (caption == "PU") return KeyCode.PageUp; if (caption == "PD") return KeyCode.PageDown; if (caption == "F1") return KeyCode.F1; if (caption == "F2") return KeyCode.F2; if (caption == "F3") return KeyCode.F3; if (caption == "F4") return KeyCode.F4; if (caption == "F5") return KeyCode.F5; if (caption == "F6") return KeyCode.F6; if (caption == "F7") return KeyCode.F7; if (caption == "F8") return KeyCode.F8; if (caption == "F9") return KeyCode.F9; if (caption == "F10") return KeyCode.F10; if (caption == "F11") return KeyCode.F11; if (caption == "F12") return KeyCode.F12; if (caption == "F13") return KeyCode.F13; if (caption == "F14") return KeyCode.F14; if (caption == "F15") return KeyCode.F15; if (caption == "Num") return KeyCode.Numlock; if (caption == "Cap") return KeyCode.CapsLock; if (caption == "Scr") return KeyCode.ScrollLock; if (caption == "RS") return KeyCode.RightShift; if (caption == "LS") return KeyCode.LeftShift; if (caption == "RC") return KeyCode.RightControl; if (caption == "LC") return KeyCode.LeftControl; if (caption == "RA") return KeyCode.RightAlt; if (caption == "LA") return KeyCode.LeftAlt; if (caption == "M0") return KeyCode.Mouse0; if (caption == "M1") return KeyCode.Mouse1; if (caption == "M2") return KeyCode.Mouse2; if (caption == "M3") return KeyCode.Mouse3; if (caption == "M4") return KeyCode.Mouse4; if (caption == "M5") return KeyCode.Mouse5; if (caption == "M6") return KeyCode.Mouse6; if (caption == "(A)") return KeyCode.JoystickButton0; if (caption == "(B)") return KeyCode.JoystickButton1; if (caption == "(X)") return KeyCode.JoystickButton2; if (caption == "(Y)") return KeyCode.JoystickButton3; if (caption == "(RB)") return KeyCode.JoystickButton4; if (caption == "(LB)") return KeyCode.JoystickButton5; if (caption == "(Back)") return KeyCode.JoystickButton6; if (caption == "(Start)") return KeyCode.JoystickButton7; if (caption == "(LS)") return KeyCode.JoystickButton8; if (caption == "(RS)") return KeyCode.JoystickButton9; if (caption == "J10") return KeyCode.JoystickButton10; if (caption == "J11") return KeyCode.JoystickButton11; if (caption == "J12") return KeyCode.JoystickButton12; if (caption == "J13") return KeyCode.JoystickButton13; if (caption == "J14") return KeyCode.JoystickButton14; if (caption == "J15") return KeyCode.JoystickButton15; if (caption == "J16") return KeyCode.JoystickButton16; if (caption == "J17") return KeyCode.JoystickButton17; if (caption == "J18") return KeyCode.JoystickButton18; if (caption == "J19") return KeyCode.JoystickButton19; return KeyCode.None; } static Dictionary mWidgets = new Dictionary(); static UIPanel mRoot; static GameObject mGo; public delegate void OnInitFunc (T w) where T : UIWidget; /// /// Immediately add a new widget to the screen or return an existing one that matches the specified ID. /// The usage of this function is very similar to GUI.Draw in a sense that it can be used to quickly /// show persistent widgets via code. /// static public T Draw (string id, OnInitFunc onInit = null) where T : UIWidget { UIWidget w; if (mWidgets.TryGetValue(id, out w) && w) return (T)w; if (mRoot == null) { UICamera baseCam = null; UIRoot baseRoot = null; for (int i = 0; i < UIRoot.list.Count; ++i) { UIRoot root = UIRoot.list[i]; if (root) { UICamera cam = UICamera.FindCameraForLayer(root.gameObject.layer); if (cam && cam.cachedCamera.orthographic) { baseCam = cam; baseRoot = root; break; } } } if (baseCam == null) { mRoot = NGUITools.CreateUI(false, LayerMask.NameToLayer("UI")); } else { mRoot = baseRoot.gameObject.AddChild(); } mRoot.depth = 100000; mGo = mRoot.gameObject; mGo.name = "Immediate Mode GUI"; } w = mGo.AddWidget(); w.name = id; mWidgets[id] = w; if (onInit != null) onInit((T)w); return (T)w; } /// /// Transforms this color from gamma to linear space, but only if the active color space is actually set to linear. /// static public Color GammaToLinearSpace (this Color c) { if (mColorSpace == ColorSpace.Uninitialized) mColorSpace = QualitySettings.activeColorSpace; if (mColorSpace == ColorSpace.Linear) { return new Color( Mathf.GammaToLinearSpace(c.r), Mathf.GammaToLinearSpace(c.g), Mathf.GammaToLinearSpace(c.b), Mathf.GammaToLinearSpace(c.a)); } return c; } /// /// Transforms this color from linear to gamma space, but only if the active color space is actually set to linear. /// static public Color LinearToGammaSpace (this Color c) { if (mColorSpace == ColorSpace.Uninitialized) mColorSpace = QualitySettings.activeColorSpace; if (mColorSpace == ColorSpace.Linear) { return new Color( Mathf.LinearToGammaSpace(c.r), Mathf.LinearToGammaSpace(c.g), Mathf.LinearToGammaSpace(c.b), Mathf.LinearToGammaSpace(c.a)); } return c; } static ColorSpace mColorSpace = ColorSpace.Uninitialized; /// /// Helper function that determines whether the two atlases are related. /// static public bool CheckIfRelated (INGUIAtlas a, INGUIAtlas b) { if (a == null || b == null) return false; return a == b || a.References(b) || b.References(a); } /// /// Replace all atlas reference of one atlas with another. /// static public void Replace (INGUIAtlas before, INGUIAtlas after) { var list = FindActive(); for (int i = 0, imax = list.Length; i < imax; ++i) { var sp = list[i]; if (sp.atlas == before) { sp.atlas = after; #if UNITY_EDITOR SetDirty(sp); #endif } } var f0 = Resources.FindObjectsOfTypeAll(); for (int i = 0, imax = f0.Length; i < imax; ++i) { var font = f0[i]; if (font.atlas == before) { font.atlas = after; #if UNITY_EDITOR SetDirty(font); #endif } } var f1 = Resources.FindObjectsOfTypeAll(); for (int i = 0, imax = f1.Length; i < imax; ++i) { var font = f1[i]; if (font.atlas == before) { font.atlas = after; #if UNITY_EDITOR SetDirty(font); #endif } } var labels = FindActive(); for (int i = 0, imax = labels.Length; i < imax; ++i) { var lbl = labels[i]; if (lbl.bitmapFont != null && lbl.atlas == before) { lbl.atlas = after; #if UNITY_EDITOR SetDirty(lbl); #endif } } } /// /// Helper function that determines whether the two atlases are related. /// static public bool CheckIfRelated (INGUIFont a, INGUIFont b) { if (a == null || b == null) return false; if (a.isDynamic && b.isDynamic && a.dynamicFont.fontNames[0] == b.dynamicFont.fontNames[0]) return true; return a == b || a.References(b) || b.References(a); } }