//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2015 Tasharen Entertainment
//----------------------------------------------
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
///
/// Inspector class used to edit the UIAtlas.
///
[CustomEditor(typeof(UIAtlas))]
public class UIAtlasInspector : Editor
{
static public UIAtlasInspector instance;
enum AtlasType
{
Normal,
Reference,
}
UIAtlas mAtlas;
AtlasType mType = AtlasType.Normal;
UIAtlas mReplacement = null;
void OnEnable () { instance = this; }
void OnDisable () { instance = null; }
///
/// Convenience function -- mark all widgets using the sprite as changed.
///
void MarkSpriteAsDirty ()
{
UISpriteData sprite = (mAtlas != null) ? mAtlas.GetSprite(NGUISettings.selectedSprite) : null;
if (sprite == null) return;
UISprite[] sprites = NGUITools.FindActive();
foreach (UISprite sp in sprites)
{
if (UIAtlas.CheckIfRelated(sp.atlas, mAtlas) && sp.spriteName == sprite.name)
{
UIAtlas atl = sp.atlas;
sp.atlas = null;
sp.atlas = atl;
EditorUtility.SetDirty(sp);
}
}
UILabel[] labels = NGUITools.FindActive();
foreach (UILabel lbl in labels)
{
if (lbl.bitmapFont != null && UIAtlas.CheckIfRelated(lbl.bitmapFont.atlas, mAtlas) && lbl.bitmapFont.UsesSprite(sprite.name))
{
UIFont font = lbl.bitmapFont;
lbl.bitmapFont = null;
lbl.bitmapFont = font;
EditorUtility.SetDirty(lbl);
}
}
}
///
/// Replacement atlas selection callback.
///
void OnSelectAtlas (Object obj)
{
if (mReplacement != obj)
{
// Undo doesn't work correctly in this case... so I won't bother.
//NGUIEditorTools.RegisterUndo("Atlas Change");
//NGUIEditorTools.RegisterUndo("Atlas Change", mAtlas);
mAtlas.replacement = obj as UIAtlas;
mReplacement = mAtlas.replacement;
NGUITools.SetDirty(mAtlas);
if (mReplacement == null) mType = AtlasType.Normal;
}
}
///
/// Draw the inspector widget.
///
public override void OnInspectorGUI ()
{
NGUIEditorTools.SetLabelWidth(80f);
mAtlas = target as UIAtlas;
UISpriteData sprite = (mAtlas != null) ? mAtlas.GetSprite(NGUISettings.selectedSprite) : null;
GUILayout.Space(6f);
if (mAtlas.replacement != null)
{
mType = AtlasType.Reference;
mReplacement = mAtlas.replacement;
}
GUILayout.BeginHorizontal();
AtlasType after = (AtlasType)EditorGUILayout.EnumPopup("Atlas Type", mType);
NGUIEditorTools.DrawPadding();
GUILayout.EndHorizontal();
if (mType != after)
{
if (after == AtlasType.Normal)
{
mType = AtlasType.Normal;
OnSelectAtlas(null);
}
else
{
mType = AtlasType.Reference;
}
}
if (mType == AtlasType.Reference)
{
ComponentSelector.Draw(mAtlas.replacement, OnSelectAtlas, true);
GUILayout.Space(6f);
EditorGUILayout.HelpBox("You can have one atlas simply point to " +
"another one. This is useful if you want to be " +
"able to quickly replace the contents of one " +
"atlas with another one, for example for " +
"swapping an SD atlas with an HD one, or " +
"replacing an English atlas with a Chinese " +
"one. All the sprites referencing this atlas " +
"will update their references to the new one.", MessageType.Info);
if (mReplacement != mAtlas && mAtlas.replacement != mReplacement)
{
NGUIEditorTools.RegisterUndo("Atlas Change", mAtlas);
mAtlas.replacement = mReplacement;
NGUITools.SetDirty(mAtlas);
}
return;
}
//GUILayout.Space(6f);
Material mat = EditorGUILayout.ObjectField("Material", mAtlas.spriteMaterial, typeof(Material), false) as Material;
if (mAtlas.spriteMaterial != mat)
{
NGUIEditorTools.RegisterUndo("Atlas Change", mAtlas);
mAtlas.spriteMaterial = mat;
// Ensure that this atlas has valid import settings
if (mAtlas.texture != null) NGUIEditorTools.ImportTexture(mAtlas.texture, false, false, !mAtlas.premultipliedAlpha);
mAtlas.MarkAsChanged();
}
if (mat != null)
{
TextAsset ta = EditorGUILayout.ObjectField("TP Import", null, typeof(TextAsset), false) as TextAsset;
if (ta != null)
{
// Ensure that this atlas has valid import settings
if (mAtlas.texture != null) NGUIEditorTools.ImportTexture(mAtlas.texture, false, false, !mAtlas.premultipliedAlpha);
NGUIEditorTools.RegisterUndo("Import Sprites", mAtlas);
NGUIJson.LoadSpriteData(mAtlas, ta);
if (sprite != null) sprite = mAtlas.GetSprite(sprite.name);
mAtlas.MarkAsChanged();
}
float pixelSize = EditorGUILayout.FloatField("Pixel Size", mAtlas.pixelSize, GUILayout.Width(120f));
if (pixelSize != mAtlas.pixelSize)
{
NGUIEditorTools.RegisterUndo("Atlas Change", mAtlas);
mAtlas.pixelSize = pixelSize;
}
}
if (mAtlas.spriteMaterial != null)
{
Color blueColor = new Color(0f, 0.7f, 1f, 1f);
Color greenColor = new Color(0.4f, 1f, 0f, 1f);
if (sprite == null && mAtlas.spriteList.Count > 0)
{
string spriteName = NGUISettings.selectedSprite;
if (!string.IsNullOrEmpty(spriteName)) sprite = mAtlas.GetSprite(spriteName);
if (sprite == null) sprite = mAtlas.spriteList[0];
}
if (sprite != null)
{
if (sprite == null) return;
Texture2D tex = mAtlas.spriteMaterial.mainTexture as Texture2D;
if (tex != null)
{
if (!NGUIEditorTools.DrawHeader("Sprite Details")) return;
NGUIEditorTools.BeginContents();
GUILayout.Space(3f);
NGUIEditorTools.DrawAdvancedSpriteField(mAtlas, sprite.name, SelectSprite, true);
GUILayout.Space(6f);
GUI.changed = false;
GUI.backgroundColor = greenColor;
NGUIEditorTools.IntVector sizeA = NGUIEditorTools.IntPair("Dimensions", "X", "Y", sprite.x, sprite.y);
NGUIEditorTools.IntVector sizeB = NGUIEditorTools.IntPair(null, "Width", "Height", sprite.width, sprite.height);
EditorGUILayout.Separator();
GUI.backgroundColor = blueColor;
NGUIEditorTools.IntVector borderA = NGUIEditorTools.IntPair("Border", "Left", "Right", sprite.borderLeft, sprite.borderRight);
NGUIEditorTools.IntVector borderB = NGUIEditorTools.IntPair(null, "Bottom", "Top", sprite.borderBottom, sprite.borderTop);
EditorGUILayout.Separator();
GUI.backgroundColor = Color.white;
NGUIEditorTools.IntVector padA = NGUIEditorTools.IntPair("Padding", "Left", "Right", sprite.paddingLeft, sprite.paddingRight);
NGUIEditorTools.IntVector padB = NGUIEditorTools.IntPair(null, "Bottom", "Top", sprite.paddingBottom, sprite.paddingTop);
if (GUI.changed)
{
NGUIEditorTools.RegisterUndo("Atlas Change", mAtlas);
sprite.x = sizeA.x;
sprite.y = sizeA.y;
sprite.width = sizeB.x;
sprite.height = sizeB.y;
sprite.paddingLeft = padA.x;
sprite.paddingRight = padA.y;
sprite.paddingBottom = padB.x;
sprite.paddingTop = padB.y;
sprite.borderLeft = borderA.x;
sprite.borderRight = borderA.y;
sprite.borderBottom = borderB.x;
sprite.borderTop = borderB.y;
MarkSpriteAsDirty();
}
GUILayout.Space(3f);
GUILayout.BeginHorizontal();
if (GUILayout.Button("Duplicate"))
{
UIAtlasMaker.SpriteEntry se = UIAtlasMaker.DuplicateSprite(mAtlas, sprite.name);
if (se != null) NGUISettings.selectedSprite = se.name;
}
if (GUILayout.Button("Save As..."))
{
#if UNITY_3_5
string path = EditorUtility.SaveFilePanel("Save As",
NGUISettings.currentPath, sprite.name + ".png", "png");
#else
string path = EditorUtility.SaveFilePanelInProject("Save As",
sprite.name + ".png", "png",
"Extract sprite into which file?", NGUISettings.currentPath);
#endif
if (!string.IsNullOrEmpty(path))
{
NGUISettings.currentPath = System.IO.Path.GetDirectoryName(path);
UIAtlasMaker.SpriteEntry se = UIAtlasMaker.ExtractSprite(mAtlas, sprite.name);
if (se != null)
{
byte[] bytes = se.tex.EncodeToPNG();
File.WriteAllBytes(path, bytes);
AssetDatabase.ImportAsset(path);
if (se.temporaryTexture) DestroyImmediate(se.tex);
}
}
}
GUILayout.EndHorizontal();
NGUIEditorTools.EndContents();
}
if (NGUIEditorTools.DrawHeader("Modify"))
{
NGUIEditorTools.BeginContents();
EditorGUILayout.BeginHorizontal();
GUILayout.Space(20f);
EditorGUILayout.BeginVertical();
NGUISettings.backgroundColor = EditorGUILayout.ColorField("Background", NGUISettings.backgroundColor);
if (GUILayout.Button("Add a Shadow")) AddShadow(sprite);
if (GUILayout.Button("Add a Soft Outline")) AddOutline(sprite);
if (GUILayout.Button("Add a Transparent Border")) AddTransparentBorder(sprite);
if (GUILayout.Button("Add a Clamped Border")) AddClampedBorder(sprite);
if (GUILayout.Button("Add a Tiled Border")) AddTiledBorder(sprite);
EditorGUI.BeginDisabledGroup(!sprite.hasBorder);
if (GUILayout.Button("Crop Border")) CropBorder(sprite);
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndVertical();
GUILayout.Space(20f);
EditorGUILayout.EndHorizontal();
NGUIEditorTools.EndContents();
}
if (NGUIEditorTools.previousSelection != null)
{
GUILayout.Space(3f);
GUI.backgroundColor = Color.green;
if (GUILayout.Button("<< Return to " + NGUIEditorTools.previousSelection.name))
{
NGUIEditorTools.SelectPrevious();
}
GUI.backgroundColor = Color.white;
}
}
}
}
///
/// Sprite selection callback.
///
void SelectSprite (string spriteName)
{
if (NGUISettings.selectedSprite != spriteName)
{
NGUISettings.selectedSprite = spriteName;
Repaint();
}
}
///
/// All widgets have a preview.
///
public override bool HasPreviewGUI () { return true; }
///
/// Draw the sprite preview.
///
public override void OnPreviewGUI (Rect rect, GUIStyle background)
{
UISpriteData sprite = (mAtlas != null) ? mAtlas.GetSprite(NGUISettings.selectedSprite) : null;
if (sprite == null) return;
Texture2D tex = mAtlas.texture as Texture2D;
if (tex != null) NGUIEditorTools.DrawSprite(tex, rect, sprite, Color.white);
}
///
/// Add a transparent border around the sprite.
///
void AddTransparentBorder (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width;
int h1 = se.tex.height;
int w2 = w1 + 2;
int h2 = h1 + 2;
Color32[] c2 = NGUIEditorTools.AddBorder(se.tex.GetPixels32(), w1, h1);
if (se.temporaryTexture) DestroyImmediate(se.tex);
++se.borderLeft;
++se.borderRight;
++se.borderTop;
++se.borderBottom;
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
///
/// Add a border around the sprite that extends the existing edge pixels.
///
void AddClampedBorder (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width - se.borderLeft - se.borderRight;
int h1 = se.tex.height - se.borderBottom - se.borderTop;
int w2 = se.tex.width + 2;
int h2 = se.tex.height + 2;
Color32[] c1 = se.tex.GetPixels32();
Color32[] c2 = new Color32[w2 * h2];
for (int y2 = 0; y2 < h2; ++y2)
{
int y1 = se.borderBottom + NGUIMath.ClampIndex(y2 - se.borderBottom - 1, h1);
for (int x2 = 0; x2 < w2; ++x2)
{
int x1 = se.borderLeft + NGUIMath.ClampIndex(x2 - se.borderLeft - 1, w1);
c2[x2 + y2 * w2] = c1[x1 + y1 * se.tex.width];
}
}
if (se.temporaryTexture) DestroyImmediate(se.tex);
++se.borderLeft;
++se.borderRight;
++se.borderTop;
++se.borderBottom;
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
///
/// Add a border around the sprite that copies the pixels from the opposite side, making it possible for the sprite to tile without seams.
///
void AddTiledBorder (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width - se.borderLeft - se.borderRight;
int h1 = se.tex.height - se.borderBottom - se.borderTop;
int w2 = se.tex.width + 2;
int h2 = se.tex.height + 2;
Color32[] c1 = se.tex.GetPixels32();
Color32[] c2 = new Color32[w2 * h2];
for (int y2 = 0; y2 < h2; ++y2)
{
int y1 = se.borderBottom + NGUIMath.RepeatIndex(y2 - se.borderBottom - 1, h1);
for (int x2 = 0; x2 < w2; ++x2)
{
int x1 = se.borderLeft + NGUIMath.RepeatIndex(x2 - se.borderLeft - 1, w1);
c2[x2 + y2 * w2] = c1[x1 + y1 * se.tex.width];
}
}
if (se.temporaryTexture) DestroyImmediate(se.tex);
++se.borderLeft;
++se.borderRight;
++se.borderTop;
++se.borderBottom;
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
///
/// Crop the border pixels around the sprite.
///
void CropBorder (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width;
int h1 = se.tex.height;
int w2 = w1 - se.borderLeft - se.borderRight;
int h2 = h1 - se.borderTop - se.borderBottom;
Color32[] c1 = se.tex.GetPixels32();
Color32[] c2 = new Color32[w2 * h2];
for (int y2 = 0; y2 < h2; ++y2)
{
int y1 = y2 + se.borderBottom;
for (int x2 = 0; x2 < w2; ++x2)
{
int x1 = x2 + se.borderLeft;
c2[x2 + y2 * w2] = c1[x1 + y1 * w1];
}
}
se.borderLeft = 0;
se.borderRight = 0;
se.borderTop = 0;
se.borderBottom = 0;
if (se.temporaryTexture) DestroyImmediate(se.tex);
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
///
/// Add a dark shadow below and to the right of the sprite.
///
void AddShadow (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width;
int h1 = se.tex.height;
int w2 = w1 + 2;
int h2 = h1 + 2;
Color32[] c2 = NGUIEditorTools.AddBorder(se.tex.GetPixels32(), w1, h1);
NGUIEditorTools.AddShadow(c2, w2, h2, NGUISettings.backgroundColor);
if (se.temporaryTexture) DestroyImmediate(se.tex);
if ((se.borderLeft | se.borderRight | se.borderBottom | se.borderTop) != 0)
{
++se.borderLeft;
++se.borderRight;
++se.borderTop;
++se.borderBottom;
}
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
///
/// Add a dark shadowy outline around the sprite, giving it some visual depth.
///
void AddOutline (UISpriteData sprite)
{
List sprites = new List();
UIAtlasMaker.ExtractSprites(mAtlas, sprites);
UIAtlasMaker.SpriteEntry se = null;
for (int i = 0; i < sprites.Count; ++i)
{
if (sprites[i].name == sprite.name)
{
se = sprites[i];
break;
}
}
if (se != null)
{
int w1 = se.tex.width;
int h1 = se.tex.height;
int w2 = w1 + 2;
int h2 = h1 + 2;
Color32[] c2 = NGUIEditorTools.AddBorder(se.tex.GetPixels32(), w1, h1);
NGUIEditorTools.AddDepth(c2, w2, h2, NGUISettings.backgroundColor);
if (se.temporaryTexture) DestroyImmediate(se.tex);
if ((se.borderLeft | se.borderRight | se.borderBottom | se.borderTop) != 0)
{
++se.borderLeft;
++se.borderRight;
++se.borderTop;
++se.borderBottom;
}
se.tex = new Texture2D(w2, h2);
se.tex.name = sprite.name;
se.tex.SetPixels32(c2);
se.tex.Apply();
se.temporaryTexture = true;
UIAtlasMaker.UpdateAtlas(mAtlas, sprites);
DestroyImmediate(se.tex);
se.tex = null;
}
}
}