Files
test/Assets/PerfectWorld/Scripts/Chat/Editor/TmpSpriteAssetGlyphMetricsBulkWindow.cs
2026-04-10 11:35:28 +07:00

258 lines
9.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEditor;
using UnityEngine;
using UnityEngine.TextCore;
namespace BrewMonster.Scripts.Editor
{
/// <summary>
/// Bulk chỉnh BX/BY/AD/Scale trên TMP_SpriteAsset (spriteGlyphTable).
/// Bulk-edit BX/BY/AD/Scale on TMP_SpriteAsset (spriteGlyphTable).
/// </summary>
public sealed class TmpSpriteAssetGlyphMetricsBulkWindow : EditorWindow
{
private enum ValueMode
{
Absolute,
AddDelta
}
private readonly List<TMP_SpriteAsset> _targets = new List<TMP_SpriteAsset>();
private Vector2 _scroll;
private string _nameContains = "";
private ValueMode _mode = ValueMode.Absolute;
private bool _setBx = true;
private bool _setBy = true;
private bool _setAd = true;
private bool _setScale;
private float _bx;
private float _by = 10f;
private float _ad = 32f;
private float _scale = 1f;
[MenuItem("Tools/Perfect World/ChatSystem/TMP Sprite Metrics (BX/BY/AD)…")]
public static void Open()
{
var w = GetWindow<TmpSpriteAssetGlyphMetricsBulkWindow>(false, "TMP Sprite Metrics", true);
w.minSize = new Vector2(420f, 360f);
}
private void OnGUI()
{
EditorGUILayout.Space(4f);
EditorGUILayout.LabelField("TMP_SpriteAsset — BX / BY / AD / Scale", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
"Áp dụng lên bảng glyph (spriteGlyphTable). Lọc theo tên sprite (cột Name) nếu cần.\n" +
"Applies to spriteGlyphTable. Optional name filter uses sprite character names.",
MessageType.None);
EditorGUILayout.Space(6f);
DrawTargetsSection();
EditorGUILayout.Space(8f);
_nameContains = EditorGUILayout.TextField("Name contains (optional)", _nameContains);
_mode = (ValueMode)EditorGUILayout.EnumPopup("Mode", _mode);
EditorGUILayout.Space(4f);
EditorGUILayout.LabelField("Fields to write", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
_setBx = GUILayout.Toggle(_setBx, "BX", GUILayout.Width(44));
_setBy = GUILayout.Toggle(_setBy, "BY", GUILayout.Width(44));
_setAd = GUILayout.Toggle(_setAd, "AD", GUILayout.Width(44));
_setScale = GUILayout.Toggle(_setScale, "Scale", GUILayout.Width(60));
EditorGUILayout.EndHorizontal();
string hint = _mode == ValueMode.Absolute
? "Giá trị gán thẳng vào metrics / Set metrics to these values."
: "Cộng dồn lên giá trị hiện tại / Add to current values.";
EditorGUILayout.HelpBox(hint, MessageType.None);
using (new EditorGUI.DisabledScope(!_setBx))
_bx = EditorGUILayout.FloatField("BX (bearing X)", _bx);
using (new EditorGUI.DisabledScope(!_setBy))
_by = EditorGUILayout.FloatField("BY (bearing Y)", _by);
using (new EditorGUI.DisabledScope(!_setAd))
_ad = EditorGUILayout.FloatField("AD (advance)", _ad);
using (new EditorGUI.DisabledScope(!_setScale))
_scale = EditorGUILayout.FloatField("Scale", _scale);
EditorGUILayout.Space(10f);
using (new EditorGUI.DisabledScope(_targets.Count == 0 || (!_setBx && !_setBy && !_setAd && !_setScale)))
{
if (GUILayout.Button("Apply to assets", GUILayout.Height(32)))
ApplyAll();
}
EditorGUILayout.Space(6f);
DrawSummary();
}
private void DrawTargetsSection()
{
EditorGUILayout.LabelField("Sprite assets", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Use selection (Project)", GUILayout.Height(22)))
AddFromSelection();
if (GUILayout.Button("Clear list", GUILayout.Width(100)))
_targets.Clear();
EditorGUILayout.EndHorizontal();
_scroll = EditorGUILayout.BeginScrollView(_scroll, GUILayout.MinHeight(120f));
for (int i = 0; i < _targets.Count; i++)
{
EditorGUILayout.BeginHorizontal();
_targets[i] = (TMP_SpriteAsset)EditorGUILayout.ObjectField(
_targets[i], typeof(TMP_SpriteAsset), false);
if (GUILayout.Button("", GUILayout.Width(24)))
{
_targets.RemoveAt(i);
i--;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
var drop = (TMP_SpriteAsset)EditorGUILayout.ObjectField(
"Drag asset here to add", null, typeof(TMP_SpriteAsset), false);
if (drop != null && !_targets.Contains(drop))
_targets.Add(drop);
}
private void AddFromSelection()
{
foreach (Object o in Selection.objects)
{
if (o is TMP_SpriteAsset sa && !_targets.Contains(sa))
_targets.Add(sa);
}
}
private void DrawSummary()
{
int n = _targets.Count;
if (n == 0)
{
EditorGUILayout.LabelField("No assets in list.");
return;
}
int glyphs = _targets.Where(t => t != null).Sum(t => t.spriteGlyphTable?.Count ?? 0);
EditorGUILayout.LabelField($"Assets: {n} | Total glyphs: {glyphs}");
}
private void ApplyAll()
{
if (!_setBx && !_setBy && !_setAd && !_setScale)
{
EditorUtility.DisplayDialog("TMP Sprite Metrics", "Chọn ít nhất một field (BX/BY/AD/Scale).", "OK");
return;
}
int changedAssets = 0;
int changedGlyphs = 0;
foreach (TMP_SpriteAsset asset in _targets.Where(a => a != null))
{
string path = AssetDatabase.GetAssetPath(asset);
if (string.IsNullOrEmpty(path))
continue;
Undo.RegisterCompleteObjectUndo(asset, "TMP Sprite glyph metrics");
var glyphTable = asset.spriteGlyphTable;
if (glyphTable == null || glyphTable.Count == 0)
continue;
HashSet<uint> allowed = BuildGlyphIndexFilter(asset);
bool touched = false;
foreach (TMP_SpriteGlyph g in glyphTable)
{
if (g == null)
continue;
if (allowed != null && !allowed.Contains(g.index))
continue;
GlyphMetrics m = g.metrics;
if (_setBx)
m.horizontalBearingX = _mode == ValueMode.Absolute ? _bx : m.horizontalBearingX + _bx;
if (_setBy)
m.horizontalBearingY = _mode == ValueMode.Absolute ? _by : m.horizontalBearingY + _by;
if (_setAd)
m.horizontalAdvance = _mode == ValueMode.Absolute ? _ad : m.horizontalAdvance + _ad;
g.metrics = m;
if (_setScale)
g.scale = _mode == ValueMode.Absolute ? _scale : g.scale + _scale;
touched = true;
changedGlyphs++;
}
if (_setScale)
{
var chars = asset.spriteCharacterTable;
if (chars != null)
{
foreach (TMP_SpriteCharacter c in chars)
{
if (c == null)
continue;
if (allowed != null && !allowed.Contains(c.glyphIndex))
continue;
c.scale = _mode == ValueMode.Absolute ? _scale : c.scale + _scale;
}
}
}
if (touched)
{
asset.UpdateLookupTables();
EditorUtility.SetDirty(asset);
changedAssets++;
}
}
AssetDatabase.SaveAssets();
Debug.Log($"[Cuong] TMP Sprite Metrics: updated {changedGlyphs} glyph(s) across {changedAssets} asset(s).");
}
/// <summary>
/// null = không lọc / no filter
/// </summary>
private HashSet<uint> BuildGlyphIndexFilter(TMP_SpriteAsset asset)
{
string f = _nameContains?.Trim();
if (string.IsNullOrEmpty(f))
return null;
var set = new HashSet<uint>();
var chars = asset.spriteCharacterTable;
if (chars == null)
return set;
foreach (TMP_SpriteCharacter c in chars)
{
if (c == null || string.IsNullOrEmpty(c.name))
continue;
if (c.name.IndexOf(f, System.StringComparison.OrdinalIgnoreCase) < 0)
continue;
set.Add(c.glyphIndex);
}
return set;
}
}
}