using System.Globalization;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace AppUI.Editor
{
///
/// 设计稿尺寸与 Canvas Reference Resolution 之间的换算工具窗口。
///
public class DesignResolutionConverterWindow : EditorWindow
{
private const string PrefDesignW = "AppUI.DesignResolutionConverter.DesignW";
private const string PrefDesignH = "AppUI.DesignResolutionConverter.DesignH";
private const string PrefCanvasW = "AppUI.DesignResolutionConverter.CanvasW";
private const string PrefCanvasH = "AppUI.DesignResolutionConverter.CanvasH";
private Vector2 _designArtboard = new Vector2(DesignResolutionConverter.DefaultDesignWidth, DesignResolutionConverter.DefaultDesignHeight);
private Vector2 _canvasReference = new Vector2(DesignResolutionConverter.DefaultDesignWidth, DesignResolutionConverter.DefaultDesignHeight);
private Vector2 _sampleDesignSize = new Vector2(100f, 40f);
private Vector2 _sampleCanvasSize = new Vector2(100f, 40f);
private const string PrefScalarValue = "AppUI.DesignResolutionConverter.ScalarValue";
private const string PrefScalarDir = "AppUI.DesignResolutionConverter.ScalarDir";
private const string PrefScalarAxis = "AppUI.DesignResolutionConverter.ScalarAxis";
private float _scalarInput = 100f;
private int _scalarDirection; // 0: 设计稿→Canvas, 1: Canvas→设计稿
private int _scalarAxis; // 0: 宽度轴 scaleX, 1: 高度轴 scaleY
private Vector2 _scroll;
[MenuItem("Tools/AppUI/设计稿与 Canvas 分辨率换算")]
public static void Open()
{
var win = GetWindow();
win.titleContent = new GUIContent("设计稿 ↔ Canvas 换算");
win.minSize = new Vector2(380f, 420f);
}
private void OnEnable()
{
_designArtboard.x = EditorPrefs.GetFloat(PrefDesignW, DesignResolutionConverter.DefaultDesignWidth);
_designArtboard.y = EditorPrefs.GetFloat(PrefDesignH, DesignResolutionConverter.DefaultDesignHeight);
_canvasReference.x = EditorPrefs.GetFloat(PrefCanvasW, DesignResolutionConverter.DefaultDesignWidth);
_canvasReference.y = EditorPrefs.GetFloat(PrefCanvasH, DesignResolutionConverter.DefaultDesignHeight);
_scalarInput = EditorPrefs.GetFloat(PrefScalarValue, 100f);
_scalarDirection = EditorPrefs.GetInt(PrefScalarDir, 0);
_scalarAxis = EditorPrefs.GetInt(PrefScalarAxis, 0);
}
private void SavePrefs()
{
EditorPrefs.SetFloat(PrefDesignW, _designArtboard.x);
EditorPrefs.SetFloat(PrefDesignH, _designArtboard.y);
EditorPrefs.SetFloat(PrefCanvasW, _canvasReference.x);
EditorPrefs.SetFloat(PrefCanvasH, _canvasReference.y);
}
private void OnGUI()
{
_scroll = EditorGUILayout.BeginScrollView(_scroll);
EditorGUILayout.LabelField("基准尺寸", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
"设计稿宽高:你在 Figma / Sketch 等中的画板像素尺寸(默认 402×874)。\n" +
"Canvas 参考分辨率:当前场景 CanvasScaler 的 Reference Resolution。",
MessageType.Info);
EditorGUI.BeginChangeCheck();
_designArtboard = EditorGUILayout.Vector2Field("设计稿宽高 (px)", _designArtboard);
_canvasReference = EditorGUILayout.Vector2Field("Canvas Reference Resolution", _canvasReference);
if (EditorGUI.EndChangeCheck())
SavePrefs();
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("从选中对象读取 CanvasScaler"))
PullFromSelection();
if (GUILayout.Button("将设计稿尺寸填到 Canvas(与左栏相同)"))
{
_canvasReference = _designArtboard;
SavePrefs();
}
EditorGUILayout.EndHorizontal();
bool valid = _designArtboard.x > 0f && _designArtboard.y > 0f && _canvasReference.x > 0f && _canvasReference.y > 0f;
if (!valid)
EditorGUILayout.HelpBox("设计稿与 Canvas 的宽高均需大于 0。", MessageType.Warning);
Vector2 scale = valid
? DesignResolutionConverter.GetScaleFactors(_designArtboard, _canvasReference)
: Vector2.one;
EditorGUILayout.Space(6f);
EditorGUILayout.LabelField("轴向缩放系数", EditorStyles.boldLabel);
if (valid)
{
EditorGUILayout.LabelField($"scaleX = {_canvasReference.x:F4} / {_designArtboard.x:F4} = {scale.x:F6}");
EditorGUILayout.LabelField($"scaleY = {_canvasReference.y:F4} / {_designArtboard.y:F4} = {scale.y:F6}");
}
EditorGUILayout.Space(10f);
EditorGUILayout.LabelField("单值换算", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("输入一个数,按所选轴向换算;结果可复制到剪贴板(Inspector / 代码中粘贴)。", MessageType.None);
EditorGUI.BeginChangeCheck();
_scalarDirection = GUILayout.Toolbar(_scalarDirection, new[] { "设计稿 → Canvas", "Canvas → 设计稿" });
_scalarAxis = GUILayout.Toolbar(_scalarAxis, new[] { "按宽度轴 (scaleX)", "按高度轴 (scaleY)" });
_scalarInput = EditorGUILayout.FloatField(_scalarDirection == 0 ? "输入值 (设计稿 px)" : "输入值 (Canvas 单位)", _scalarInput);
if (EditorGUI.EndChangeCheck())
{
EditorPrefs.SetFloat(PrefScalarValue, _scalarInput);
EditorPrefs.SetInt(PrefScalarDir, _scalarDirection);
EditorPrefs.SetInt(PrefScalarAxis, _scalarAxis);
}
if (valid)
{
bool useWidthAxis = _scalarAxis == 0;
float scalarResult = _scalarDirection == 0
? DesignResolutionConverter.DesignLengthToCanvas(_scalarInput, useWidthAxis, _designArtboard, _canvasReference)
: DesignResolutionConverter.CanvasLengthToDesign(_scalarInput, useWidthAxis, _designArtboard, _canvasReference);
string resultLabel = _scalarDirection == 0 ? "Canvas 单位" : "设计稿 px";
EditorGUILayout.LabelField($"换算结果 ({resultLabel})", EditorStyles.boldLabel);
string resultText = scalarResult.ToString("G9", CultureInfo.InvariantCulture);
EditorGUILayout.SelectableLabel(resultText, GUILayout.Height(18f));
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("复制结果"))
{
EditorGUIUtility.systemCopyBuffer = resultText;
ShowNotification(new GUIContent("已复制到剪贴板"));
}
if (GUILayout.Button("复制(保留 4 位小数)"))
{
string rounded = scalarResult.ToString("F4", CultureInfo.InvariantCulture);
EditorGUIUtility.systemCopyBuffer = rounded;
ShowNotification(new GUIContent("已复制(F4)"));
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space(10f);
EditorGUILayout.LabelField("尺寸换算", EditorStyles.boldLabel);
_sampleDesignSize = EditorGUILayout.Vector2Field("设计稿上的宽×高 (px)", _sampleDesignSize);
if (valid)
{
Vector2 toCanvas = DesignResolutionConverter.DesignSizeToCanvasUnits(_sampleDesignSize, _designArtboard, _canvasReference);
EditorGUILayout.SelectableLabel($"→ Canvas 单位: ({toCanvas.x:F4}, {toCanvas.y:F4})", GUILayout.Height(18f));
if (GUILayout.Button("将换算结果应用到选中 RectTransform(宽×高)"))
ApplyCanvasSizeToSelection(toCanvas);
}
EditorGUILayout.Space(6f);
_sampleCanvasSize = EditorGUILayout.Vector2Field("Canvas 上的宽×高", _sampleCanvasSize);
if (valid)
{
Vector2 toDesign = DesignResolutionConverter.CanvasUnitsToDesignSize(_sampleCanvasSize, _designArtboard, _canvasReference);
EditorGUILayout.SelectableLabel($"→ 设计稿 px: ({toDesign.x:F4}, {toDesign.y:F4})", GUILayout.Height(18f));
if (GUILayout.Button("将当前 Canvas 宽×高应用到选中 RectTransform"))
ApplyCanvasSizeToSelection(_sampleCanvasSize);
}
EditorGUILayout.Space(10f);
EditorGUILayout.LabelField("文档", EditorStyles.boldLabel);
if (GUILayout.Button("打开说明文档 (AppUI/Docs)"))
{
const string docPath = "Assets/AppUI/Docs/UI设计稿与Canvas分辨率换算.md";
var obj = AssetDatabase.LoadAssetAtPath