This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,551 @@
using System;
using System.IO;
using UnityEngine;
using UnityEditorInternal;
using System.Collections.Generic;
using System.Text;
using UnityTexture2D = UnityEngine.Texture2D;
using UnityEditor.ShortcutManagement;
namespace UnityEditor.U2D.Sprites
{
[RequireSpriteDataProvider(typeof(ITextureDataProvider))]
internal partial class SpriteFrameModule : SpriteFrameModuleBase
{
public enum AutoSlicingMethod
{
DeleteAll = 0,
Smart = 1,
Safe = 2
}
private bool[] m_AlphaPixelCache;
SpriteFrameModuleContext m_SpriteFrameModuleContext;
private const float kOverlapTolerance = 0.00001f;
private StringBuilder m_SpriteNameStringBuilder;
private List<Rect> m_PotentialRects;
public List<Rect> potentialRects
{
set => m_PotentialRects = value;
}
public SpriteFrameModule(ISpriteEditor sw, IEventSystem es, IUndoSystem us, IAssetDatabase ad) :
base("Sprite Editor", sw, es, us, ad)
{}
class SpriteFrameModuleContext : IShortcutToolContext
{
SpriteFrameModule m_SpriteFrameModule;
public SpriteFrameModuleContext(SpriteFrameModule spriteFrame)
{
m_SpriteFrameModule = spriteFrame;
}
public bool active
{
get { return true; }
}
public SpriteFrameModule spriteFrameModule
{
get { return m_SpriteFrameModule; }
}
}
[FormerlyPrefKeyAs("Sprite Editor/Trim", "#t")]
[Shortcut("Sprite Editor/Trim", typeof(SpriteFrameModuleContext), KeyCode.T, ShortcutModifiers.Shift)]
static void ShortcutTrim(ShortcutArguments args)
{
if (!string.IsNullOrEmpty(GUI.GetNameOfFocusedControl()))
return;
var spriteFrameContext = (SpriteFrameModuleContext)args.context;
spriteFrameContext.spriteFrameModule.TrimAlpha();
spriteFrameContext.spriteFrameModule.spriteEditor.RequestRepaint();
}
public override void OnModuleActivate()
{
base.OnModuleActivate();
spriteEditor.enableMouseMoveEvent = true;
m_SpriteFrameModuleContext = new SpriteFrameModuleContext(this);
ShortcutIntegration.instance.contextManager.RegisterToolContext(m_SpriteFrameModuleContext);
m_SpriteNameStringBuilder = new StringBuilder(GetSpriteNamePrefix() + "_");
m_PotentialRects = null;
}
public override void OnModuleDeactivate()
{
base.OnModuleDeactivate();
ShortcutIntegration.instance.contextManager.DeregisterToolContext(m_SpriteFrameModuleContext);
m_PotentialRects = null;
m_AlphaPixelCache = null;
}
public static SpriteImportMode GetSpriteImportMode(ISpriteEditorDataProvider dataProvider)
{
return dataProvider == null ? SpriteImportMode.None : dataProvider.spriteImportMode;
}
public override bool CanBeActivated()
{
return GetSpriteImportMode(spriteEditor.GetDataProvider<ISpriteEditorDataProvider>()) != SpriteImportMode.Polygon;
}
private string GenerateSpriteNameWithIndex(int startIndex)
{
int originalLength = m_SpriteNameStringBuilder.Length;
m_SpriteNameStringBuilder.Append(startIndex);
var name = m_SpriteNameStringBuilder.ToString();
m_SpriteNameStringBuilder.Length = originalLength;
return name;
}
// 1. Find top-most rectangle
// 2. Sweep it vertically to find out all rects from that "row"
// 3. goto 1.
// This will give us nicely sorted left->right top->down list of rectangles
// Works for most sprite sheets pretty nicely
private List<Rect> SortRects(List<Rect> rects)
{
List<Rect> result = new List<Rect>();
while (rects.Count > 0)
{
// Because the slicing algorithm works from bottom-up, the topmost rect is the last one in the array
Rect r = rects[rects.Count - 1];
Rect sweepRect = new Rect(0, r.yMin, textureActualWidth, r.height);
List<Rect> rowRects = RectSweep(rects, sweepRect);
if (rowRects.Count > 0)
result.AddRange(rowRects);
else
{
// We didn't find any rects, just dump the remaining rects and continue
result.AddRange(rects);
break;
}
}
return result;
}
private List<Rect> RectSweep(List<Rect> rects, Rect sweepRect)
{
if (rects == null || rects.Count == 0)
return new List<Rect>();
List<Rect> containedRects = new List<Rect>();
foreach (Rect rect in rects)
{
if (rect.Overlaps(sweepRect))
containedRects.Add(rect);
}
// Remove found rects from original list
foreach (Rect rect in containedRects)
rects.Remove(rect);
// Sort found rects by x position
containedRects.Sort((a, b) => a.x.CompareTo(b.x));
return containedRects;
}
private int AddSprite(Rect frame, int alignment, Vector2 pivot, AutoSlicingMethod slicingMethod, int originalCount, ref int nameIndex)
{
int outSprite = -1;
switch (slicingMethod)
{
case AutoSlicingMethod.DeleteAll:
{
while (outSprite == -1)
{
outSprite = AddSprite(frame, alignment, pivot, GenerateSpriteNameWithIndex(nameIndex++), Vector4.zero, false);
}
}
break;
case AutoSlicingMethod.Smart:
{
outSprite = GetExistingOverlappingSprite(frame, originalCount, true);
if (outSprite != -1)
{
var existingRect = m_RectsCache.spriteRects[outSprite];
existingRect.rect = frame;
existingRect.alignment = (SpriteAlignment)alignment;
existingRect.pivot = pivot;
}
else
{
while (outSprite == -1)
{
outSprite = AddSprite(frame, alignment, pivot, GenerateSpriteNameWithIndex(nameIndex++), Vector4.zero);
}
}
}
break;
case AutoSlicingMethod.Safe:
{
outSprite = GetExistingOverlappingSprite(frame, originalCount);
while (outSprite == -1)
{
outSprite = AddSprite(frame, alignment, pivot, GenerateSpriteNameWithIndex(nameIndex++), Vector4.zero);
}
}
break;
}
return outSprite;
}
private int GetExistingOverlappingSprite(Rect rect, int originalCount, bool bestFit = false)
{
var count = Math.Min(originalCount, m_RectsCache.spriteRects.Count);
int bestRect = -1;
float rectArea = rect.width * rect.height;
if (rectArea < kOverlapTolerance)
return bestRect;
float bestRatio = float.MaxValue;
float bestArea = float.MaxValue;
for (int i = 0; i < count; i++)
{
Rect existingRect = m_RectsCache.spriteRects[i].rect;
if (existingRect.Overlaps(rect))
{
if (bestFit)
{
float dx = Math.Min(rect.xMax, existingRect.xMax) - Math.Max(rect.xMin, existingRect.xMin);
float dy = Math.Min(rect.yMax, existingRect.yMax) - Math.Max(rect.yMin, existingRect.yMin);
float overlapArea = dx * dy;
float overlapRatio = Math.Abs((overlapArea / rectArea) - 1.0f);
float existingArea = existingRect.width * existingRect.height;
if (overlapRatio < bestRatio || (overlapRatio < kOverlapTolerance && existingArea < bestArea))
{
bestRatio = overlapRatio;
if (overlapRatio < kOverlapTolerance)
bestArea = existingArea;
bestRect = i;
}
}
else
{
bestRect = i;
break;
}
}
}
return bestRect;
}
private bool PixelHasAlpha(int x, int y, UnityTexture2D texture)
{
if (m_AlphaPixelCache == null)
{
m_AlphaPixelCache = new bool[texture.width * texture.height];
Color32[] pixels = texture.GetPixels32();
for (int i = 0; i < pixels.Length; i++)
m_AlphaPixelCache[i] = pixels[i].a != 0;
}
int index = y * (int)texture.width + x;
return m_AlphaPixelCache[index];
}
private int AddSprite(Rect rect, int alignment, Vector2 pivot, string name, Vector4 border, bool uniqueNameCheck = true)
{
var sed = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
long internalID = AssetImporter.MakeLocalFileIDWithHash(spriteType.persistentTypeID, name, 0);
if (m_RectsCache.HasName(name))
return -1;
if (m_RectsCache.HasInternalID(internalID))
return -1;
SpriteRect spriteRect = new SpriteRect();
spriteRect.rect = rect;
spriteRect.alignment = (SpriteAlignment)alignment;
spriteRect.pivot = pivot;
spriteRect.name = name;
spriteRect.originalName = spriteRect.name;
spriteRect.border = border;
spriteRect.internalID = internalID;
spriteRect.spriteID = GUID.CreateGUIDFromSInt64(internalID);
// check if someone is using the internal id, if so, we change it to us.
// Only TextureImporter needs this now.
var ai = sed.targetObject as TextureImporter;
var oldName = "";
if (ai != null && ai.GetNameFromInternalIDMap(internalID, ref oldName))
{
if (string.IsNullOrEmpty(oldName))
return -1;
spriteRect.originalName = oldName;
}
else
{
spriteRect.m_RegisterInternalID = true;
}
m_RectsCache.Add(spriteRect);
spriteEditor.SetDataModified();
return m_RectsCache.spriteRects.Count - 1;
}
private string GetSpriteNamePrefix()
{
return Path.GetFileNameWithoutExtension(spriteAssetPath);
}
public void DoAutomaticSlicing(int minimumSpriteSize, int alignment, Vector2 pivot, AutoSlicingMethod slicingMethod)
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Automatic Slicing");
if (slicingMethod == AutoSlicingMethod.DeleteAll)
m_RectsCache.Clear();
var textureToUse = GetTextureToSlice();
List<Rect> frames = new List<Rect>(InternalSpriteUtility.GenerateAutomaticSpriteRectangles((UnityTexture2D)textureToUse, minimumSpriteSize, 0));
frames = SortRects(frames);
int index = 0;
int originalCount = m_RectsCache.spriteRects.Count;
foreach (Rect frame in frames)
AddSprite(frame, alignment, pivot, slicingMethod, originalCount, ref index);
selected = null;
spriteEditor.SetDataModified();
Repaint();
}
UnityTexture2D GetTextureToSlice()
{
int width, height;
m_TextureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var readableTexture = m_TextureDataProvider.GetReadableTexture2D();
if (readableTexture == null || (readableTexture.width == width && readableTexture.height == height))
return readableTexture;
// we want to slice based on the original texture slice. Upscale the imported texture
var texture = UnityEditor.SpriteUtility.CreateTemporaryDuplicate(readableTexture, width, height);
return texture;
}
public IEnumerable<Rect> GetGridRects(Vector2 size, Vector2 offset, Vector2 padding, bool keepEmptyRects)
{
var textureToUse = GetTextureToSlice();
return InternalSpriteUtility.GenerateGridSpriteRectangles((UnityTexture2D)textureToUse, offset, size, padding, keepEmptyRects);
}
public void DoGridSlicing(Vector2 size, Vector2 offset, Vector2 padding, int alignment, Vector2 pivot, AutoSlicingMethod slicingMethod, bool keepEmptyRects = false)
{
var frames = GetGridRects(size, offset, padding, keepEmptyRects);
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Grid Slicing");
if (slicingMethod == AutoSlicingMethod.DeleteAll)
m_RectsCache.Clear();
int index = 0;
int originalCount = m_RectsCache.spriteRects.Count;
foreach (Rect frame in frames)
AddSprite(frame, alignment, pivot, slicingMethod, originalCount, ref index);
selected = null;
spriteEditor.SetDataModified();
Repaint();
}
public IEnumerable<Rect> GetIsometricRects(Vector2 size, Vector2 offset, bool isAlternate, bool keepEmptyRects)
{
var textureToUse = GetTextureToSlice();
var gradient = (size.x / 2) / (size.y / 2);
bool isAlt = isAlternate;
float x = offset.x;
if (isAlt)
x += size.x / 2;
float y = textureToUse.height - offset.y;
while (y - size.y >= 0)
{
while (x + size.x <= textureToUse.width)
{
var rect = new Rect(x, y - size.y, size.x, size.y);
if (!keepEmptyRects)
{
int sx = (int)rect.x;
int sy = (int)rect.y;
int width = (int)size.x;
int odd = ((int)size.y) % 2;
int topY = ((int)size.y / 2) - 1;
int bottomY = topY + odd;
int totalPixels = 0;
int alphaPixels = 0;
{
for (int ry = 0; ry <= topY; ry++)
{
var pixelOffset = Mathf.CeilToInt(gradient * ry);
for (int rx = pixelOffset; rx < width - pixelOffset; ++rx)
{
if (PixelHasAlpha(sx + rx, sy + topY - ry, textureToUse))
alphaPixels++;
if (PixelHasAlpha(sx + rx, sy + bottomY + ry, textureToUse))
alphaPixels++;
totalPixels += 2;
}
}
}
if (odd > 0)
{
int ry = topY + 1;
for (int rx = 0; rx < size.x; ++rx)
{
if (PixelHasAlpha(sx + rx, sy + ry, textureToUse))
alphaPixels++;
totalPixels++;
}
}
if (totalPixels > 0 && ((float)alphaPixels) / totalPixels > 0.01f)
yield return rect;
}
else
yield return rect;
x += size.x;
}
isAlt = !isAlt;
x = offset.x;
if (isAlt)
x += size.x / 2;
y -= size.y / 2;
}
}
public void DoIsometricGridSlicing(Vector2 size, Vector2 offset, int alignment, Vector2 pivot, AutoSlicingMethod slicingMethod, bool keepEmptyRects = false, bool isAlternate = false)
{
var frames = GetIsometricRects(size, offset, isAlternate, keepEmptyRects);
List<Vector2[]> outlines = new List<Vector2[]>(4);
outlines.Add(new[] { new Vector2(0.0f, -size.y / 2)
, new Vector2(size.x / 2, 0.0f)
, new Vector2(0.0f, size.y / 2)
, new Vector2(-size.x / 2, 0.0f)});
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Isometric Grid Slicing");
if (slicingMethod == AutoSlicingMethod.DeleteAll)
m_RectsCache.Clear();
int index = 0;
var spriteRects = m_RectsCache.GetSpriteRects();
int originalCount = spriteRects.Count;
foreach (var frame in frames)
{
var spriteIndex = AddSprite(frame, alignment, pivot, slicingMethod, originalCount, ref index);
var outlineRect = new OutlineSpriteRect(spriteRects[spriteIndex]);
outlineRect.outlines = outlines;
spriteRects[spriteIndex] = outlineRect;
}
selected = null;
spriteEditor.SetDataModified();
Repaint();
}
public void ScaleSpriteRect(Rect r)
{
if (selected != null)
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Scale sprite");
selected.rect = ClampSpriteRect(r, textureActualWidth, textureActualHeight);
selected.border = ClampSpriteBorderToRect(selected.border, selected.rect);
spriteEditor.SetDataModified();
}
}
public void TrimAlpha()
{
var texture = GetTextureToSlice();
if (texture == null)
return;
Rect rect = selected.rect;
int xMin = (int)rect.xMax;
int xMax = (int)rect.xMin;
int yMin = (int)rect.yMax;
int yMax = (int)rect.yMin;
for (int y = (int)rect.yMin; y < (int)rect.yMax; y++)
{
for (int x = (int)rect.xMin; x < (int)rect.xMax; x++)
{
if (PixelHasAlpha(x, y, texture))
{
xMin = Mathf.Min(xMin, x);
xMax = Mathf.Max(xMax, x);
yMin = Mathf.Min(yMin, y);
yMax = Mathf.Max(yMax, y);
}
}
}
// Case 582309: Return an empty rectangle if no pixel has an alpha
if (xMin > xMax || yMin > yMax)
rect = new Rect(0, 0, 0, 0);
else
rect = new Rect(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
if (rect.width <= 0 && rect.height <= 0)
{
m_RectsCache.Remove(selected);
spriteEditor.SetDataModified();
selected = null;
}
else
{
rect = ClampSpriteRect(rect, texture.width, texture.height);
if (selected.rect != rect)
spriteEditor.SetDataModified();
selected.rect = rect;
PopulateSpriteFrameInspectorField();
}
}
public void DuplicateSprite()
{
if (selected != null)
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Duplicate sprite");
var index = 0;
var createdIndex = -1;
while (createdIndex == -1)
{
createdIndex = AddSprite(selected.rect, (int)selected.alignment, selected.pivot, GenerateSpriteNameWithIndex(index++), selected.border);
}
selected = m_RectsCache.spriteRects[createdIndex];
}
}
public void CreateSprite(Rect rect)
{
rect = ClampSpriteRect(rect, textureActualWidth, textureActualHeight);
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Create sprite");
var index = 0;
var createdIndex = -1;
while (createdIndex == -1)
{
createdIndex = AddSprite(rect, 0, Vector2.zero, GenerateSpriteNameWithIndex(index++), Vector4.zero);
}
selected = m_RectsCache.spriteRects[createdIndex];
}
public void DeleteSprite()
{
if (selected != null)
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Delete sprite");
m_RectsCache.Remove(selected);
selected = null;
spriteEditor.SetDataModified();
}
}
}
}

View File

@@ -0,0 +1,524 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
using UnityEditorInternal;
namespace UnityEditor.U2D.Sprites
{
internal class SpriteRectModel : ScriptableObject, ISerializationCallbackReceiver
{
[SerializeField]
private List<SpriteRect> m_SpriteRects;
private HashSet<string> m_Names;
private HashSet<long> m_InternalIds;
private IReadOnlyList<SpriteRect> m_SpriteReadOnlyList;
public IReadOnlyList<SpriteRect> spriteRects
{
get { return m_SpriteReadOnlyList; }
}
private SpriteRectModel()
{
m_Names = new HashSet<string>();
m_InternalIds = new HashSet<long>();
}
public void SetSpriteRects(List<SpriteRect> newSpriteRects)
{
m_SpriteRects = newSpriteRects;
foreach (var spriteRect in m_SpriteRects)
{
m_Names.Add(spriteRect.name);
m_InternalIds.Add(spriteRect.internalID);
}
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
}
public int FindIndex(Predicate<SpriteRect> match)
{
int i = 0;
foreach (var spriteRect in m_SpriteRects)
{
if (match.Invoke(spriteRect))
return i;
i++;
}
return -1;
}
public void Clear()
{
m_SpriteRects = new List<SpriteRect>();
m_InternalIds.Clear();
m_Names.Clear();
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
}
public bool Add(SpriteRect spriteRect)
{
if (m_Names.Contains(spriteRect.name))
return false;
if (spriteRect.internalID != 0 && m_InternalIds.Contains(spriteRect.internalID))
return false;
m_Names.Add(spriteRect.name);
if (spriteRect.internalID != 0)
m_InternalIds.Add(spriteRect.internalID);
m_SpriteRects.Add(spriteRect);
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
return true;
}
public void Remove(SpriteRect spriteRect)
{
m_Names.Remove(spriteRect.name);
if (spriteRect.internalID != 0)
m_InternalIds.Remove(spriteRect.internalID);
m_SpriteRects.Remove(spriteRect);
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
}
public bool HasName(string rectName)
{
return m_Names.Contains(rectName);
}
public bool HasInternalID(long internalID)
{
return m_InternalIds.Contains(internalID);
}
public List<SpriteRect> GetSpriteRects()
{
return m_SpriteRects;
}
public void Rename(string oldName, string newName)
{
m_Names.Remove(oldName);
m_Names.Add(newName);
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
m_SpriteReadOnlyList = m_SpriteRects.AsReadOnly();
m_Names.Clear();
m_InternalIds.Clear();
foreach (var sprite in m_SpriteReadOnlyList)
{
m_Names.Add(sprite.name);
m_InternalIds.Add(sprite.internalID);
}
}
}
internal class OutlineSpriteRect : SpriteRect
{
public List<Vector2[]> outlines;
public OutlineSpriteRect(SpriteRect rect)
{
this.name = rect.name;
this.originalName = rect.originalName;
this.pivot = rect.pivot;
this.alignment = rect.alignment;
this.border = rect.border;
this.rect = rect.rect;
this.spriteID = rect.spriteID;
this.internalID = rect.internalID;
outlines = new List<Vector2[]>();
}
}
internal abstract partial class SpriteFrameModuleBase : SpriteEditorModuleBase
{
protected static UnityType spriteType = UnityType.FindTypeByName("Sprite");
protected SpriteRectModel m_RectsCache;
protected ITextureDataProvider m_TextureDataProvider;
protected ISpriteEditorDataProvider m_SpriteDataProvider;
string m_ModuleName;
internal enum PivotUnitMode
{
Normalized,
Pixels
}
private PivotUnitMode m_PivotUnitMode = PivotUnitMode.Normalized;
protected SpriteFrameModuleBase(string name, ISpriteEditor sw, IEventSystem es, IUndoSystem us, IAssetDatabase ad)
{
spriteEditor = sw;
eventSystem = es;
undoSystem = us;
assetDatabase = ad;
m_ModuleName = name;
}
// implements ISpriteEditorModule
public override void OnModuleActivate()
{
spriteImportMode = SpriteFrameModule.GetSpriteImportMode(spriteEditor.GetDataProvider<ISpriteEditorDataProvider>());
m_TextureDataProvider = spriteEditor.GetDataProvider<ITextureDataProvider>();
m_SpriteDataProvider = spriteEditor.GetDataProvider<ISpriteEditorDataProvider>();
int width, height;
m_TextureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
textureActualWidth = width;
textureActualHeight = height;
m_RectsCache = ScriptableObject.CreateInstance<SpriteRectModel>();
m_RectsCache.hideFlags = HideFlags.HideAndDontSave;
var spriteList = m_SpriteDataProvider.GetSpriteRects().ToList();
m_RectsCache.SetSpriteRects(spriteList);
spriteEditor.spriteRects = spriteList;
if (spriteEditor.selectedSpriteRect != null)
spriteEditor.selectedSpriteRect = m_RectsCache.spriteRects.FirstOrDefault(x => x.spriteID == spriteEditor.selectedSpriteRect.spriteID);
AddMainUI(spriteEditor.GetMainVisualContainer());
undoSystem.RegisterUndoCallback(UndoCallback);
}
public override void OnModuleDeactivate()
{
if (m_RectsCache != null)
{
undoSystem.ClearUndo(m_RectsCache);
ScriptableObject.DestroyImmediate(m_RectsCache);
m_RectsCache = null;
}
undoSystem.UnregisterUndoCallback(UndoCallback);
RemoveMainUI(spriteEditor.GetMainVisualContainer());
}
public override bool ApplyRevert(bool apply)
{
if (apply)
{
if (containsMultipleSprites)
{
var oldNames = new List<string>();
var newNames = new List<string>();
var ids = new List<long>();
var names = new List<string>();
foreach (var spriteRect in m_RectsCache.spriteRects)
{
if (string.IsNullOrEmpty(spriteRect.name))
spriteRect.name = "Empty";
if (!string.IsNullOrEmpty(spriteRect.originalName))
{
oldNames.Add(spriteRect.originalName);
newNames.Add(spriteRect.name);
}
if (spriteRect.m_RegisterInternalID)
{
ids.Add(spriteRect.internalID);
names.Add(spriteRect.name);
}
spriteRect.m_RegisterInternalID = false;
}
var so = new SerializedObject(m_SpriteDataProvider.targetObject);
if (so.isValid && ids.Count > 0)
{
ImportSettingInternalID.RegisterInternalID(so, spriteType, ids, names);
so.ApplyModifiedPropertiesWithoutUndo();
}
AssetImporter assetImporter = m_SpriteDataProvider.targetObject as AssetImporter;
if (oldNames.Count > 0 && assetImporter != null)
{
assetImporter.RenameSubAssets(spriteType.persistentTypeID, oldNames.ToArray(), newNames.ToArray());
so.ApplyModifiedPropertiesWithoutUndo();
}
}
var array = m_RectsCache != null ? m_RectsCache.spriteRects.ToArray() : null;
m_SpriteDataProvider.SetSpriteRects(array);
var outlineDataProvider = m_SpriteDataProvider.GetDataProvider<ISpriteOutlineDataProvider>();
var physicsDataProvider = m_SpriteDataProvider.GetDataProvider<ISpritePhysicsOutlineDataProvider>();
foreach (var rect in array)
{
if (rect is OutlineSpriteRect outlineRect)
{
if (outlineRect.outlines.Count > 0)
{
outlineDataProvider.SetOutlines(outlineRect.spriteID, outlineRect.outlines);
physicsDataProvider.SetOutlines(outlineRect.spriteID, outlineRect.outlines);
}
}
}
if (m_RectsCache != null)
undoSystem.ClearUndo(m_RectsCache);
}
else
{
if (m_RectsCache != null)
{
undoSystem.ClearUndo(m_RectsCache);
var spriteList = m_SpriteDataProvider.GetSpriteRects().ToList();
m_RectsCache.SetSpriteRects(spriteList);
spriteEditor.spriteRects = spriteList;
if (spriteEditor.selectedSpriteRect != null)
spriteEditor.selectedSpriteRect = m_RectsCache.spriteRects.FirstOrDefault(x => x.spriteID == spriteEditor.selectedSpriteRect.spriteID);
}
}
return true;
}
public override string moduleName
{
get { return m_ModuleName; }
}
// injected interfaces
protected IEventSystem eventSystem
{
get;
private set;
}
protected IUndoSystem undoSystem
{
get;
private set;
}
protected IAssetDatabase assetDatabase
{
get;
private set;
}
protected SpriteRect selected
{
get { return spriteEditor.selectedSpriteRect; }
set { spriteEditor.selectedSpriteRect = value; }
}
protected SpriteImportMode spriteImportMode
{
get; private set;
}
protected string spriteAssetPath
{
get { return assetDatabase.GetAssetPath(m_TextureDataProvider.texture); }
}
public bool hasSelected
{
get { return spriteEditor.selectedSpriteRect != null; }
}
public SpriteAlignment selectedSpriteAlignment
{
get { return selected.alignment; }
}
public Vector2 selectedSpritePivot
{
get { return selected.pivot; }
}
private Vector2 selectedSpritePivotInCurUnitMode
{
get
{
return m_PivotUnitMode == PivotUnitMode.Pixels
? ConvertFromNormalizedToRectSpace(selectedSpritePivot, selectedSpriteRect)
: selectedSpritePivot;
}
}
public int CurrentSelectedSpriteIndex()
{
if (m_RectsCache != null && selected != null)
return m_RectsCache.FindIndex(x => x.spriteID == selected.spriteID);
return -1;
}
public Vector4 selectedSpriteBorder
{
get { return ClampSpriteBorderToRect(selected.border, selected.rect); }
set
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Change Sprite Border");
spriteEditor.SetDataModified();
selected.border = ClampSpriteBorderToRect(value, selected.rect);
}
}
public Rect selectedSpriteRect
{
get { return selected.rect; }
set
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Change Sprite rect");
spriteEditor.SetDataModified();
selected.rect = ClampSpriteRect(value, textureActualWidth, textureActualHeight);
}
}
public string selectedSpriteName
{
get { return selected.name; }
set
{
if (selected.name == value)
return;
if (m_RectsCache.HasName(value))
return;
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Change Sprite Name");
spriteEditor.SetDataModified();
string oldName = selected.name;
string newName = InternalEditorUtility.RemoveInvalidCharsFromFileName(value, true);
// These can only be changed in sprite multiple mode
if (string.IsNullOrEmpty(selected.originalName) && (newName != oldName))
selected.originalName = oldName;
// Is the name empty?
if (string.IsNullOrEmpty(newName))
newName = oldName;
m_RectsCache.Rename(oldName, newName);
selected.name = newName;
}
}
public int spriteCount
{
get { return m_RectsCache.spriteRects.Count; }
}
public Vector4 GetSpriteBorderAt(int i)
{
return m_RectsCache.spriteRects[i].border;
}
public Rect GetSpriteRectAt(int i)
{
return m_RectsCache.spriteRects[i].rect;
}
public int textureActualWidth { get; private set; }
public int textureActualHeight { get; private set; }
public void SetSpritePivotAndAlignment(Vector2 pivot, SpriteAlignment alignment)
{
undoSystem.RegisterCompleteObjectUndo(m_RectsCache, "Change Sprite Pivot");
spriteEditor.SetDataModified();
selected.alignment = alignment;
selected.pivot = SpriteEditorUtility.GetPivotValue(alignment, pivot);
}
public bool containsMultipleSprites
{
get { return spriteImportMode == SpriteImportMode.Multiple; }
}
protected void SnapPivotToSnapPoints(Vector2 pivot, out Vector2 outPivot, out SpriteAlignment outAlignment)
{
Rect rect = selectedSpriteRect;
// Convert from normalized space to texture space
Vector2 texturePos = new Vector2(rect.xMin + rect.width * pivot.x, rect.yMin + rect.height * pivot.y);
Vector2[] snapPoints = GetSnapPointsArray(rect);
// Snapping is now a firm action, it will always snap to one of the snapping points.
SpriteAlignment snappedAlignment = SpriteAlignment.Custom;
float nearestDistance = float.MaxValue;
for (int alignment = 0; alignment < snapPoints.Length; alignment++)
{
float distance = (texturePos - snapPoints[alignment]).magnitude * m_Zoom;
if (distance < nearestDistance)
{
snappedAlignment = (SpriteAlignment)alignment;
nearestDistance = distance;
}
}
outAlignment = snappedAlignment;
outPivot = ConvertFromTextureToNormalizedSpace(snapPoints[(int)snappedAlignment], rect);
}
protected void SnapPivotToPixels(Vector2 pivot, out Vector2 outPivot, out SpriteAlignment outAlignment)
{
outAlignment = SpriteAlignment.Custom;
Rect rect = selectedSpriteRect;
float unitsPerPixelX = 1.0f / rect.width;
float unitsPerPixelY = 1.0f / rect.height;
outPivot.x = Mathf.Round(pivot.x / unitsPerPixelX) * unitsPerPixelX;
outPivot.y = Mathf.Round(pivot.y / unitsPerPixelY) * unitsPerPixelY;
}
private void UndoCallback()
{
UIUndoCallback();
}
protected static Rect ClampSpriteRect(Rect rect, float maxX, float maxY)
{
// Clamp rect to width height
rect = FlipNegativeRect(rect);
Rect newRect = new Rect();
newRect.xMin = Mathf.Clamp(rect.xMin, 0, maxX - 1);
newRect.yMin = Mathf.Clamp(rect.yMin, 0, maxY - 1);
newRect.xMax = Mathf.Clamp(rect.xMax, 1, maxX);
newRect.yMax = Mathf.Clamp(rect.yMax, 1, maxY);
// Prevent width and height to be 0 value after clamping.
if (Mathf.RoundToInt(newRect.width) == 0)
newRect.width = 1;
if (Mathf.RoundToInt(newRect.height) == 0)
newRect.height = 1;
return SpriteEditorUtility.RoundedRect(newRect);
}
protected static Rect FlipNegativeRect(Rect rect)
{
Rect newRect = new Rect();
newRect.xMin = Mathf.Min(rect.xMin, rect.xMax);
newRect.yMin = Mathf.Min(rect.yMin, rect.yMax);
newRect.xMax = Mathf.Max(rect.xMin, rect.xMax);
newRect.yMax = Mathf.Max(rect.yMin, rect.yMax);
return newRect;
}
protected static Vector4 ClampSpriteBorderToRect(Vector4 border, Rect rect)
{
Rect flipRect = FlipNegativeRect(rect);
float w = flipRect.width;
float h = flipRect.height;
Vector4 newBorder = new Vector4();
// Make sure borders are within the width/height and left < right and top < bottom
newBorder.x = Mathf.RoundToInt(Mathf.Clamp(border.x, 0, Mathf.Min(Mathf.Abs(w - border.z), w))); // Left
newBorder.z = Mathf.RoundToInt(Mathf.Clamp(border.z, 0, Mathf.Min(Mathf.Abs(w - newBorder.x), w))); // Right
newBorder.y = Mathf.RoundToInt(Mathf.Clamp(border.y, 0, Mathf.Min(Mathf.Abs(h - border.w), h))); // Bottom
newBorder.w = Mathf.RoundToInt(Mathf.Clamp(border.w, 0, Mathf.Min(Mathf.Abs(h - newBorder.y), h))); // Top
return newBorder;
}
}
}

View File

@@ -0,0 +1,744 @@
using System;
using System.Collections.Generic;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UnityEngine;
namespace UnityEditor.U2D.Sprites
{
internal abstract partial class SpriteFrameModuleBase : SpriteEditorModuleBase
{
protected enum GizmoMode
{
BorderEditing,
RectEditing
}
protected class Styles
{
public readonly GUIStyle dragdot = "U2D.dragDot";
public readonly GUIStyle dragdotactive = "U2D.dragDotActive";
public readonly GUIStyle createRect = "U2D.createRect";
public readonly GUIStyle pivotdotactive = "U2D.pivotDotActive";
public readonly GUIStyle pivotdot = "U2D.pivotDot";
public readonly GUIStyle dragBorderdot = new GUIStyle();
public readonly GUIStyle dragBorderDotActive = new GUIStyle();
public readonly GUIStyle toolbar;
public Styles()
{
toolbar = new GUIStyle(EditorStyles.inspectorBig);
toolbar.margin.top = 0;
toolbar.margin.bottom = 0;
createRect.border = new RectOffset(3, 3, 3, 3);
dragBorderdot.fixedHeight = 5f;
dragBorderdot.fixedWidth = 5f;
dragBorderdot.normal.background = EditorGUIUtility.whiteTexture;
dragBorderDotActive.fixedHeight = dragBorderdot.fixedHeight;
dragBorderDotActive.fixedWidth = dragBorderdot.fixedWidth;
dragBorderDotActive.normal.background = EditorGUIUtility.whiteTexture;
}
}
private static Styles s_Styles;
protected static Styles styles
{
get
{
if (s_Styles == null)
s_Styles = new Styles();
return s_Styles;
}
}
private const float kInspectorWidth = 330f;
private const float kInspectorHeight = 170;
private const float kPivotFieldPrecision = 0.0001f;
private float m_Zoom = 1.0f;
private GizmoMode m_GizmoMode;
private VisualElement m_NameElement;
private TextField m_NameField;
private VisualElement m_PositionElement;
private IntegerField m_PositionFieldX;
private IntegerField m_PositionFieldY;
private IntegerField m_PositionFieldW;
private IntegerField m_PositionFieldH;
private IntegerField m_BorderFieldL;
private IntegerField m_BorderFieldT;
private IntegerField m_BorderFieldR;
private IntegerField m_BorderFieldB;
private EnumField m_PivotField;
private EnumField m_PivotUnitModeField;
private VisualElement m_CustomPivotElement;
private FloatField m_CustomPivotFieldX;
private FloatField m_CustomPivotFieldY;
private VisualElement m_SelectedFrameInspector;
private bool ShouldShowRectScaling()
{
return hasSelected && m_GizmoMode == GizmoMode.RectEditing;
}
private static Rect inspectorRect
{
get
{
return new Rect(
0, 0,
kInspectorWidth,
kInspectorHeight);
}
}
private void RemoveMainUI(VisualElement mainView)
{
if (mainView.Contains(m_SelectedFrameInspector))
mainView.Remove(m_SelectedFrameInspector);
mainView.UnregisterCallback<SpriteSelectionChangeEvent>(SelectionChange);
}
protected void UpdatePositionField(FocusOutEvent evt)
{
if (hasSelected)
{
m_PositionFieldX.SetValueWithoutNotify((int)selectedSpriteRect.x);
m_PositionFieldY.SetValueWithoutNotify((int)selectedSpriteRect.y);
m_PositionFieldW.SetValueWithoutNotify((int)selectedSpriteRect.width);
m_PositionFieldH.SetValueWithoutNotify((int)selectedSpriteRect.height);
}
}
private void UpdateBorderField(FocusOutEvent evt)
{
if (hasSelected)
{
m_BorderFieldL.SetValueWithoutNotify((int)selectedSpriteBorder.x);
m_BorderFieldB.SetValueWithoutNotify((int)selectedSpriteBorder.y);
m_BorderFieldR.SetValueWithoutNotify((int)selectedSpriteBorder.z);
m_BorderFieldT.SetValueWithoutNotify((int)selectedSpriteBorder.w);
}
}
void SetupIntegerField(IntegerField field, EventCallback<FocusOutEvent> onFocusOutEvent, EventCallback<ChangeEvent<int>> onChangeEvent)
{
field.RegisterCallback(onFocusOutEvent);
field.RegisterValueChangedCallback(onChangeEvent);
}
void SetDragFieldLimit(IntegerField field, int value)
{
// The only way to know if value change is due to dragger or text input
var t = field.Q("unity-text-input");
if (!t.focusController.IsFocused(t))
{
// Value changed due to drag. We set back the field so to show the drag limit
field.SetValueWithoutNotify(value);
}
}
void OnPositionIntXChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var rect = selectedSpriteRect;
rect.x = evt.newValue;
selectedSpriteRect = rect;
SetDragFieldLimit(m_PositionFieldX, (int)selectedSpriteRect.x);
m_PositionFieldW.SetValueWithoutNotify((int)selectedSpriteRect.width);
}
}
void OnPositionIntYChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var rect = selectedSpriteRect;
rect.y = evt.newValue;
selectedSpriteRect = rect;
SetDragFieldLimit(m_PositionFieldY, (int)selectedSpriteRect.y);
m_PositionFieldH.SetValueWithoutNotify((int)selectedSpriteRect.height);
}
}
void OnPositionIntWChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var rect = selectedSpriteRect;
rect.width = evt.newValue;
selectedSpriteRect = rect;
SetDragFieldLimit(m_PositionFieldW, (int)selectedSpriteRect.width);
m_PositionFieldX.SetValueWithoutNotify((int)selectedSpriteRect.x);
}
}
void OnPositionIntHChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var rect = selectedSpriteRect;
rect.height = evt.newValue;
selectedSpriteRect = rect;
SetDragFieldLimit(m_PositionFieldH, (int)selectedSpriteRect.height);
m_PositionFieldY.SetValueWithoutNotify((int)selectedSpriteRect.y);
}
}
void OnBorderIntLChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var border = selectedSpriteBorder;
border.x = evt.newValue;
selectedSpriteBorder = border;
SetDragFieldLimit(m_BorderFieldL, (int)selectedSpriteBorder.x);
}
}
void OnBorderIntBChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var border = selectedSpriteBorder;
border.y = evt.newValue;
selectedSpriteBorder = border;
SetDragFieldLimit(m_BorderFieldB, (int)selectedSpriteBorder.y);
}
}
void OnBorderIntRChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var border = selectedSpriteBorder;
border.z = (evt.newValue + border.x) <= selectedSpriteRect.width ? evt.newValue : selectedSpriteRect.width - border.x;
selectedSpriteBorder = border;
SetDragFieldLimit(m_BorderFieldR, (int)selectedSpriteBorder.z);
}
}
void OnBorderIntTChange(ChangeEvent<int> evt)
{
if (hasSelected)
{
var border = selectedSpriteBorder;
border.w = (evt.newValue + border.y) <= selectedSpriteRect.height ? evt.newValue : selectedSpriteRect.height - border.y;
selectedSpriteBorder = border;
SetDragFieldLimit(m_BorderFieldT, (int)selectedSpriteBorder.w);
}
}
private void AddMainUI(VisualElement mainView)
{
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Packages/com.unity.2d.sprite/Editor/UI/SpriteEditor/SpriteFrameModuleInspector.uxml") as VisualTreeAsset;
m_SelectedFrameInspector = visualTree.CloneTree().Q("spriteFrameModuleInspector");
m_NameElement = m_SelectedFrameInspector.Q("name");
m_NameField = m_SelectedFrameInspector.Q<TextField>("spriteName");
m_NameField.RegisterValueChangedCallback((evt) =>
{
if (hasSelected)
{
selectedSpriteName = evt.newValue;
}
});
m_NameField.RegisterCallback<FocusOutEvent>((focus) =>
{
if (hasSelected)
{
m_NameField.SetValueWithoutNotify(selectedSpriteName);
}
});
m_PositionElement = m_SelectedFrameInspector.Q("position");
m_PositionFieldX = m_PositionElement.Q<IntegerField>("positionX");
SetupIntegerField(m_PositionFieldX, UpdatePositionField, OnPositionIntXChange);
m_PositionFieldY = m_PositionElement.Q<IntegerField>("positionY");
SetupIntegerField(m_PositionFieldY, UpdatePositionField, OnPositionIntYChange);
m_PositionFieldW = m_PositionElement.Q<IntegerField>("positionW");
SetupIntegerField(m_PositionFieldW, UpdatePositionField, OnPositionIntWChange);
m_PositionFieldH = m_PositionElement.Q<IntegerField>("positionH");
SetupIntegerField(m_PositionFieldH, UpdatePositionField, OnPositionIntHChange);
var borderElement = m_SelectedFrameInspector.Q("border");
m_BorderFieldL = borderElement.Q<IntegerField>("borderL");
SetupIntegerField(m_BorderFieldL, UpdateBorderField, OnBorderIntLChange);
m_BorderFieldT = borderElement.Q<IntegerField>("borderT");
SetupIntegerField(m_BorderFieldT, UpdateBorderField, OnBorderIntTChange);
m_BorderFieldR = borderElement.Q<IntegerField>("borderR");
SetupIntegerField(m_BorderFieldR, UpdateBorderField, OnBorderIntRChange);
m_BorderFieldB = borderElement.Q<IntegerField>("borderB");
SetupIntegerField(m_BorderFieldB, UpdateBorderField, OnBorderIntBChange);
m_PivotField = m_SelectedFrameInspector.Q<EnumField>("pivotField");
m_PivotField.Init(SpriteAlignment.Center);
m_PivotField.label = L10n.Tr("Pivot");
m_PivotField.RegisterValueChangedCallback((evt) =>
{
if (hasSelected)
{
SpriteAlignment alignment = (SpriteAlignment)evt.newValue;
SetSpritePivotAndAlignment(selectedSpritePivot, alignment);
m_CustomPivotElement.SetEnabled(selectedSpriteAlignment == SpriteAlignment.Custom);
Vector2 pivot = selectedSpritePivotInCurUnitMode;
m_CustomPivotFieldX.SetValueWithoutNotify(pivot.x);
m_CustomPivotFieldY.SetValueWithoutNotify(pivot.y);
}
});
m_PivotUnitModeField = m_SelectedFrameInspector.Q<EnumField>("pivotUnitModeField");
m_PivotUnitModeField.Init(PivotUnitMode.Normalized);
m_PivotUnitModeField.label = L10n.Tr("Pivot Unit Mode");
m_PivotUnitModeField.RegisterValueChangedCallback((evt) =>
{
if (hasSelected)
{
m_PivotUnitMode = (PivotUnitMode)evt.newValue;
Vector2 pivot = selectedSpritePivotInCurUnitMode;
m_CustomPivotFieldX.SetValueWithoutNotify(pivot.x);
m_CustomPivotFieldY.SetValueWithoutNotify(pivot.y);
}
});
m_CustomPivotElement = m_SelectedFrameInspector.Q("customPivot");
m_CustomPivotFieldX = m_CustomPivotElement.Q<FloatField>("customPivotX");
m_CustomPivotFieldX.RegisterValueChangedCallback((evt) =>
{
if (hasSelected)
{
float newValue = (float)evt.newValue;
float pivotX = m_PivotUnitMode == PivotUnitMode.Pixels
? ConvertFromRectToNormalizedSpace(new Vector2(newValue, 0.0f), selectedSpriteRect).x
: newValue;
var pivot = selectedSpritePivot;
pivot.x = pivotX;
SetSpritePivotAndAlignment(pivot, selectedSpriteAlignment);
}
});
m_CustomPivotFieldY = m_CustomPivotElement.Q<FloatField>("customPivotY");
m_CustomPivotFieldY.RegisterValueChangedCallback((evt) =>
{
if (hasSelected)
{
float newValue = (float)evt.newValue;
float pivotY = m_PivotUnitMode == PivotUnitMode.Pixels
? ConvertFromRectToNormalizedSpace(new Vector2(0.0f, newValue), selectedSpriteRect).y
: newValue;
var pivot = selectedSpritePivot;
pivot.y = pivotY;
SetSpritePivotAndAlignment(pivot, selectedSpriteAlignment);
}
});
//// Force an update of all the fields.
PopulateSpriteFrameInspectorField();
mainView.RegisterCallback<SpriteSelectionChangeEvent>(SelectionChange);
// Stop mouse events from reaching the main view.
m_SelectedFrameInspector.pickingMode = PickingMode.Ignore;
m_SelectedFrameInspector.RegisterCallback<MouseDownEvent>((e) => { e.StopPropagation(); });
m_SelectedFrameInspector.RegisterCallback<MouseUpEvent>((e) => { e.StopPropagation(); });
m_SelectedFrameInspector.AddToClassList("moduleWindow");
m_SelectedFrameInspector.AddToClassList("bottomRightFloating");
mainView.Add(m_SelectedFrameInspector);
}
private void SelectionChange(SpriteSelectionChangeEvent evt)
{
m_SelectedFrameInspector.style.display = hasSelected ? DisplayStyle.Flex : DisplayStyle.None;
PopulateSpriteFrameInspectorField();
}
private void UIUndoCallback()
{
PopulateSpriteFrameInspectorField();
}
protected void PopulateSpriteFrameInspectorField()
{
m_SelectedFrameInspector.style.display = hasSelected ? DisplayStyle.Flex : DisplayStyle.None;
if (!hasSelected)
return;
m_NameElement.SetEnabled(containsMultipleSprites);
m_NameField.SetValueWithoutNotify(selectedSpriteName);
m_PositionElement.SetEnabled(containsMultipleSprites);
var spriteRect = selectedSpriteRect;
m_PositionFieldX.SetValueWithoutNotify(Mathf.RoundToInt(spriteRect.x));
m_PositionFieldY.SetValueWithoutNotify(Mathf.RoundToInt(spriteRect.y));
m_PositionFieldW.SetValueWithoutNotify(Mathf.RoundToInt(spriteRect.width));
m_PositionFieldH.SetValueWithoutNotify(Mathf.RoundToInt(spriteRect.height));
var spriteBorder = selectedSpriteBorder;
m_BorderFieldL.SetValueWithoutNotify(Mathf.RoundToInt(spriteBorder.x));
m_BorderFieldT.SetValueWithoutNotify(Mathf.RoundToInt(spriteBorder.w));
m_BorderFieldR.SetValueWithoutNotify(Mathf.RoundToInt(spriteBorder.z));
m_BorderFieldB.SetValueWithoutNotify(Mathf.RoundToInt(spriteBorder.y));
m_PivotField.SetValueWithoutNotify(selectedSpriteAlignment);
m_PivotUnitModeField.SetValueWithoutNotify(m_PivotUnitMode);
Vector2 pivot = selectedSpritePivotInCurUnitMode;
m_CustomPivotFieldX.SetValueWithoutNotify(pivot.x);
m_CustomPivotFieldY.SetValueWithoutNotify(pivot.y);
m_CustomPivotElement.SetEnabled(hasSelected && selectedSpriteAlignment == SpriteAlignment.Custom);
}
private static Vector2 ApplySpriteAlignmentToPivot(Vector2 pivot, Rect rect, SpriteAlignment alignment)
{
if (alignment != SpriteAlignment.Custom)
{
Vector2[] snapPoints = GetSnapPointsArray(rect);
Vector2 texturePos = snapPoints[(int)alignment];
return ConvertFromTextureToNormalizedSpace(texturePos, rect);
}
return pivot;
}
private static Vector2 ConvertFromTextureToNormalizedSpace(Vector2 texturePos, Rect rect)
{
return new Vector2((texturePos.x - rect.xMin) / rect.width, (texturePos.y - rect.yMin) / rect.height);
}
private static Vector2 ConvertFromNormalizedToRectSpace(Vector2 normalizedPos, Rect rect)
{
Vector2 rectPos = new Vector2(rect.width * normalizedPos.x, rect.height * normalizedPos.y);
// This is to combat the lack of precision formating on the UI controls.
rectPos.x = Mathf.Round(rectPos.x / kPivotFieldPrecision) * kPivotFieldPrecision;
rectPos.y = Mathf.Round(rectPos.y / kPivotFieldPrecision) * kPivotFieldPrecision;
return rectPos;
}
private static Vector2 ConvertFromRectToNormalizedSpace(Vector2 rectPos, Rect rect)
{
return new Vector2(rectPos.x / rect.width, rectPos.y / rect.height);
}
private static Vector2[] GetSnapPointsArray(Rect rect)
{
Vector2[] snapPoints = new Vector2[9];
snapPoints[(int)SpriteAlignment.TopLeft] = new Vector2(rect.xMin, rect.yMax);
snapPoints[(int)SpriteAlignment.TopCenter] = new Vector2(rect.center.x, rect.yMax);
snapPoints[(int)SpriteAlignment.TopRight] = new Vector2(rect.xMax, rect.yMax);
snapPoints[(int)SpriteAlignment.LeftCenter] = new Vector2(rect.xMin, rect.center.y);
snapPoints[(int)SpriteAlignment.Center] = new Vector2(rect.center.x, rect.center.y);
snapPoints[(int)SpriteAlignment.RightCenter] = new Vector2(rect.xMax, rect.center.y);
snapPoints[(int)SpriteAlignment.BottomLeft] = new Vector2(rect.xMin, rect.yMin);
snapPoints[(int)SpriteAlignment.BottomCenter] = new Vector2(rect.center.x, rect.yMin);
snapPoints[(int)SpriteAlignment.BottomRight] = new Vector2(rect.xMax, rect.yMin);
return snapPoints;
}
protected void Repaint()
{
spriteEditor.RequestRepaint();
}
protected void HandleGizmoMode()
{
GizmoMode oldGizmoMode = m_GizmoMode;
var evt = eventSystem.current;
if (evt.control)
m_GizmoMode = GizmoMode.BorderEditing;
else
m_GizmoMode = GizmoMode.RectEditing;
if (oldGizmoMode != m_GizmoMode && (evt.type == EventType.KeyDown || evt.type == EventType.KeyUp) && (evt.keyCode == KeyCode.LeftControl || evt.keyCode == KeyCode.RightControl || evt.keyCode == KeyCode.LeftAlt || evt.keyCode == KeyCode.RightAlt))
Repaint();
}
protected bool MouseOnTopOfInspector()
{
if (hasSelected == false)
return false;
var point = GUIClip.Unclip(eventSystem.current.mousePosition);
point = m_SelectedFrameInspector.parent.LocalToWorld(point);
var selectedElement = m_SelectedFrameInspector.panel.Pick(point);
if (selectedElement != null
&& selectedElement.pickingMode != PickingMode.Ignore
&& selectedElement.FindCommonAncestor(m_SelectedFrameInspector) == m_SelectedFrameInspector)
return true;
return false;
}
protected void HandlePivotHandle()
{
if (!hasSelected)
return;
EditorGUI.BeginChangeCheck();
SpriteAlignment alignment = selectedSpriteAlignment;
Vector2 pivot = selectedSpritePivot;
Rect rect = selectedSpriteRect;
pivot = ApplySpriteAlignmentToPivot(pivot, rect, alignment);
Vector2 pivotHandlePosition = SpriteEditorHandles.PivotSlider(rect, pivot, styles.pivotdot, styles.pivotdotactive);
if (EditorGUI.EndChangeCheck())
{
// Pivot snapping only happen when ctrl is press. Same as scene view snapping move
if (eventSystem.current.control)
SnapPivotToSnapPoints(pivotHandlePosition, out pivot, out alignment);
else if (m_PivotUnitMode == PivotUnitMode.Pixels)
SnapPivotToPixels(pivotHandlePosition, out pivot, out alignment);
else
{
pivot = pivotHandlePosition;
alignment = SpriteAlignment.Custom;
}
SetSpritePivotAndAlignment(pivot, alignment);
PopulateSpriteFrameInspectorField();
}
}
protected void HandleBorderSidePointScalingSliders()
{
if (!hasSelected)
return;
GUIStyle dragDot = styles.dragBorderdot;
GUIStyle dragDotActive = styles.dragBorderDotActive;
var color = new Color(0f, 1f, 0f);
Rect rect = selectedSpriteRect;
Vector4 border = selectedSpriteBorder;
float left = rect.xMin + border.x;
float right = rect.xMax - border.z;
float top = rect.yMax - border.w;
float bottom = rect.yMin + border.y;
EditorGUI.BeginChangeCheck();
float horizontal = bottom - (bottom - top) / 2;
float vertical = left - (left - right) / 2;
float center = horizontal;
HandleBorderPointSlider(ref left, ref center, MouseCursor.ResizeHorizontal, false, dragDot, dragDotActive, color);
center = horizontal;
HandleBorderPointSlider(ref right, ref center, MouseCursor.ResizeHorizontal, false, dragDot, dragDotActive, color);
center = vertical;
HandleBorderPointSlider(ref center, ref top, MouseCursor.ResizeVertical, false, dragDot, dragDotActive, color);
center = vertical;
HandleBorderPointSlider(ref center, ref bottom, MouseCursor.ResizeVertical, false, dragDot, dragDotActive, color);
if (EditorGUI.EndChangeCheck())
{
border.x = left - rect.xMin;
border.z = rect.xMax - right;
border.w = rect.yMax - top;
border.y = bottom - rect.yMin;
selectedSpriteBorder = border;
PopulateSpriteFrameInspectorField();
}
}
protected void HandleBorderCornerScalingHandles()
{
if (!hasSelected)
return;
GUIStyle dragDot = styles.dragBorderdot;
GUIStyle dragDotActive = styles.dragBorderDotActive;
var color = new Color(0f, 1f, 0f);
Rect rect = selectedSpriteRect;
Vector4 border = selectedSpriteBorder;
float left = rect.xMin + border.x;
float right = rect.xMax - border.z;
float top = rect.yMax - border.w;
float bottom = rect.yMin + border.y;
EditorGUI.BeginChangeCheck();
// Handle corner points, but hide them if border values are below 1
HandleBorderPointSlider(ref left, ref top, MouseCursor.ResizeUpLeft, border.x < 1 && border.w < 1, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref right, ref top, MouseCursor.ResizeUpRight, border.z < 1 && border.w < 1, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref left, ref bottom, MouseCursor.ResizeUpRight, border.x < 1 && border.y < 1, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref right, ref bottom, MouseCursor.ResizeUpLeft, border.z < 1 && border.y < 1, dragDot, dragDotActive, color);
if (EditorGUI.EndChangeCheck())
{
border.x = left - rect.xMin;
border.z = rect.xMax - right;
border.w = rect.yMax - top;
border.y = bottom - rect.yMin;
selectedSpriteBorder = border;
PopulateSpriteFrameInspectorField();
}
}
protected void HandleBorderSideScalingHandles()
{
if (hasSelected == false)
return;
Rect rect = new Rect(selectedSpriteRect);
Vector4 border = selectedSpriteBorder;
float left = rect.xMin + border.x;
float right = rect.xMax - border.z;
float top = rect.yMax - border.w;
float bottom = rect.yMin + border.y;
Vector2 screenRectTopLeft = Handles.matrix.MultiplyPoint(new Vector3(rect.xMin, rect.yMin));
Vector2 screenRectBottomRight = Handles.matrix.MultiplyPoint(new Vector3(rect.xMax, rect.yMax));
float screenRectWidth = Mathf.Abs(screenRectBottomRight.x - screenRectTopLeft.x);
float screenRectHeight = Mathf.Abs(screenRectBottomRight.y - screenRectTopLeft.y);
EditorGUI.BeginChangeCheck();
left = HandleBorderScaleSlider(left, rect.yMax, screenRectWidth, screenRectHeight, true);
right = HandleBorderScaleSlider(right, rect.yMax, screenRectWidth, screenRectHeight, true);
top = HandleBorderScaleSlider(rect.xMin, top, screenRectWidth, screenRectHeight, false);
bottom = HandleBorderScaleSlider(rect.xMin, bottom, screenRectWidth, screenRectHeight, false);
if (EditorGUI.EndChangeCheck())
{
border.x = left - rect.xMin;
border.z = rect.xMax - right;
border.w = rect.yMax - top;
border.y = bottom - rect.yMin;
selectedSpriteBorder = border;
PopulateSpriteFrameInspectorField();
}
}
protected void HandleBorderPointSlider(ref float x, ref float y, MouseCursor mouseCursor, bool isHidden, GUIStyle dragDot, GUIStyle dragDotActive, Color color)
{
var originalColor = GUI.color;
if (isHidden)
GUI.color = new Color(0, 0, 0, 0);
else
GUI.color = color;
Vector2 point = SpriteEditorHandles.PointSlider(new Vector2(x, y), mouseCursor, dragDot, dragDotActive);
x = point.x;
y = point.y;
GUI.color = originalColor;
}
protected float HandleBorderScaleSlider(float x, float y, float width, float height, bool isHorizontal)
{
float handleSize = styles.dragBorderdot.fixedWidth;
Vector2 point = Handles.matrix.MultiplyPoint(new Vector2(x, y));
float result;
EditorGUI.BeginChangeCheck();
if (isHorizontal)
{
Rect newRect = new Rect(point.x - handleSize * .5f, point.y, handleSize, height);
result = SpriteEditorHandles.ScaleSlider(point, MouseCursor.ResizeHorizontal, newRect).x;
}
else
{
Rect newRect = new Rect(point.x, point.y - handleSize * .5f, width, handleSize);
result = SpriteEditorHandles.ScaleSlider(point, MouseCursor.ResizeVertical, newRect).y;
}
if (EditorGUI.EndChangeCheck())
return result;
return isHorizontal ? x : y;
}
protected void DrawSpriteRectGizmos()
{
if (eventSystem.current.type != EventType.Repaint)
return;
SpriteEditorUtility.BeginLines(new Color(0f, 1f, 0f, 0.7f));
var selectedGUID = selected != null ? selected.spriteID : new GUID();
for (int i = 0; i < spriteCount; i++)
{
Vector4 border = GetSpriteBorderAt(i);
if (m_GizmoMode != GizmoMode.BorderEditing && (m_RectsCache != null && m_RectsCache.spriteRects[i].spriteID != selectedGUID))
{
// border does not contain negative values
if (border.sqrMagnitude < Mathf.Epsilon * 8)
continue;
}
var rect = GetSpriteRectAt(i);
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin + border.x, rect.yMin), new Vector3(rect.xMin + border.x, rect.yMax));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMax - border.z, rect.yMin), new Vector3(rect.xMax - border.z, rect.yMax));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin, rect.yMin + border.y), new Vector3(rect.xMax, rect.yMin + border.y));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin, rect.yMax - border.w), new Vector3(rect.xMax, rect.yMax - border.w));
}
SpriteEditorUtility.EndLines();
if (ShouldShowRectScaling())
{
Rect r = selectedSpriteRect;
SpriteEditorUtility.BeginLines(new Color(0f, 0.1f, 0.3f, 0.25f));
SpriteEditorUtility.DrawBox(new Rect(r.xMin + 1f / m_Zoom, r.yMin + 1f / m_Zoom, r.width, r.height));
SpriteEditorUtility.EndLines();
SpriteEditorUtility.BeginLines(new Color(0.25f, 0.5f, 1f, 0.75f));
SpriteEditorUtility.DrawBox(r);
SpriteEditorUtility.EndLines();
}
}
protected void DrawRectGizmos(IEnumerable<Rect> rects, Color color)
{
if (eventSystem.current.type != EventType.Repaint)
return;
SpriteEditorUtility.BeginLines(color);
foreach (var rect in rects)
{
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin, rect.yMin), new Vector3(rect.xMin, rect.yMax));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMax, rect.yMin), new Vector3(rect.xMax, rect.yMax));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin, rect.yMin), new Vector3(rect.xMax, rect.yMin));
SpriteEditorUtility.DrawLine(new Vector3(rect.xMin, rect.yMax), new Vector3(rect.xMax, rect.yMax));
}
SpriteEditorUtility.EndLines();
}
// implements ISpriteEditorModule
public override void DoMainGUI()
{
m_Zoom = Handles.matrix.GetColumn(0).magnitude;
}
public override void DoPostGUI()
{
}
}
}

View File

@@ -0,0 +1,220 @@
using UnityEngine;
namespace UnityEditor.U2D.Sprites
{
internal partial class SpriteFrameModule : SpriteFrameModuleBase
{
private static class SpriteFrameModuleStyles
{
public static readonly GUIContent sliceButtonLabel = EditorGUIUtility.TrTextContent("Slice");
public static readonly GUIContent trimButtonLabel = EditorGUIUtility.TrTextContent("Trim", "Trims selected rectangle (T)");
}
// overrides for SpriteFrameModuleBase
public override void DoMainGUI()
{
base.DoMainGUI();
DrawSpriteRectGizmos();
DrawPotentialSpriteRectGizmos();
HandleGizmoMode();
if (containsMultipleSprites)
HandleRectCornerScalingHandles();
HandleBorderCornerScalingHandles();
HandleBorderSidePointScalingSliders();
if (containsMultipleSprites)
HandleRectSideScalingHandles();
HandleBorderSideScalingHandles();
HandlePivotHandle();
if (containsMultipleSprites)
HandleDragging();
spriteEditor.HandleSpriteSelection();
if (containsMultipleSprites)
{
HandleCreate();
HandleDelete();
HandleDuplicate();
}
spriteEditor.spriteRects = m_RectsCache.GetSpriteRects();
}
private void DrawPotentialSpriteRectGizmos()
{
if (m_PotentialRects != null && m_PotentialRects.Count > 0)
DrawRectGizmos(m_PotentialRects, Color.red);
}
public override void DoToolbarGUI(Rect toolbarRect)
{
using (new EditorGUI.DisabledScope(!containsMultipleSprites || spriteEditor.editingDisabled || m_TextureDataProvider.GetReadableTexture2D() == null))
{
GUIStyle skin = EditorStyles.toolbarPopup;
Rect drawArea = toolbarRect;
drawArea.width = skin.CalcSize(SpriteFrameModuleStyles.sliceButtonLabel).x;
SpriteUtilityWindow.DrawToolBarWidget(ref drawArea, ref toolbarRect, (adjustedDrawArea) =>
{
if (GUI.Button(adjustedDrawArea, SpriteFrameModuleStyles.sliceButtonLabel, skin))
{
if (SpriteEditorMenu.ShowAtPosition(adjustedDrawArea, this, m_TextureDataProvider))
GUIUtility.ExitGUI();
}
});
using (new EditorGUI.DisabledScope(!hasSelected))
{
drawArea.x += drawArea.width;
drawArea.width = skin.CalcSize(SpriteFrameModuleStyles.trimButtonLabel).x;
SpriteUtilityWindow.DrawToolBarWidget(ref drawArea, ref toolbarRect, (adjustedDrawArea) =>
{
if (GUI.Button(adjustedDrawArea, SpriteFrameModuleStyles.trimButtonLabel, EditorStyles.toolbarButton))
{
TrimAlpha();
Repaint();
}
});
}
}
}
private void HandleRectCornerScalingHandles()
{
if (!hasSelected)
return;
GUIStyle dragDot = styles.dragdot;
GUIStyle dragDotActive = styles.dragdotactive;
var color = Color.white;
Rect rect = new Rect(selectedSpriteRect);
float left = rect.xMin;
float right = rect.xMax;
float top = rect.yMax;
float bottom = rect.yMin;
EditorGUI.BeginChangeCheck();
HandleBorderPointSlider(ref left, ref top, MouseCursor.ResizeUpLeft, false, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref right, ref top, MouseCursor.ResizeUpRight, false, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref left, ref bottom, MouseCursor.ResizeUpRight, false, dragDot, dragDotActive, color);
HandleBorderPointSlider(ref right, ref bottom, MouseCursor.ResizeUpLeft, false, dragDot, dragDotActive, color);
if (EditorGUI.EndChangeCheck())
{
rect.xMin = left;
rect.xMax = right;
rect.yMax = top;
rect.yMin = bottom;
ScaleSpriteRect(rect);
PopulateSpriteFrameInspectorField();
}
}
private void HandleRectSideScalingHandles()
{
if (!hasSelected)
return;
Rect rect = new Rect(selectedSpriteRect);
float left = rect.xMin;
float right = rect.xMax;
float top = rect.yMax;
float bottom = rect.yMin;
Vector2 screenRectTopLeft = Handles.matrix.MultiplyPoint(new Vector3(rect.xMin, rect.yMin));
Vector2 screenRectBottomRight = Handles.matrix.MultiplyPoint(new Vector3(rect.xMax, rect.yMax));
float screenRectWidth = Mathf.Abs(screenRectBottomRight.x - screenRectTopLeft.x);
float screenRectHeight = Mathf.Abs(screenRectBottomRight.y - screenRectTopLeft.y);
EditorGUI.BeginChangeCheck();
left = HandleBorderScaleSlider(left, rect.yMax, screenRectWidth, screenRectHeight, true);
right = HandleBorderScaleSlider(right, rect.yMax, screenRectWidth, screenRectHeight, true);
top = HandleBorderScaleSlider(rect.xMin, top, screenRectWidth, screenRectHeight, false);
bottom = HandleBorderScaleSlider(rect.xMin, bottom, screenRectWidth, screenRectHeight, false);
if (EditorGUI.EndChangeCheck())
{
rect.xMin = left;
rect.xMax = right;
rect.yMax = top;
rect.yMin = bottom;
ScaleSpriteRect(rect);
PopulateSpriteFrameInspectorField();
}
}
private void HandleDragging()
{
if (hasSelected && !MouseOnTopOfInspector())
{
Rect textureBounds = new Rect(0, 0, textureActualWidth, textureActualHeight);
EditorGUI.BeginChangeCheck();
Rect oldRect = selectedSpriteRect;
Rect newRect = SpriteEditorUtility.ClampedRect(SpriteEditorUtility.RoundedRect(SpriteEditorHandles.SliderRect(oldRect)), textureBounds, true);
if (EditorGUI.EndChangeCheck())
{
selectedSpriteRect = newRect;
UpdatePositionField(null);
}
}
}
private void HandleCreate()
{
if (!MouseOnTopOfInspector() && !eventSystem.current.alt)
{
// Create new rects via dragging in empty space
EditorGUI.BeginChangeCheck();
Rect newRect = SpriteEditorHandles.RectCreator(textureActualWidth, textureActualHeight, styles.createRect);
if (EditorGUI.EndChangeCheck() && newRect.width > 0f && newRect.height > 0f)
{
CreateSprite(newRect);
GUIUtility.keyboardControl = 0;
}
}
}
private void HandleDuplicate()
{
IEvent evt = eventSystem.current;
if ((evt.type == EventType.ValidateCommand || evt.type == EventType.ExecuteCommand)
&& evt.commandName == EventCommandNames.Duplicate)
{
if (evt.type == EventType.ExecuteCommand)
DuplicateSprite();
evt.Use();
}
}
private void HandleDelete()
{
IEvent evt = eventSystem.current;
if ((evt.type == EventType.ValidateCommand || evt.type == EventType.ExecuteCommand)
&& (evt.commandName == EventCommandNames.SoftDelete || evt.commandName == EventCommandNames.Delete))
{
if (evt.type == EventType.ExecuteCommand && hasSelected)
DeleteSprite();
evt.Use();
}
}
}
}

View File

@@ -0,0 +1,109 @@
using UnityEngine;
using System.Collections.Generic;
namespace UnityEditor.U2D.Sprites
{
[RequireSpriteDataProvider(typeof(ISpriteOutlineDataProvider), typeof(ITextureDataProvider))]
internal partial class SpritePolygonModeModule : SpriteFrameModuleBase
{
List<List<Vector2[]>> m_Outline;
public SpritePolygonModeModule(ISpriteEditor sw, IEventSystem es, IUndoSystem us, IAssetDatabase ad) :
base("Sprite Polygon Mode Editor", sw, es, us, ad)
{}
// ISpriteEditorModule implemenation
public override void OnModuleActivate()
{
base.OnModuleActivate();
AddMainUI(spriteEditor.GetMainVisualContainer());
m_Outline = new List<List<Vector2[]>>();
for (int i = 0; i < m_RectsCache.spriteRects.Count; ++i)
{
var rect = m_RectsCache.spriteRects[i];
m_Outline.Add(spriteEditor.GetDataProvider<ISpriteOutlineDataProvider>().GetOutlines(rect.spriteID));
}
showChangeShapeWindow = polygonSprite;
if (polygonSprite)
DeterminePolygonSides();
}
public override bool CanBeActivated()
{
return SpriteFrameModule.GetSpriteImportMode(spriteEditor.GetDataProvider<ISpriteEditorDataProvider>()) == SpriteImportMode.Polygon;
}
private bool polygonSprite
{
get { return spriteImportMode == SpriteImportMode.Polygon; }
}
private void DeterminePolygonSides()
{
if (polygonSprite && m_RectsCache.spriteRects.Count == 1 && m_Outline.Count == 1 && m_Outline[0].Count == 1)
{
polygonSides = m_Outline[0][0].Length;
}
else
// If for reasons we cannot determine the sides of the polygon, fall back to 0 (Square)
polygonSides = 0;
ViewUpdateSideCountField();
}
public int GetPolygonSideCount()
{
DeterminePolygonSides();
return polygonSides;
}
public int polygonSides
{
get;
set;
}
public List<Vector2[]> GetSpriteOutlineAt(int i)
{
return m_Outline[i];
}
public void GeneratePolygonOutline()
{
for (int i = 0; i < m_RectsCache.spriteRects.Count; i++)
{
SpriteRect currentRect = m_RectsCache.spriteRects[i];
var result = UnityEditor.Sprites.SpriteUtility.GeneratePolygonOutlineVerticesOfSize(polygonSides, (int)currentRect.rect.width, (int)currentRect.rect.height);
m_Outline.Clear();
var newOutlineList = new List<Vector2[]>();
newOutlineList.Add(result);
m_Outline.Add(newOutlineList);
spriteEditor.SetDataModified();
}
Repaint();
}
public override bool ApplyRevert(bool apply)
{
var outlineProvider = spriteEditor.GetDataProvider<ISpriteOutlineDataProvider>();
if (apply)
{
for (int i = 0; i < m_RectsCache.spriteRects.Count && i < m_Outline.Count; ++i)
outlineProvider.SetOutlines(m_RectsCache.spriteRects[i].spriteID, m_Outline[i]);
}
else
{
m_Outline.Clear();
for (int i = 0; i < m_RectsCache.spriteRects.Count; ++i)
m_Outline.Add(outlineProvider.GetOutlines(m_RectsCache.spriteRects[i].spriteID));
DeterminePolygonSides();
ViewUpdateSideCountField();
}
return base.ApplyRevert(apply);
}
}
}

View File

@@ -0,0 +1,141 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UIElementButton = UnityEngine.UIElements.Button;
namespace UnityEditor.U2D.Sprites
{
internal partial class SpritePolygonModeModule : SpriteFrameModuleBase
{
private static class SpritePolygonModeStyles
{
public static readonly GUIContent changeShapeLabel = EditorGUIUtility.TrTextContent("Change Shape");
}
private VisualElement m_PolygonShapeView;
private UIElementButton m_ChangeButton;
private VisualElement m_WarningMessage;
// overrides for SpriteFrameModuleViewBase
private void AddMainUI(VisualElement element)
{
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Packages/com.unity.2d.sprite/Editor/UI/SpriteEditor/PolygonChangeShapeWindow.uxml") as VisualTreeAsset;
m_PolygonShapeView = visualTree.CloneTree().Q<VisualElement>("polygonShapeWindow");
m_PolygonShapeView.RegisterCallback<MouseDownEvent>((e) => { e.StopPropagation(); });
m_PolygonShapeView.RegisterCallback<MouseUpEvent>((e) => { e.StopPropagation(); });
SetupPolygonChangeShapeWindowElements(m_PolygonShapeView);
element.Add(m_PolygonShapeView);
}
public override void DoMainGUI()
{
base.DoMainGUI();
DrawGizmos();
HandleGizmoMode();
HandleBorderCornerScalingHandles();
HandleBorderSidePointScalingSliders();
HandleBorderSideScalingHandles();
HandlePivotHandle();
if (!MouseOnTopOfInspector())
spriteEditor.HandleSpriteSelection();
}
public override void DoToolbarGUI(Rect toolbarRect)
{
using (new EditorGUI.DisabledScope(spriteEditor.editingDisabled))
{
GUIStyle skin = EditorStyles.toolbarPopup;
Rect drawArea = toolbarRect;
drawArea.width = skin.CalcSize(SpritePolygonModeStyles.changeShapeLabel).x;
SpriteUtilityWindow.DrawToolBarWidget(ref drawArea, ref toolbarRect, (adjustedDrawArea) =>
{
showChangeShapeWindow = GUI.Toggle(adjustedDrawArea, showChangeShapeWindow, SpritePolygonModeStyles.changeShapeLabel, EditorStyles.toolbarButton);
});
}
}
private void DrawGizmos()
{
if (eventSystem.current.type != EventType.Repaint)
return;
for (int i = 0; i < spriteCount; i++)
{
List<Vector2[]> outline = GetSpriteOutlineAt(i);
Vector2 offset = GetSpriteRectAt(i).size * 0.5f;
if (outline.Count > 0)
{
SpriteEditorUtility.BeginLines(new Color(0.75f, 0.75f, 0.75f, 0.75f));
for (int j = 0; j < outline.Count; ++j)
{
for (int k = 0, last = outline[j].Length - 1; k < outline[j].Length; last = k, ++k)
SpriteEditorUtility.DrawLine(outline[j][last] + offset, outline[j][k] + offset);
}
SpriteEditorUtility.EndLines();
}
}
DrawSpriteRectGizmos();
}
private void ViewUpdateSideCountField()
{
var sidesField = m_PolygonShapeView.Q<IntegerField>("labelIntegerField");
sidesField.value = polygonSides;
}
private void SetupPolygonChangeShapeWindowElements(VisualElement moduleView)
{
var sidesField = moduleView.Q<IntegerField>("labelIntegerField");
sidesField.SetValueWithoutNotify(polygonSides);
sidesField.RegisterValueChangedCallback((evt) =>
{
polygonSides = (int)evt.newValue;
ShowHideWarningMessage();
});
m_ChangeButton = moduleView.Q<UIElementButton>("changeButton");
m_ChangeButton.RegisterCallback<MouseUpEvent>((e) =>
{
if (isSidesValid)
{
GeneratePolygonOutline();
showChangeShapeWindow = false;
}
});
m_WarningMessage = moduleView.Q("warning");
ShowHideWarningMessage();
}
void ShowHideWarningMessage()
{
m_WarningMessage.style.display = !isSidesValid ? DisplayStyle.Flex : DisplayStyle.None;
m_WarningMessage.style.position = m_WarningMessage.style.display == DisplayStyle.Flex ? Position.Relative : Position.Absolute;
m_ChangeButton.style.display = isSidesValid ? DisplayStyle.Flex : DisplayStyle.None;;
m_ChangeButton.style.position = m_ChangeButton.style.display == DisplayStyle.Flex ? Position.Relative : Position.Absolute;
}
private bool isSidesValid
{
get
{
return polygonSides == 0 || (polygonSides >= 3 && polygonSides <= 128);
}
}
public bool showChangeShapeWindow
{
get { return m_PolygonShapeView.style.display == DisplayStyle.Flex; }
set
{
var displayValue = value ? DisplayStyle.Flex : DisplayStyle.None;
if (m_PolygonShapeView.style.display == displayValue)
return;
m_PolygonShapeView.style.display = displayValue;
}
}
}
}