using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Decentralized
{
///
/// PLEDGER 硬件风格公共皮肤与组件:
/// - 机身:自画像素九宫格 ui_hw_shell(圆角石墨,左上受光边、右下背光边),3× 像素放大
/// - 刻字:游戏 machinery 窗口的标题栏与分隔线设为透明;标题当机身刻字(灰色粗体、字距 18、居中)
/// - 屏幕:黑色边框 ui_hw_bezel 包一块浅色墨水屏 ui_hw_paper(#D8DAD0),左右对称居中
/// - 文字:深墨色 Ink,次要信息灰 _dim,警示暗红 _note
/// - 按钮:黑底白字触控键 Key / KeyText;选中的项反色(白底黑框黑字加粗)加准星角标 ui_hw_sel,不用 [方括号]
/// - 数据表:列右对齐,整行可点,选中行整行反色(黑底白字)
/// - 滚动区:背景透明露出墨水屏底色,滚动条滑块为墨色
///
public static class PledgerSkin
{
public static readonly Color Ink = new Color(0.12f, 0.12f, 0.14f);
public static readonly Color Key = new Color(0.16f, 0.16f, 0.19f);
public static readonly Color KeyText = new Color(0.93f, 0.93f, 0.90f);
public static readonly Color Dim = new Color(0.38f, 0.39f, 0.40f);
public static readonly Color Alert = new Color(0.62f, 0.16f, 0.12f);
public static readonly Color Title = new Color(0.62f, 0.64f, 0.70f);
public static readonly Color Paper = new Color(0.847f, 0.855f, 0.816f); // #D8DAD0
public static readonly Color RowNormal = new Color(0f, 0f, 0f, 0.04f);
public static readonly Color Transparent = new Color(0f, 0f, 0f, 0f);
public static readonly Color MaskClear = new Color(0f, 0f, 0f, 0.004f);
public static readonly Color Separator = new Color(0.12f, 0.12f, 0.14f, 0.18f);
/// 透明化底图:若附带 Mask 组件则保留极微小 alpha(0.004),避免 Mask 模板 alpha 为 0 导致子内容被整裁。
public static void SetClear(Image img)
{
if (img == null) return;
img.color = (img.GetComponent() != null) ? MaskClear : Transparent;
}
private static readonly Dictionary Sliced = new Dictionary();
/// 把本 mod 的像素图做成九宫格贴到 Image 上:边角 border 像素不拉伸,一个像素放大成 3 个界面单位。
public static void Slice(Image img, string key, int border)
{
var src = Items.ModSprite(key);
if (img == null || src == null) return;
if (!Sliced.TryGetValue(key, out var sp))
{
src.texture.filterMode = FilterMode.Point;
sp = Sprite.Create(src.texture, src.rect, new Vector2(0.5f, 0.5f), src.pixelsPerUnit, 0, SpriteMeshType.FullRect, new Vector4(border, border, border, border));
Sliced[key] = sp;
}
img.sprite = sp;
img.type = Image.Type.Sliced;
img.pixelsPerUnitMultiplier = 100f / (3f * sp.pixelsPerUnit);
img.color = Color.white;
}
/// 把输入框切片为墨水屏凹槽:浅色底、1 像素深墨边框(1:1 像素映射)。
public static void SliceGroove(Image img)
{
if (img == null) return;
if (!Sliced.TryGetValue("ui_hw_groove", out var sp))
{
var src = Items.ModSprite("ui_hw_groove");
if (src != null)
{
src.texture.filterMode = FilterMode.Point;
sp = Sprite.Create(src.texture, src.rect, new Vector2(0.5f, 0.5f), src.pixelsPerUnit, 0, SpriteMeshType.FullRect, new Vector4(2, 2, 2, 2));
}
else
{
var tex = new Texture2D(12, 12, TextureFormat.RGBA32, false) { filterMode = FilterMode.Point };
for (int y = 0; y < 12; y++)
for (int x = 0; x < 12; x++)
tex.SetPixel(x, y, (x == 0 || x == 11 || y == 0 || y == 11) ? Ink : Paper);
tex.Apply();
sp = Sprite.Create(tex, new Rect(0, 0, 12, 12), new Vector2(0.5f, 0.5f), 100f, 0, SpriteMeshType.FullRect, new Vector4(2, 2, 2, 2));
}
Sliced["ui_hw_groove"] = sp;
}
img.sprite = sp;
img.type = Image.Type.Sliced;
img.pixelsPerUnitMultiplier = 100f / sp.pixelsPerUnit;
img.color = Color.white;
}
/// 屏上的选择按钮(币种、档位、子页):选中的一个画成白底黑框黑字、四角带准星角标。
public static void Pick(CustomUIBuilder b, string text, bool selected, Action onClick, ICollection picked)
{
b.AddButton(text, onClick);
if (selected && picked != null) picked.Add(b.Last.root);
}
/// 数据表行定义:整行高亮与点击回调。
public sealed class RowDef
{
public GameObject Root;
public Image Image;
public bool Selected;
public Action OnClick;
}
/// 数据表的一行:列右对齐(第一列默认左对齐),整行可点击,选中行反色。
public static void TableRow(CustomUIBuilder b, float totalW, float height, float[] widths, TextAnchor[] aligns, string[] texts, bool selected, Action onClick, ICollection rows, ICollection clear)
{
b.BeginPanel(totalW, height, TextAnchor.MiddleLeft, 6f, 0f);
var root = b.Last.root;
var img = b.Last.image;
if (rows != null) rows.Add(new RowDef { Root = root, Image = img, Selected = selected, OnClick = onClick });
b.BeginRow(0f, TextAnchor.MiddleLeft);
for (int i = 0; i < widths.Length; i++)
{
float w = widths[i];
var align = (aligns != null && i < aligns.Length) ? aligns[i] : (i == 0 ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight);
b.BeginPanel(w, height - 6f, align, 0f, 0f);
if (clear != null) clear.Add(b.Last.image);
b.AddLabel(i < texts.Length ? texts[i] : "");
b.End();
}
b.End();
b.End();
}
/// 数据表表头:与表行同对齐方式,加粗,无底色。
public static void TableHeader(CustomUIBuilder b, float totalW, float height, float[] widths, TextAnchor[] aligns, string[] headers, ICollection clear)
{
b.BeginPanel(totalW, height, TextAnchor.MiddleLeft, 6f, 0f);
if (clear != null) clear.Add(b.Last.image);
b.BeginRow(0f, TextAnchor.MiddleLeft);
for (int i = 0; i < widths.Length; i++)
{
float w = widths[i];
var align = (aligns != null && i < aligns.Length) ? aligns[i] : (i == 0 ? TextAnchor.MiddleLeft : TextAnchor.MiddleRight);
b.BeginPanel(w, height - 6f, align, 0f, 0f);
if (clear != null) clear.Add(b.Last.image);
b.AddLabel(i < headers.Length ? "" + headers[i] + "" : "");
b.End();
}
b.End();
b.End();
}
/// 应用整套 PLEDGER 皮肤:机身、边框、墨水屏、刻字、文字颜色、触控键、滚动条与数据表行。
public static void Apply(CustomUIWindow win, RectTransform screen, Image bezel, Image paper, ICollection picked, ICollection clear, IEnumerable rows = null)
{
if (win?.root == null) return;
Slice(win.root.GetComponent(), "ui_hw_shell", 10);
if (bezel != null) Slice(bezel, "ui_hw_bezel", 5);
if (paper != null) Slice(paper, "ui_hw_paper", 3);
// 标题栏和分隔线透明,标题当机身刻字
foreach (var name in new[] { "header", "rule" })
{
var img = win.root.transform.Find(name)?.GetComponent();
if (img != null) SetClear(img);
}
if (win.frame?.titleText != null)
{
var t = win.frame.titleText;
t.color = Title;
t.fontStyle = FontStyles.Bold;
t.characterSpacing = 18f;
t.fontSize = 16f;
t.horizontalAlignment = HorizontalAlignmentOptions.Center;
}
var content = win.frame?.contentRoot?.GetComponent();
if (content != null) content.childAlignment = TextAnchor.UpperCenter;
if (screen == null) return;
// 收集所有表格行 root,避免按钮样式覆盖整行
var rowRoots = new HashSet();
if (rows != null)
{
foreach (var r in rows)
if (r?.Root != null) rowRoots.Add(r.Root);
}
// 屏上文字:note 暗红,dim 灰,其余深墨色
foreach (var t in screen.GetComponentsInChildren(true))
{
if (t.GetComponentInParent