Editor
NGUIEditorTools.cs
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2013 Tasharen Entertainment
//----------------------------------------------
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
///
/// Tools for the editor
///
public clast NGUIEditorTools
{
static Texture2D mWhiteTex;
static Texture2D mBackdropTex;
static Texture2D mContrastTex;
static Texture2D mGradientTex;
static GameObject mPrevious;
///
/// Returns a blank usable 1x1 white texture.
///
static public Texture2D blankTexture
{
get
{
return EditorGUIUtility.whiteTexture;
}
}
///
/// Returns a usable texture that looks like a dark checker board.
///
static public Texture2D backdropTexture
{
get
{
if (mBackdropTex == null) mBackdropTex = CreateCheckerTex(
new Color(0.1f, 0.1f, 0.1f, 0.5f),
new Color(0.2f, 0.2f, 0.2f, 0.5f));
return mBackdropTex;
}
}
///
/// Returns a usable texture that looks like a high-contrast checker board.
///
static public Texture2D contrastTexture
{
get
{
if (mContrastTex == null) mContrastTex = CreateCheckerTex(
new Color(0f, 0.0f, 0f, 0.5f),
new Color(1f, 1f, 1f, 0.5f));
return mContrastTex;
}
}
///
/// Gradient texture is used for satle bars / headers.
///
static public Texture2D gradientTexture
{
get
{
if (mGradientTex == null) mGradientTex = CreateGradientTex();
return mGradientTex;
}
}
///
/// Create a white dummy texture.
///
static Texture2D CreateDummyTex ()
{
Texture2D tex = new Texture2D(1, 1);
tex.name = "[Generated] Dummy Texture";
tex.hideFlags = HideFlags.DontSave;
tex.filterMode = FilterMode.Point;
tex.SetPixel(0, 0, Color.white);
tex.Apply();
return tex;
}
///
/// Create a checker-background texture
///
static Texture2D CreateCheckerTex (Color c0, Color c1)
{
Texture2D tex = new Texture2D(16, 16);
tex.name = "[Generated] Checker Texture";
tex.hideFlags = HideFlags.DontSave;
for (int y = 0; y < 8; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c1);
for (int y = 8; y < 16; ++y) for (int x = 0; x < 8; ++x) tex.SetPixel(x, y, c0);
for (int y = 0; y < 8; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c0);
for (int y = 8; y < 16; ++y) for (int x = 8; x < 16; ++x) tex.SetPixel(x, y, c1);
tex.Apply();
tex.filterMode = FilterMode.Point;
return tex;
}
///
/// Create a gradient texture
///
static Texture2D CreateGradientTex ()
{
Texture2D tex = new Texture2D(1, 16);
tex.name = "[Generated] Gradient Texture";
tex.hideFlags = HideFlags.DontSave;
Color c0 = new Color(1f, 1f, 1f, 0f);
Color c1 = new Color(1f, 1f, 1f, 0.4f);
for (int i = 0; i < 16; ++i)
{
float f = Mathf.Abs((i / 15f) * 2f - 1f);
f *= f;
tex.SetPixel(0, i, Color.Lerp(c0, c1, f));
}
tex.Apply();
tex.filterMode = FilterMode.Bilinear;
return tex;
}
///
/// Draws the tiled texture. Like GUI.DrawTexture() but tiled instead of stretched.
///
static public void DrawTiledTexture (Rect rect, Texture tex)
{
GUI.BeginGroup(rect);
{
int width = Mathf.RoundToInt(rect.width);
int height = Mathf.RoundToInt(rect.height);
for (int y = 0; y < height; y += tex.height)
{
for (int x = 0; x < width; x += tex.width)
{
GUI.DrawTexture(new Rect(x, y, tex.width, tex.height), tex);
}
}
}
GUI.EndGroup();
}
///
/// Draw a single-pixel outline around the specified rectangle.
///
static public void DrawOutline (Rect rect)
{
if (Event.current.type == EventType.Repaint)
{
Texture2D tex = contrastTexture;
GUI.color = Color.white;
DrawTiledTexture(new Rect(rect.xMin, rect.yMax, 1f, -rect.height), tex);
DrawTiledTexture(new Rect(rect.xMax, rect.yMax, 1f, -rect.height), tex);
DrawTiledTexture(new Rect(rect.xMin, rect.yMin, rect.width, 1f), tex);
DrawTiledTexture(new Rect(rect.xMin, rect.yMax, rect.width, 1f), tex);
}
}
///
/// Draw a single-pixel outline around the specified rectangle.
///
static public void DrawOutline (Rect rect, Color color)
{
if (Event.current.type == EventType.Repaint)
{
Texture2D tex = blankTexture;
GUI.color = color;
GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, 1f, rect.height), tex);
GUI.DrawTexture(new Rect(rect.xMax, rect.yMin, 1f, rect.height), tex);
GUI.DrawTexture(new Rect(rect.xMin, rect.yMin, rect.width, 1f), tex);
GUI.DrawTexture(new Rect(rect.xMin, rect.yMax, rect.width, 1f), tex);
GUI.color = Color.white;
}
}
///
/// Draw a selection outline around the specified rectangle.
///
static public void DrawOutline (Rect rect, Rect relative, Color color)
{
if (Event.current.type == EventType.Repaint)
{
// Calculate where the outer rectangle would be
float x = rect.xMin + rect.width * relative.xMin;
float y = rect.yMax - rect.height * relative.yMin;
float width = rect.width * relative.width;
float height = -rect.height * relative.height;
relative = new Rect(x, y, width, height);
// Draw the selection
DrawOutline(relative, color);
}
}
///
/// Draw a selection outline around the specified rectangle.
///
static public void DrawOutline (Rect rect, Rect relative)
{
if (Event.current.type == EventType.Repaint)
{
// Calculate where the outer rectangle would be
float x = rect.xMin + rect.width * relative.xMin;
float y = rect.yMax - rect.height * relative.yMin;
float width = rect.width * relative.width;
float height = -rect.height * relative.height;
relative = new Rect(x, y, width, height);
// Draw the selection
DrawOutline(relative);
}
}
///
/// Draw a 9-sliced outline.
///
static public void DrawOutline (Rect rect, Rect outer, Rect inner)
{
if (Event.current.type == EventType.Repaint)
{
Color green = new Color(0.4f, 1f, 0f, 1f);
DrawOutline(rect, new Rect(outer.x, inner.y, outer.width, inner.height));
DrawOutline(rect, new Rect(inner.x, outer.y, inner.width, outer.height));
DrawOutline(rect, outer, green);
}
}
///
/// Draw a checkered background for the specified texture.
///
static public Rect DrawBackground (Texture2D tex, float ratio)
{
Rect rect = GUILayoutUtility.GetRect(0f, 0f);
rect.width = Screen.width - rect.xMin;
rect.height = rect.width * ratio;
GUILayout.Space(rect.height);
if (Event.current.type == EventType.Repaint)
{
Texture2D blank = blankTexture;
Texture2D check = backdropTexture;
// Lines above and below the texture rectangle
GUI.color = new Color(0f, 0f, 0f, 0.2f);
GUI.DrawTexture(new Rect(rect.xMin, rect.yMin - 1, rect.width, 1f), blank);
GUI.DrawTexture(new Rect(rect.xMin, rect.yMax, rect.width, 1f), blank);
GUI.color = Color.white;
// Checker background
DrawTiledTexture(rect, check);
}
return rect;
}
///
/// Draw a visible separator in addition to adding some padding.
///
static public void DrawSeparator ()
{
GUILayout.Space(12f);
if (Event.current.type == EventType.Repaint)
{
Texture2D tex = blankTexture;
Rect rect = GUILayoutUtility.GetLastRect();
GUI.color = new Color(0f, 0f, 0f, 0.25f);
GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 4f), tex);
GUI.DrawTexture(new Rect(0f, rect.yMin + 6f, Screen.width, 1f), tex);
GUI.DrawTexture(new Rect(0f, rect.yMin + 9f, Screen.width, 1f), tex);
GUI.color = Color.white;
}
}
///
/// Draw a distinctly different looking header label
///
static public Rect DrawHeader (string text)
{
GUILayout.Space(28f);
Rect rect = GUILayoutUtility.GetLastRect();
rect.yMin += 5f;
rect.yMax -= 4f;
rect.width = Screen.width;
if (Event.current.type == EventType.Repaint)
{
GUI.color = Color.black;
GUI.DrawTexture(new Rect(0f, rect.yMin, Screen.width, rect.yMax - rect.yMin), gradientTexture);
GUI.color = new Color(0f, 0f, 0f, 0.25f);
GUI.DrawTexture(new Rect(0f, rect.yMin, Screen.width, 1f), blankTexture);
GUI.DrawTexture(new Rect(0f, rect.yMax - 1, Screen.width, 1f), blankTexture);
GUI.color = Color.white;
GUI.Label(new Rect(rect.x + 4f, rect.y, rect.width - 4, rect.height), text, EditorStyles.boldLabel);
}
return rect;
}
///
/// Draw a simple box outline for the entire line.
///
static public void HighlightLine (Color c)
{
Rect rect = GUILayoutUtility.GetRect(Screen.width - 16f, 22f);
GUILayout.Space(-23f);
c.a *= 0.3f;
GUI.color = c;
GUI.DrawTexture(rect, gradientTexture);
c.r *= 0.5f;
c.g *= 0.5f;
c.b *= 0.5f;
GUI.color = c;
GUI.DrawTexture(new Rect(rect.x, rect.y + 1f, rect.width, 1f), blankTexture);
GUI.DrawTexture(new Rect(rect.x, rect.y + rect.height - 1f, rect.width, 1f), blankTexture);
GUI.color = Color.white;
}
///
/// Convenience function that displays a list of sprites and returns the selected value.
///
static public string DrawList (string field, string[] list, string selection, params GUILayoutOption[] options)
{
if (list != null && list.Length > 0)
{
int index = 0;
if (string.IsNullOrEmpty(selection)) selection = list[0];
// We need to find the sprite in order to have it selected
if (!string.IsNullOrEmpty(selection))
{
for (int i = 0; i < list.Length; ++i)
{
if (selection.Equals(list[i], System.StringComparison.OrdinalIgnoreCase))
{
index = i;
break;
}
}
}
// Draw the sprite selection popup
index = string.IsNullOrEmpty(field) ?
EditorGUILayout.Popup(index, list, options) :
EditorGUILayout.Popup(field, index, list, options);
return list[index];
}
return null;
}
///
/// Convenience function that displays a list of sprites and returns the selected value.
///
static public string DrawAdvancedList (string field, string[] list, string selection, params GUILayoutOption[] options)
{
if (list != null && list.Length > 0)
{
int index = 0;
if (string.IsNullOrEmpty(selection)) selection = list[0];
// We need to find the sprite in order to have it selected
if (!string.IsNullOrEmpty(selection))
{
for (int i = 0; i < list.Length; ++i)
{
if (selection.Equals(list[i], System.StringComparison.OrdinalIgnoreCase))
{
index = i;
break;
}
}
}
// Draw the sprite selection popup
index = string.IsNullOrEmpty(field) ?
EditorGUILayout.Popup(index, list, "DropDownButton", options) :
EditorGUILayout.Popup(field, index, list, "DropDownButton", options);
return list[index];
}
return null;
}
///
/// Helper function that returns the selected root object.
///
static public GameObject SelectedRoot () { return SelectedRoot(false); }
///
/// Helper function that returns the selected root object.
///
static public GameObject SelectedRoot (bool createIfMissing)
{
GameObject go = Selection.activeGameObject;
// Only use active objects
if (go != null && !NGUITools.GetActive(go)) go = null;
// Try to find a panel
UIPanel p = (go != null) ? NGUITools.FindInParents(go) : null;
// No selection? Try to find the root automatically
if (p == null)
{
UIPanel[] panels = NGUITools.FindActive();
if (panels.Length > 0) go = panels[0].gameObject;
}
// Now find the first uniformly scaled object
if (go != null)
{
Transform t = go.transform;
// Find the first uniformly scaled object
while (!Mathf.Approximately(t.localScale.x, t.localScale.y) ||
!Mathf.Approximately(t.localScale.x, t.localScale.z))
{
t = t.parent;
if (t == null) return (p != null) ? p.gameObject : null;
else go = t.gameObject;
}
}
if (createIfMissing && go == null)
{
// No object specified -- find the first panel
if (go == null)
{
UIPanel panel = GameObject.FindObjectOfType(typeof(UIPanel)) as UIPanel;
if (panel != null) go = panel.gameObject;
}
// No UI present -- create a new one
if (go == null) go = UICreateNewUIWizard.CreateNewUI();
}
return go;
}
///
/// Helper function that checks to see if this action would break the prefab connection.
///
static public bool WillLosePrefab (GameObject root)
{
if (root == null) return false;
if (root.transform != null)
{
// Check if the selected object is a prefab instance and display a warning
#if UNITY_3_4
PrefabType type = EditorUtility.GetPrefabType(root);
#else
PrefabType type = PrefabUtility.GetPrefabType(root);
#endif
if (type == PrefabType.PrefabInstance)
{
return EditorUtility.DisplayDialog("Losing prefab",
"This action will lose the prefab connection. Are you sure you wish to continue?",
"Continue", "Cancel");
}
}
return true;
}
///
/// Change the import settings of the specified texture astet, making it readable.
///
static bool MakeTextureReadable (string path, bool force)
{
if (string.IsNullOrEmpty(path)) return false;
TextureImporter ti = astetImporter.GetAtPath(path) as TextureImporter;
if (ti == null) return false;
TextureImporterSettings settings = new TextureImporterSettings();
ti.ReadTextureSettings(settings);
if (force ||
settings.mipmapEnabled ||
!settings.readable ||
settings.maxTextureSize < 4096 ||
settings.filterMode != FilterMode.Point ||
settings.wrapMode != TextureWrapMode.Clamp ||
settings.npotScale != TextureImporterNPOTScale.None)
{
settings.mipmapEnabled = false;
settings.readable = true;
settings.maxTextureSize = 4096;
settings.textureFormat = TextureImporterFormat.ARGB32;
settings.filterMode = FilterMode.Point;
settings.wrapMode = TextureWrapMode.Clamp;
settings.npotScale = TextureImporterNPOTScale.None;
ti.SetTextureSettings(settings);
astetDatabase.Importastet(path, ImportastetOptions.ForceUpdate | ImportastetOptions.ForceSynchronousImport);
}
return true;
}
///
/// Change the import settings of the specified texture astet, making it suitable to be used as a texture atlas.
///
static bool MakeTextureAnAtlas (string path, bool force)
{
if (string.IsNullOrEmpty(path)) return false;
TextureImporter ti = astetImporter.GetAtPath(path) as TextureImporter;
if (ti == null) return false;
TextureImporterSettings settings = new TextureImporterSettings();
ti.ReadTextureSettings(settings);
if (force ||
settings.readable ||
settings.maxTextureSize < 4096 ||
settings.wrapMode != TextureWrapMode.Clamp ||
settings.npotScale != TextureImporterNPOTScale.ToNearest)
{
//settings.mipmapEnabled = true;
settings.readable = false;
settings.maxTextureSize = 4096;
settings.textureFormat = TextureImporterFormat.RGBA32;
settings.filterMode = FilterMode.Trilinear;
settings.aniso = 4;
settings.wrapMode = TextureWrapMode.Clamp;
settings.npotScale = TextureImporterNPOTScale.ToNearest;
ti.SetTextureSettings(settings);
astetDatabase.Importastet(path, ImportastetOptions.ForceUpdate | ImportastetOptions.ForceSynchronousImport);
}
return true;
}
///
/// Fix the import settings for the specified texture, re-importing it if necessary.
///
static public Texture2D ImportTexture (string path, bool forInput, bool force)
{
if (!string.IsNullOrEmpty(path))
{
if (forInput) { if (!MakeTextureReadable(path, force)) return null; }
else if (!MakeTextureAnAtlas(path, force)) return null;
//return astetDatabase.LoadastetAtPath(path, typeof(Texture2D)) as Texture2D;
Texture2D tex = astetDatabase.LoadastetAtPath(path, typeof(Texture2D)) as Texture2D;
astetDatabase.Refresh(ImportastetOptions.ForceSynchronousImport);
return tex;
}
return null;
}
///
/// Fix the import settings for the specified texture, re-importing it if necessary.
///
static public Texture2D ImportTexture (Texture tex, bool forInput, bool force)
{
if (tex != null)
{
string path = astetDatabase.GetastetPath(tex.GetInstanceID());
return ImportTexture(path, forInput, force);
}
return null;
}
///
/// Figures out the saveable filename for the texture of the specified atlas.
///
static public string GetSaveableTexturePath (UIAtlas atlas)
{
// Path where the texture atlas will be saved
string path = "";
// If the atlas already has a texture, overwrite its texture
if (atlas.texture != null)
{
path = astetDatabase.GetastetPath(atlas.texture.GetInstanceID());
if (!string.IsNullOrEmpty(path))
{
int dot = path.LastIndexOf('.');
return path.Substring(0, dot) + ".png";
}
}
// No texture to use -- figure out a name using the atlas
path = astetDatabase.GetastetPath(atlas.GetInstanceID());
path = string.IsNullOrEmpty(path) ? "astets/" + atlas.name + ".png" : path.Replace(".prefab", ".png");
return path;
}
///
/// Helper function that returns the folder where the current selection resides.
///
static public string GetSelectionFolder ()
{
if (Selection.activeObject != null)
{
string path = astetDatabase.GetastetPath(Selection.activeObject.GetInstanceID());
if (!string.IsNullOrEmpty(path))
{
int dot = path.LastIndexOf('.');
int slash = Mathf.Max(path.LastIndexOf('/'), path.LastIndexOf('\\'));
if (slash > 0) return (dot > slash) ? path.Substring(0, slash + 1) : path + "/";
}
}
return "astets/";
}
///
/// Struct type for the integer vector field below.
///
public struct IntVector
{
public int x;
public int y;
}
///
/// Integer vector field.
///
static public IntVector IntPair (string prefix, string leftCaption, string rightCaption, int x, int y)
{
GUILayout.BeginHorizontal();
if (string.IsNullOrEmpty(prefix))
{
GUILayout.Space(82f);
}
else
{
GUILayout.Label(prefix, GUILayout.Width(74f));
}
EditorGUIUtility.LookLikeControls(48f);
IntVector retVal;
retVal.x = EditorGUILayout.IntField(leftCaption, x, GUILayout.MinWidth(30f));
retVal.y = EditorGUILayout.IntField(rightCaption, y, GUILayout.MinWidth(30f));
EditorGUIUtility.LookLikeControls(80f);
GUILayout.EndHorizontal();
return retVal;
}
///
/// Integer rectangle field.
///
static public Rect IntRect (string prefix, Rect rect)
{
int left = Mathf.RoundToInt(rect.xMin);
int top = Mathf.RoundToInt(rect.yMin);
int width = Mathf.RoundToInt(rect.width);
int height = Mathf.RoundToInt(rect.height);
NGUIEditorTools.IntVector a = NGUIEditorTools.IntPair(prefix, "Left", "Top", left, top);
NGUIEditorTools.IntVector b = NGUIEditorTools.IntPair(null, "Width", "Height", width, height);
return new Rect(a.x, a.y, b.x, b.y);
}
///
/// Integer vector field.
///
static public Vector4 IntPadding (string prefix, Vector4 v)
{
int left = Mathf.RoundToInt(v.x);
int top = Mathf.RoundToInt(v.y);
int right = Mathf.RoundToInt(v.z);
int bottom = Mathf.RoundToInt(v.w);
NGUIEditorTools.IntVector a = NGUIEditorTools.IntPair(prefix, "Left", "Top", left, top);
NGUIEditorTools.IntVector b = NGUIEditorTools.IntPair(null, "Right", "Bottom", right, bottom);
return new Vector4(a.x, a.y, b.x, b.y);
}
///
/// Create an undo point for the specified objects.
///
static public void RegisterUndo (string name, params Object[] objects)
{
if (objects != null && objects.Length > 0)
{
foreach (Object obj in objects)
{
if (obj == null) continue;
Undo.RegisterUndo(obj, name);
EditorUtility.SetDirty(obj);
}
}
else
{
Undo.RegisterSceneUndo(name);
}
}
///
/// Find all scene components, active or inactive.
///
static public List FindInScene () where T : Component
{
T[] comps = Resources.FindObjectsOfTypeAll(typeof(T)) as T[];
List list = new List();
foreach (T comp in comps)
{
if (comp.gameObject.hideFlags == 0)
{
string path = astetDatabase.GetastetPath(comp.gameObject);
if (string.IsNullOrEmpty(path)) list.Add(comp);
}
}
return list;
}
///
/// Draw the specified sprite.
///
public static void DrawSprite (Texture2D tex, Rect rect, Rect outer, Rect inner, Rect uv, Color color)
{
DrawSprite(tex, rect, outer, inner, uv, color, null);
}
///
/// Draw the specified sprite.
///
public static void DrawSprite (Texture2D tex, Rect rect, Rect outer, Rect inner, Rect uv, Color color, Material mat)
{
// Create the texture rectangle that is centered inside rect.
Rect outerRect = rect;
outerRect.width = outer.width;
outerRect.height = outer.height;
if (outerRect.width > 0f)
{
float f = rect.width / outerRect.width;
outerRect.width *= f;
outerRect.height *= f;
}
if (rect.height > outerRect.height)
{
outerRect.y += (rect.height - outerRect.height) * 0.5f;
}
else if (outerRect.height > rect.height)
{
float f = rect.height / outerRect.height;
outerRect.width *= f;
outerRect.height *= f;
}
if (rect.width > outerRect.width) outerRect.x += (rect.width - outerRect.width) * 0.5f;
// Draw the background
NGUIEditorTools.DrawTiledTexture(outerRect, NGUIEditorTools.backdropTexture);
// Draw the sprite
GUI.color = color;
if (mat == null)
{
GUI.DrawTextureWithTexCoords(outerRect, tex, uv, true);
}
else
{
// NOTE: There is an issue in Unity that prevents it from clipping the drawn preview
// using BeginGroup/EndGroup, and there is no way to specify a UV rect... le'suq.
UnityEditor.EditorGUI.DrawPreviewTexture(outerRect, tex, mat);
}
// Draw the border indicator lines
GUI.BeginGroup(outerRect);
{
tex = NGUIEditorTools.contrastTexture;
GUI.color = Color.white;
if (inner.xMin != outer.xMin)
{
float x0 = (inner.xMin - outer.xMin) / outer.width * outerRect.width - 1;
NGUIEditorTools.DrawTiledTexture(new Rect(x0, 0f, 1f, outerRect.height), tex);
}
if (inner.xMax != outer.xMax)
{
float x1 = (inner.xMax - outer.xMin) / outer.width * outerRect.width - 1;
NGUIEditorTools.DrawTiledTexture(new Rect(x1, 0f, 1f, outerRect.height), tex);
}
if (inner.yMin != outer.yMin)
{
float y0 = (inner.yMin - outer.yMin) / outer.height * outerRect.height - 1;
NGUIEditorTools.DrawTiledTexture(new Rect(0f, y0, outerRect.width, 1f), tex);
}
if (inner.yMax != outer.yMax)
{
float y1 = (inner.yMax - outer.yMin) / outer.height * outerRect.height - 1;
NGUIEditorTools.DrawTiledTexture(new Rect(0f, y1, outerRect.width, 1f), tex);
}
}
GUI.EndGroup();
// Draw the lines around the sprite
Handles.color = Color.black;
Handles.DrawLine(new Vector3(outerRect.xMin, outerRect.yMin), new Vector3(outerRect.xMin, outerRect.yMax));
Handles.DrawLine(new Vector3(outerRect.xMax, outerRect.yMin), new Vector3(outerRect.xMax, outerRect.yMax));
Handles.DrawLine(new Vector3(outerRect.xMin, outerRect.yMin), new Vector3(outerRect.xMax, outerRect.yMin));
Handles.DrawLine(new Vector3(outerRect.xMin, outerRect.yMax), new Vector3(outerRect.xMax, outerRect.yMax));
// Sprite size label
string text = string.Format("Sprite Size: {0}x{1}",
Mathf.RoundToInt(Mathf.Abs(outer.width)),
Mathf.RoundToInt(Mathf.Abs(outer.height)));
EditorGUI.DropShadowLabel(GUILayoutUtility.GetRect(Screen.width, 18f), text);
}
///
/// Draw a sprite selection field.
///
static public void SpriteField (string fieldName, UIAtlas atlas, string spriteName,
SpriteSelector.Callback callback, params GUILayoutOption[] options)
{
GUILayout.BeginHorizontal();
GUILayout.Label(fieldName, GUILayout.Width(76f));
if (GUILayout.Button(spriteName, "MiniPullDown", options))
{
SpriteSelector.Show(atlas, spriteName, callback);
}
GUILayout.EndHorizontal();
}
///
/// Draw a sprite selection field.
///
static public void SpriteField (string fieldName, UIAtlas atlas, string spriteName, SpriteSelector.Callback callback)
{
SpriteField(fieldName, null, atlas, spriteName, callback);
}
///
/// Draw a sprite selection field.
///
static public void SpriteField (string fieldName, string caption, UIAtlas atlas, string spriteName, SpriteSelector.Callback callback)
{
GUILayout.BeginHorizontal();
GUILayout.Label(fieldName, GUILayout.Width(76f));
if (atlas.GetSprite(spriteName) == null)
spriteName = "";
if (GUILayout.Button(spriteName, "MiniPullDown", GUILayout.Width(120f)))
{
SpriteSelector.Show(atlas, spriteName, callback);
}
if (!string.IsNullOrEmpty(caption))
{
GUILayout.Space(20f);
GUILayout.Label(caption);
}
GUILayout.EndHorizontal();
}
///
/// Draw a simple sprite selection button.
///
static public bool SimpleSpriteField (UIAtlas atlas, string spriteName, SpriteSelector.Callback callback, params GUILayoutOption[] options)
{
if (atlas.GetSprite(spriteName) == null)
spriteName = "";
if (GUILayout.Button(spriteName, "DropDown", options))
{
SpriteSelector.Show(atlas, spriteName, callback);
return true;
}
return false;
}
///
/// Convenience function that displays a list of sprites and returns the selected value.
///
static public void AdvancedSpriteField (UIAtlas atlas, string spriteName, SpriteSelector.Callback callback, bool editable,
params GUILayoutOption[] options)
{
// Give the user a warning if there are no sprites in the atlas
if (atlas.spriteList.Count == 0)
{
EditorGUILayout.HelpBox("No sprites found", MessageType.Warning);
return;
}
// Sprite selection drop-down list
GUILayout.BeginHorizontal();
{
if (GUILayout.Button("Sprite", "DropDownButton", GUILayout.Width(76f)))
{
SpriteSelector.Show(atlas, spriteName, callback);
}
if (editable)
{
string sn = GUILayout.TextField(spriteName);
if (sn != spriteName)
{
UIAtlas.Sprite sp = atlas.GetSprite(spriteName);
if (sp != null)
{
NGUIEditorTools.RegisterUndo("Edit Sprite Name", atlas);
sp.name = sn;
spriteName = sn;
}
}
}
else
{
GUILayout.BeginHorizontal();
GUILayout.Label(spriteName, "HelpBox", GUILayout.Height(18f));
GUILayout.Space(18f);
GUILayout.EndHorizontal();
if (GUILayout.Button("Edit", GUILayout.Width(40f)))
{
EditorPrefs.SetString("NGUI Selected Sprite", spriteName);
Select(atlas.gameObject);
}
}
}
GUILayout.EndHorizontal();
}
///
/// Select the specified game object and remember what was selected before.
///
static public void Select (GameObject go)
{
mPrevious = Selection.activeGameObject;
Selection.activeGameObject = go;
}
///
/// Select the previous game object.
///
static public void SelectPrevious ()
{
if (mPrevious != null)
{
Selection.activeGameObject = mPrevious;
mPrevious = null;
}
}
///
/// Previously selected game object.
///
static public GameObject previousSelection { get { return mPrevious; } }
///
/// Helper function that checks to see if the scale is uniform.
///
static public bool IsUniform (Vector3 scale)
{
return Mathf.Approximately(scale.x, scale.y) && Mathf.Approximately(scale.x, scale.z);
}
///
/// Check to see if the specified game object has a uniform scale.
///
static public bool IsUniform (GameObject go)
{
if (go == null) return true;
if (go.GetComponent() != null)
{
Transform parent = go.transform.parent;
return parent == null || IsUniform(parent.gameObject);
}
return IsUniform(go.transform.lossyScale);
}
///
/// Fix uniform scaling of the specified object.
///
static public void FixUniform (GameObject go)
{
Transform t = go.transform;
while (t != null && t.gameObject.GetComponent() == null)
{
if (!NGUIEditorTools.IsUniform(t.localScale))
{
Undo.RegisterUndo(t, "Uniform scaling fix");
t.localScale = Vector3.one;
EditorUtility.SetDirty(t);
}
t = t.parent;
}
}
///
/// Raycast into the specified panel, returning a list of widgets.
///
static public UIWidget[] Raycast (UIPanel panel, Vector2 mousePos)
{
List list = new List();
UIWidget[] widgets = panel.gameObject.GetComponentsInChildren();
for (int i = 0; i < widgets.Length; ++i)
{
UIWidget w = widgets[i];
if (w.panel == panel)
{
Vector3[] corners = NGUIMath.CalculateWidgetCorners(w);
if (DistanceToRectangle(corners, mousePos) == 0f)
list.Add(w);
}
}
list.Sort(delegate(UIWidget w1, UIWidget w2) { return w2.depth.CompareTo(w1.depth); });
return list.ToArray();
}
///
/// Determine the distance from the specified point to the line segment.
///
static float DistancePointToLineSegment (Vector2 point, Vector2 a, Vector2 b)
{
float l2 = (b - a).sqrMagnitude;
if (l2 == 0f) return (point - a).magnitude;
float t = Vector2.Dot(point - a, b - a) / l2;
if (t < 0f) return (point - a).magnitude;
else if (t > 1f) return (point - b).magnitude;
Vector2 projection = a + t * (b - a);
return (point - projection).magnitude;
}
///
/// Determine the distance from the mouse position to the world rectangle specified by the 4 points.
///
static public float DistanceToRectangle (Vector3[] worldPoints, Vector2 mousePos)
{
Vector2[] screenPoints = new Vector2[4];
for (int i = 0; i < 4; ++i)
screenPoints[i] = HandleUtility.WorldToGUIPoint(worldPoints[i]);
return DistanceToRectangle(screenPoints, mousePos);
}
///
/// Determine the distance from the mouse position to the screen space rectangle specified by the 4 points.
///
static public float DistanceToRectangle (Vector2[] screenPoints, Vector2 mousePos)
{
bool oddNodes = false;
int j = 4;
for (int i = 0; i < 5; i++)
{
Vector3 v0 = screenPoints[NGUIMath.RepeatIndex(i, 4)];
Vector3 v1 = screenPoints[NGUIMath.RepeatIndex(j, 4)];
if ((v0.y > mousePos.y) != (v1.y > mousePos.y))
{
if (mousePos.x < (v1.x - v0.x) * (mousePos.y - v0.y) / (v1.y - v0.y) + v0.x)
{
oddNodes = !oddNodes;
}
}
j = i;
}
if (!oddNodes)
{
float dist, closestDist = -1f;
for (int i = 0; i < 4; i++)
{
Vector3 v0 = screenPoints[i];
Vector3 v1 = screenPoints[NGUIMath.RepeatIndex(i + 1, 4)];
dist = DistancePointToLineSegment(mousePos, v0, v1);
if (dist < closestDist || closestDist < 0f) closestDist = dist;
}
return closestDist;
}
else return 0f;
}
}