Rasagar/Library/PackageCache/com.unity.2d.sprite/Editor/SpriteEditor/SpriteUtilityWindow.cs
2024-08-26 23:07:20 +03:00

426 lines
17 KiB
C#

using System;
using UnityEngine;
using UnityEvent = UnityEngine.Event;
namespace UnityEditor.U2D.Sprites
{
internal class SpriteUtilityWindow : EditorWindow
{
protected class Styles
{
public readonly GUIStyle dragdot = "U2D.dragDot";
public readonly GUIStyle dragdotDimmed = "U2D.dragDotDimmed";
public readonly GUIStyle dragdotactive = "U2D.dragDotActive";
public readonly GUIStyle createRect = "U2D.createRect";
public readonly GUIStyle preToolbar = "preToolbar";
public readonly GUIStyle preButton = "preButton";
public readonly GUIStyle preLabel = "preLabel";
public readonly GUIStyle preSlider = "preSlider";
public readonly GUIStyle preSliderThumb = "preSliderThumb";
public readonly GUIStyle preBackground = "preBackground";
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 readonly GUIContent alphaIcon;
public readonly GUIContent RGBIcon;
public readonly GUIStyle notice;
public readonly GUIContent smallMip;
public readonly GUIContent largeMip;
public Styles()
{
toolbar = new GUIStyle(EditorStyles.inspectorBig);
toolbar.margin.top = 0;
toolbar.margin.bottom = 0;
alphaIcon = EditorGUIUtility.IconContent("PreTextureAlpha");
RGBIcon = EditorGUIUtility.IconContent("PreTextureRGB");
preToolbar.border.top = 0;
createRect.border = new RectOffset(3, 3, 3, 3);
notice = new GUIStyle(GUI.skin.label);
notice.alignment = TextAnchor.MiddleCenter;
notice.normal.textColor = Color.yellow;
dragBorderdot.fixedHeight = 5f;
dragBorderdot.fixedWidth = 5f;
dragBorderdot.normal.background = EditorGUIUtility.whiteTexture;
dragBorderDotActive.fixedHeight = dragBorderdot.fixedHeight;
dragBorderDotActive.fixedWidth = dragBorderdot.fixedWidth;
dragBorderDotActive.normal.background = EditorGUIUtility.whiteTexture;
smallMip = EditorGUIUtility.IconContent("PreTextureMipMapLow");
largeMip = EditorGUIUtility.IconContent("PreTextureMipMapHigh");
}
}
protected void InitStyles()
{
if (m_Styles == null)
m_Styles = new Styles();
}
protected Styles m_Styles;
protected const float k_BorderMargin = 10f;
protected const float k_ScrollbarMargin = 16f;
protected const float k_InspectorWindowMargin = 8f;
protected const float k_InspectorWidth = 330f;
protected const float k_MinZoomPercentage = 0.9f;
protected const float k_MaxZoom = 50f;
protected const float k_WheelZoomSpeed = 0.03f;
protected const float k_MouseZoomSpeed = 0.005f;
protected const float k_ToolbarHeight = 17f;
protected ITexture2D m_Texture;
protected ITexture2D m_TextureAlphaOverride;
Rect m_TextureViewRect;
protected Rect m_TextureRect;
[SerializeField]
protected bool m_ShowAlpha = false;
[SerializeField]
protected float m_MipLevel = 0;
[SerializeField]
protected float m_Zoom = -1f;
[SerializeField]
protected Vector2 m_ScrollPosition = new Vector2();
public float zoomLevel
{
get { return m_Zoom; }
set { m_Zoom = Mathf.Clamp(value, GetMinZoom(), k_MaxZoom); }
}
internal Rect textureViewRect
{
get => m_TextureViewRect;
set
{
m_TextureViewRect = value;
zoomLevel = m_Zoom; // update zoom level
}
}
public Vector2 scrollPosition
{
get { return m_ScrollPosition; }
set
{
if (m_Zoom < 0)
m_Zoom = GetMinZoom();
m_ScrollPosition.x = Mathf.Clamp(value.x, maxScrollRect.xMin, maxScrollRect.xMax);
m_ScrollPosition.y = Mathf.Clamp(value.y, maxScrollRect.yMin, maxScrollRect.yMax);
}
}
public bool showAlpha
{
get { return m_ShowAlpha; }
set { m_ShowAlpha = value; }
}
public float mipLevel
{
get { return m_MipLevel; }
set
{
var mipCount = 1;
if (m_Texture != null)
mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture));
m_MipLevel = Mathf.Clamp(value, 0, mipCount - 1);
}
}
protected float GetMinZoom()
{
if (m_Texture == null)
return 1.0f;
// Case 654327: Add k_MaxZoom size to min check to ensure that min zoom is smaller than max zoom
return Mathf.Min(m_TextureViewRect.width / m_Texture.width, m_TextureViewRect.height / m_Texture.height, k_MaxZoom) * k_MinZoomPercentage;
}
protected void HandleZoom()
{
bool zoomMode = UnityEvent.current.alt && UnityEvent.current.button == 1;
if (zoomMode)
{
EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Zoom);
}
if (
((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && zoomMode) ||
((UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt)
)
{
Repaint();
}
if (UnityEvent.current.type == EventType.ScrollWheel || (UnityEvent.current.type == EventType.MouseDrag && UnityEvent.current.alt && UnityEvent.current.button == 1))
{
float zoomMultiplier = 1f - UnityEvent.current.delta.y * (UnityEvent.current.type == EventType.ScrollWheel ? k_WheelZoomSpeed : -k_MouseZoomSpeed);
// Clamp zoom
float wantedZoom = m_Zoom * zoomMultiplier;
float currentZoom = Mathf.Clamp(wantedZoom, GetMinZoom(), k_MaxZoom);
if (currentZoom != m_Zoom)
{
m_Zoom = currentZoom;
// We need to fix zoomMultiplier if we clamped wantedZoom != currentZoom
if (wantedZoom != currentZoom)
zoomMultiplier /= wantedZoom / currentZoom;
Vector3 textureHalfSize = new Vector2(m_Texture.width, m_Texture.height) * 0.5f;
Vector3 mousePositionWorld = Handles.inverseMatrix.MultiplyPoint3x4(UnityEvent.current.mousePosition + m_ScrollPosition);
Vector3 delta = (mousePositionWorld - textureHalfSize) * (zoomMultiplier - 1f);
m_ScrollPosition += (Vector2)Handles.matrix.MultiplyVector(delta);
UnityEvent.current.Use();
}
}
}
protected void HandlePanning()
{
// You can pan by holding ALT and using left button or NOT holding ALT and using right button. ALT + right is reserved for zooming.
bool panMode = (!UnityEvent.current.alt && UnityEvent.current.button > 0 || UnityEvent.current.alt && UnityEvent.current.button <= 0);
if (panMode && GUIUtility.hotControl == 0)
{
EditorGUIUtility.AddCursorRect(m_TextureViewRect, MouseCursor.Pan);
if (UnityEvent.current.type == EventType.MouseDrag)
{
m_ScrollPosition -= UnityEvent.current.delta;
UnityEvent.current.Use();
}
}
//We need to repaint when entering or exiting the pan mode, so the mouse cursor gets refreshed.
if (
((UnityEvent.current.type == EventType.MouseUp || UnityEvent.current.type == EventType.MouseDown) && panMode) ||
(UnityEvent.current.type == EventType.KeyUp || UnityEvent.current.type == EventType.KeyDown) && UnityEvent.current.keyCode == KeyCode.LeftAlt
)
{
Repaint();
}
}
// Bounding values for scrollbars. Changes with zoom, because we want min/max scroll to stop at texture edges.
protected Rect maxScrollRect
{
get
{
float halfWidth = m_Texture.width * .5f * m_Zoom;
float halfHeight = m_Texture.height * .5f * m_Zoom;
return new Rect(-halfWidth, -halfHeight, m_TextureViewRect.width + halfWidth * 2f, m_TextureViewRect.height + halfHeight * 2f);
}
}
// Max rect in texture space that can ever be visible
protected Rect maxRect
{
get
{
float marginW = m_TextureViewRect.width * .5f / GetMinZoom();
float marginH = m_TextureViewRect.height * .5f / GetMinZoom();
float left = -marginW;
float top = -marginH;
float width = m_Texture.width + marginW * 2f;
float height = m_Texture.height + marginH * 2f;
return new Rect(left, top, width, height);
}
}
protected void DrawTexturespaceBackground()
{
float size = Mathf.Max(maxRect.width, maxRect.height);
Vector2 offset = new Vector2(maxRect.xMin, maxRect.yMin);
float halfSize = size * .5f;
float alpha = EditorGUIUtility.isProSkin ? 0.15f : 0.08f;
float gridSize = 8f;
SpriteEditorUtility.BeginLines(new Color(0f, 0f, 0f, alpha));
for (float v = 0; v <= size; v += gridSize)
SpriteEditorUtility.DrawLine(new Vector2(-halfSize + v, halfSize + v) + offset, new Vector2(halfSize + v, -halfSize + v) + offset);
SpriteEditorUtility.EndLines();
}
private float Log2(float x)
{
return (float)(System.Math.Log(x) / System.Math.Log(2));
}
protected void DrawTexture()
{
float mipLevel = Mathf.Min(m_MipLevel, TextureUtil.GetMipmapCount(m_Texture) - 1);
if (m_ShowAlpha)
{
// check if we have a valid alpha texture
if (m_TextureAlphaOverride != null)
EditorGUI.DrawTextureTransparent(m_TextureRect, m_TextureAlphaOverride, ScaleMode.StretchToFill, 0, mipLevel);
// else use the original texture and display its alpha
else
EditorGUI.DrawTextureAlpha(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel);
}
else
EditorGUI.DrawTextureTransparent(m_TextureRect, m_Texture, ScaleMode.StretchToFill, 0, mipLevel);
}
protected void DrawScreenspaceBackground()
{
if (UnityEvent.current.type == EventType.Repaint)
m_Styles.preBackground.Draw(m_TextureViewRect, false, false, false, false);
}
protected void HandleScrollbars()
{
Rect horizontalScrollBarPosition = new Rect(m_TextureViewRect.xMin, m_TextureViewRect.yMax, m_TextureViewRect.width, k_ScrollbarMargin);
m_ScrollPosition.x = GUI.HorizontalScrollbar(horizontalScrollBarPosition, m_ScrollPosition.x, m_TextureViewRect.width, maxScrollRect.xMin, maxScrollRect.xMax);
Rect verticalScrollBarPosition = new Rect(m_TextureViewRect.xMax, m_TextureViewRect.yMin, k_ScrollbarMargin, m_TextureViewRect.height);
m_ScrollPosition.y = GUI.VerticalScrollbar(verticalScrollBarPosition, m_ScrollPosition.y, m_TextureViewRect.height, maxScrollRect.yMin, maxScrollRect.yMax);
}
protected void SetupHandlesMatrix()
{
// Offset from top left to center in view space
Vector3 handlesPos = new Vector3(m_TextureRect.x, m_TextureRect.yMax, 0f);
// We flip Y-scale because Unity texture space is bottom-up
Vector3 handlesScale = new Vector3(zoomLevel, -zoomLevel, 1f);
// Handle matrix is for converting between view and texture space coordinates, without taking account the scroll position.
// Scroll position is added separately so we can use it with GUIClip.
Handles.matrix = Matrix4x4.TRS(handlesPos, Quaternion.identity, handlesScale);
}
protected Rect DoAlphaZoomToolbarGUI(Rect area)
{
int mipCount = 1;
if (m_Texture != null)
mipCount = Mathf.Max(mipCount, TextureUtil.GetMipmapCount(m_Texture));
Rect drawArea = new Rect(area.width, 0, 0, area.height);
using (new EditorGUI.DisabledScope(mipCount == 1))
{
drawArea.width = m_Styles.largeMip.image.width;
drawArea.x -= drawArea.width;
GUI.Box(drawArea, m_Styles.largeMip, m_Styles.preLabel);
drawArea.width = EditorGUI.kSliderMinW;
drawArea.x -= drawArea.width;
m_MipLevel = Mathf.Round(GUI.HorizontalSlider(drawArea, m_MipLevel, mipCount - 1, 0, m_Styles.preSlider, m_Styles.preSliderThumb));
drawArea.width = m_Styles.smallMip.image.width;
drawArea.x -= drawArea.width;
GUI.Box(drawArea, m_Styles.smallMip, m_Styles.preLabel);
}
drawArea.width = EditorGUI.kSliderMinW;
drawArea.x -= drawArea.width;
zoomLevel = GUI.HorizontalSlider(drawArea, zoomLevel, GetMinZoom(), k_MaxZoom, m_Styles.preSlider, m_Styles.preSliderThumb);
drawArea.width = EditorGUI.kObjectFieldMiniThumbnailWidth;
drawArea.x -= drawArea.width + EditorGUI.kSpacing;
m_ShowAlpha = GUI.Toggle(drawArea, m_ShowAlpha, m_ShowAlpha ? m_Styles.alphaIcon : m_Styles.RGBIcon, "toolbarButton");
// Returns the area that is not used
return new Rect(area.x, area.y, drawArea.x, area.height);
}
protected void DoTextureGUI()
{
if (m_Texture == null)
return;
// zoom startup init
if (m_Zoom < 0f)
m_Zoom = GetMinZoom();
// Texture rect in view space
m_TextureRect = new Rect(
m_TextureViewRect.width / 2f - (m_Texture.width * m_Zoom / 2f),
m_TextureViewRect.height / 2f - (m_Texture.height * m_Zoom / 2f),
(m_Texture.width * m_Zoom),
(m_Texture.height * m_Zoom)
);
HandleScrollbars();
SetupHandlesMatrix();
DrawScreenspaceBackground();
GUIClip.Push(m_TextureViewRect, -m_ScrollPosition, Vector2.zero, false);
if (UnityEvent.current.type == EventType.Repaint)
{
DrawTexturespaceBackground();
DrawTexture();
DrawGizmos();
}
DoTextureGUIExtras();
GUIClip.Pop();
// Handle this after DoTextureGUIExtras in case user wants any event that is handled by Zoom or Panning
HandleZoom();
HandlePanning();
}
protected virtual void DoTextureGUIExtras()
{
}
protected virtual void DrawGizmos()
{
}
protected void SetNewTexture(Texture2D texture)
{
if (texture != m_Texture)
{
m_Texture = new Texture2DWrapper(texture);
m_Zoom = -1;
m_TextureAlphaOverride = null;
}
}
protected void SetAlphaTextureOverride(Texture2D alphaTexture)
{
if (alphaTexture != m_TextureAlphaOverride)
{
m_TextureAlphaOverride = new Texture2DWrapper(alphaTexture);
m_Zoom = -1;
}
}
internal override void OnResized()
{
if (m_Texture != null && UnityEvent.current != null)
HandleZoom();
base.OnResized();
}
internal static void DrawToolBarWidget(ref Rect drawRect, ref Rect toolbarRect, Action<Rect> drawAction)
{
toolbarRect.width -= drawRect.width;
if (toolbarRect.width < 0)
drawRect.width += toolbarRect.width;
if (drawRect.width > 0)
drawAction(drawRect);
}
} // class
}