139 lines
7.0 KiB
C#
139 lines
7.0 KiB
C#
#if UNITY_EDITOR
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace AIGame.EditorTools
|
|
{
|
|
/// <summary>Common 标准控件的九宫格导入规则,基于 Doc/UI_Normal_Set.md。</summary>
|
|
public static class UiSpriteNineSliceRules
|
|
{
|
|
private const string CommonRoot = "Assets/Bundles/UI/Texture/Common/";
|
|
private const string JournalRoot = "Assets/Bundles/UI/Texture/Journal/";
|
|
private static readonly HashSet<string> JournalControls = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
"journal_card", "journal_hero", "journal_gold_card", "journal_primary_normal", "journal_primary_pressed",
|
|
"journal_secondary_normal", "journal_secondary_pressed", "journal_disabled", "journal_progress_bg", "journal_progress_fill"
|
|
};
|
|
// W,H,L,R,T,B:设计尺寸与边界;实际切图按尺寸换算,并包含 2px 透明留边。
|
|
private static readonly Dictionary<string, int[]> Rules = new Dictionary<string, int[]>(StringComparer.OrdinalIgnoreCase)
|
|
{
|
|
{ "ui_panel_main", new[] { 480, 256, 40, 40, 40, 40 } },
|
|
{ "ui_panel_popup", new[] { 360, 240, 36, 36, 36, 36 } },
|
|
{ "ui_panel_content", new[] { 320, 200, 28, 28, 28, 28 } },
|
|
{ "ui_panel_header", new[] { 400, 80, 32, 32, 24, 24 } },
|
|
{ "btn_primary_normal", new[] { 224, 88, 32, 32, 24, 24 } },
|
|
{ "btn_primary_pressed", new[] { 224, 88, 32, 32, 24, 24 } },
|
|
{ "btn_primary_disabled", new[] { 224, 88, 32, 32, 24, 24 } },
|
|
{ "btn_secondary_normal", new[] { 224, 88, 32, 32, 24, 24 } },
|
|
{ "btn_secondary_pressed", new[] { 224, 88, 32, 32, 24, 24 } },
|
|
{ "btn_small_normal", new[] { 160, 64, 24, 24, 18, 18 } },
|
|
{ "btn_small_pressed", new[] { 160, 64, 24, 24, 18, 18 } },
|
|
{ "scrollbar_track_v", new[] { 28, 160, 8, 8, 16, 16 } },
|
|
{ "scrollbar_thumb_v", new[] { 28, 80, 8, 8, 16, 16 } },
|
|
{ "input_bg_normal", new[] { 360, 72, 28, 28, 20, 20 } },
|
|
{ "input_bg_focus", new[] { 360, 72, 28, 28, 20, 20 } },
|
|
{ "ui_list_item_normal", new[] { 320, 72, 20, 20, 16, 16 } },
|
|
{ "ui_list_item_selected", new[] { 320, 72, 20, 20, 16, 16 } },
|
|
{ "tab_active", new[] { 200, 72, 28, 28, 20, 20 } },
|
|
{ "tab_inactive", new[] { 200, 72, 28, 28, 20, 20 } },
|
|
{ "progress_bg", new[] { 400, 32, 16, 16, 10, 10 } },
|
|
{ "progress_fill", new[] { 400, 32, 16, 16, 10, 10 } },
|
|
{ "slider_track", new[] { 320, 28, 14, 14, 8, 8 } },
|
|
{ "slider_fill", new[] { 320, 28, 14, 14, 8, 8 } },
|
|
{ "toast_bg", new[] { 280, 80, 28, 28, 20, 20 } },
|
|
{ "toggle_bg_off", new[] { 112, 56, 28, 28, 18, 18 } },
|
|
{ "toggle_bg_on", new[] { 112, 56, 28, 28, 18, 18 } }
|
|
};
|
|
|
|
public static bool IsStandardControl(string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path)) return false;
|
|
path = path.Replace('\\', '/');
|
|
if (string.Equals(Path.GetDirectoryName(path)?.Replace('\\', '/'), JournalRoot.TrimEnd('/'), StringComparison.OrdinalIgnoreCase))
|
|
return JournalControls.Contains(Path.GetFileNameWithoutExtension(path));
|
|
return path.StartsWith(CommonRoot, StringComparison.OrdinalIgnoreCase)
|
|
&& string.Equals(Path.GetDirectoryName(path)?.Replace('\\', '/'), CommonRoot.TrimEnd('/'), StringComparison.OrdinalIgnoreCase)
|
|
&& Rules.ContainsKey(Path.GetFileNameWithoutExtension(path));
|
|
}
|
|
|
|
public static Vector4 GetBorder(string path, int width, int height)
|
|
{
|
|
if (JournalControls.Contains(Path.GetFileNameWithoutExtension(path)))
|
|
return new Vector4(30f * width / 128, 32f * height / 128, 30f * width / 128, 28f * height / 128);
|
|
int[] rule = Rules[Path.GetFileNameWithoutExtension(path)];
|
|
float sx = Mathf.Max(1, width - 4) / (float)rule[0];
|
|
float sy = Mathf.Max(1, height - 4) / (float)rule[1];
|
|
// Unity Vector4 顺序为 L,B,R,T,与文档 L,R,T,B 不同。
|
|
float maxX = Mathf.Max(1, (width - 1) / 2);
|
|
float maxY = Mathf.Max(1, (height - 1) / 2);
|
|
return new Vector4(
|
|
Mathf.Clamp(Mathf.Round(rule[2] * sx) + 2, 1, maxX),
|
|
Mathf.Clamp(Mathf.Round(rule[5] * sy) + 2, 1, maxY),
|
|
Mathf.Clamp(Mathf.Round(rule[3] * sx) + 2, 1, maxX),
|
|
Mathf.Clamp(Mathf.Round(rule[4] * sy) + 2, 1, maxY));
|
|
}
|
|
|
|
public static bool Configure(TextureImporter importer)
|
|
{
|
|
if (!IsStandardControl(importer.assetPath)) return false;
|
|
importer.GetSourceTextureWidthAndHeight(out int width, out int height);
|
|
Vector4 border = GetBorder(importer.assetPath, width, height);
|
|
var settings = new TextureImporterSettings();
|
|
importer.ReadTextureSettings(settings);
|
|
bool changed = importer.textureType != TextureImporterType.Sprite
|
|
|| importer.spriteImportMode != SpriteImportMode.Single
|
|
|| settings.spriteMeshType != SpriteMeshType.FullRect
|
|
|| importer.spriteBorder != border;
|
|
if (!changed) return false;
|
|
importer.textureType = TextureImporterType.Sprite;
|
|
importer.spriteImportMode = SpriteImportMode.Single;
|
|
importer.ReadTextureSettings(settings);
|
|
settings.spriteMeshType = SpriteMeshType.FullRect;
|
|
importer.SetTextureSettings(settings);
|
|
importer.spriteBorder = border;
|
|
return true;
|
|
}
|
|
|
|
[MenuItem("Tools/UI/Apply Standard Control Nine-Slice")]
|
|
public static void ApplyFromMenu()
|
|
{
|
|
Debug.Log("[UIGen] 九宫格更新: " + ApplyExisting() + " 张标准控件图。");
|
|
}
|
|
|
|
public static int ApplyExisting()
|
|
{
|
|
if (EditorApplication.isPlayingOrWillChangePlaymode)
|
|
throw new InvalidOperationException("Apply UI sprite borders in Edit Mode.");
|
|
int changed = 0;
|
|
foreach (string name in Rules.Keys)
|
|
{
|
|
string path = CommonRoot + name + ".png";
|
|
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
|
|
if (importer == null || !Configure(importer)) continue;
|
|
importer.SaveAndReimport();
|
|
changed++;
|
|
}
|
|
foreach (string name in JournalControls)
|
|
{
|
|
var importer = AssetImporter.GetAtPath(JournalRoot + name + ".png") as TextureImporter;
|
|
if (importer == null || !Configure(importer)) continue;
|
|
importer.SaveAndReimport();
|
|
changed++;
|
|
}
|
|
return changed;
|
|
}
|
|
}
|
|
|
|
public sealed class UiSpriteNineSlicePostprocessor : AssetPostprocessor
|
|
{
|
|
private void OnPreprocessTexture()
|
|
{
|
|
UiSpriteNineSliceRules.Configure((TextureImporter)assetImporter);
|
|
}
|
|
}
|
|
}
|
|
#endif
|