From 5486a9c033aafb2d597b7ded592667731ce47c66 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:16:53 +0800 Subject: [PATCH 1/8] ui: keep the scroll viewport mask visible (alpha 0 clipped all content) Co-Authored-By: Claude Sonnet 5.5 --- src/Decentralized/PledgerSkin.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index bbcfd01..f87347d 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -197,7 +197,8 @@ namespace Decentralized if (scroll.viewport != null) { var vpImg = scroll.viewport.GetComponent(); - if (vpImg != null) vpImg.color = Transparent; + // 视口的图是 Mask 的模板:alpha 为 0 会把整个内容裁掉,只能压到几乎看不见 + if (vpImg != null) vpImg.color = new Color(0f, 0f, 0f, 0.004f); } if (scroll.verticalScrollbar != null) { From 58bf83d08ef49099f25ac25f33b5155ab265326e Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:30:47 +0800 Subject: [PATCH 2/8] ui: avoid alpha 0 on images with Mask dependency across PledgerSkin --- src/Decentralized/PledgerSkin.cs | 24 ++++++++++++++++++------ src/Decentralized/WalletWindow.cs | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index f87347d..737a478 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -27,8 +27,16 @@ namespace Decentralized 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 个界面单位。 @@ -116,7 +124,7 @@ namespace Decentralized foreach (var name in new[] { "header", "rule" }) { var img = win.root.transform.Find(name)?.GetComponent(); - if (img != null) img.color = Transparent; + if (img != null) SetClear(img); } if (win.frame?.titleText != null) { @@ -193,18 +201,18 @@ namespace Decentralized foreach (var scroll in screen.GetComponentsInChildren(true)) { var bg = scroll.GetComponent(); - if (bg != null) bg.color = Transparent; + if (bg != null) SetClear(bg); if (scroll.viewport != null) { var vpImg = scroll.viewport.GetComponent(); // 视口的图是 Mask 的模板:alpha 为 0 会把整个内容裁掉,只能压到几乎看不见 - if (vpImg != null) vpImg.color = new Color(0f, 0f, 0f, 0.004f); + if (vpImg != null) SetClear(vpImg); } if (scroll.verticalScrollbar != null) { var sb = scroll.verticalScrollbar; var track = sb.GetComponent(); - if (track != null) track.color = Transparent; + if (track != null) SetClear(track); if (sb.handleRect != null) { var handleImg = sb.handleRect.GetComponent(); @@ -217,11 +225,15 @@ namespace Decentralized } } - // 清理辅助 Panel 底图 + // 清理辅助 Panel 底图与任何残留原生灰色边框的容器 if (clear != null) { foreach (var img in clear) - if (img != null) img.color = Transparent; + if (img != null) SetClear(img); + } + foreach (var img in screen.GetComponentsInChildren(true)) + { + if (img.sprite == MachineryStyle.BevelFrame) SetClear(img); } // 数据表行:反色高亮与整行点击 diff --git a/src/Decentralized/WalletWindow.cs b/src/Decentralized/WalletWindow.cs index 5050e8e..727dcef 100644 --- a/src/Decentralized/WalletWindow.cs +++ b/src/Decentralized/WalletWindow.cs @@ -195,7 +195,7 @@ namespace Decentralized OnClick = () => { dev.Asset = x.asset; dev.Note = null; Open(dev); } }); PledgerSkin.Apply(win, screen, bezel, paper, _picked, _clear, rows); - if (plate != null) plate.color = PledgerSkin.Transparent; + if (plate != null) PledgerSkin.SetClear(plate); // 签名要按住 ✓:在按键上挂一个按住计时 if (ok != null && dev.Screen == Screen.Review && ok.GetComponent() == null) ok.AddComponent().Device = dev.Address; } From 6cc546cd67ca8b5a9b2768af4d23a561e0a77f43 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:31:09 +0800 Subject: [PATCH 3/8] ui: stack bank deposit and withdraw buttons vertically to fit labels --- src/Decentralized/TerminalWindow.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Decentralized/TerminalWindow.cs b/src/Decentralized/TerminalWindow.cs index 158b8c1..1ba60b5 100644 --- a/src/Decentralized/TerminalWindow.cs +++ b/src/Decentralized/TerminalWindow.cs @@ -194,11 +194,12 @@ namespace Decentralized r.AddHeader(L.T("bank.ops")); AmountRow(r); AmlPreview(r); - r.AddSpace(4f); - r.BeginRow(6f); + r.AddSpace(6f); r.AddButton(L.T("trade.deposit"), Deposit); + r.Last?.SetPreferredSize(RightW - 30f, 28f); + r.AddSpace(4f); r.AddButton(L.T("trade.withdraw"), Withdraw); - r.End(); + r.Last?.SetPreferredSize(RightW - 30f, 28f); }); } From 9f0bc5d180a51f88c756bff207dd8841c8da8728 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:32:20 +0800 Subject: [PATCH 4/8] ui: style all text inputs as light e-ink grooves with dark borders --- art/sprites.py | 9 +++++ .../ModFiles/Textures/Items/ui_hw_groove.png | Bin 0 -> 86 bytes src/Decentralized/PledgerSkin.cs | 33 +++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/Decentralized/ModFiles/Textures/Items/ui_hw_groove.png diff --git a/art/sprites.py b/art/sprites.py index 1a83c01..49d4482 100644 --- a/art/sprites.py +++ b/art/sprites.py @@ -739,11 +739,20 @@ def hw_selected(): return c +def hw_groove(): + """PLEDGER 墨水屏输入框凹槽(12×12,九宫格边 2):浅色底、1 像素深墨边。""" + c = Canvas(12, 12) + c.rect(0, 0, 11, 11, 'n') + c.rect(1, 1, 10, 10, 'P') + return c + + UI_ICONS = {'ui_bank': ui_bank, 'ui_poinbase': ui_poinbase, 'ui_web3': ui_web3} UI_ICONS['ui_hw_shell'] = lambda: rounded(32, 7, 'K', 'E', 'z') UI_ICONS['ui_hw_bezel'] = lambda: rounded(16, 4, 'n') UI_ICONS['ui_hw_paper'] = lambda: rounded(12, 2, 'P') UI_ICONS['ui_hw_sel'] = hw_selected +UI_ICONS['ui_hw_groove'] = hw_groove UI_ICONS['ui_hw_ok'] = lambda: hw_button('ok') UI_ICONS['ui_hw_no'] = lambda: hw_button('no') diff --git a/src/Decentralized/ModFiles/Textures/Items/ui_hw_groove.png b/src/Decentralized/ModFiles/Textures/Items/ui_hw_groove.png new file mode 100644 index 0000000000000000000000000000000000000000..163ef61f3a2228f55a5f10bae5378d68eef76cd8 GIT binary patch literal 86 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kSx*把输入框切片为墨水屏凹槽:浅色底、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) { @@ -155,9 +184,11 @@ namespace Decentralized t.color = t.gameObject.name.Contains("_note") ? Alert : t.gameObject.name.Contains("_dim") ? Dim : Ink; } - // 屏上输入框 + // 屏上输入框:墨水屏凹槽样式(浅色底、深墨 1px 边、深墨文字、灰色占位符) foreach (var inp in screen.GetComponentsInChildren(true)) { + var bg = inp.GetComponent() ?? inp.targetGraphic as Image; + if (bg != null) SliceGroove(bg); if (inp.textComponent != null) inp.textComponent.color = Ink; if (inp.placeholder is TextMeshProUGUI ph) ph.color = Dim; } From 4bf7e58b36f8edf6a631504aab40bd1b09732c82 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:32:52 +0800 Subject: [PATCH 5/8] ui: slim down vertical scrollbars to 6px dark ink handles with transparent tracks --- src/Decentralized/PledgerSkin.cs | 35 ++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index 19ed5ae..7589eff 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -242,14 +242,45 @@ namespace Decentralized if (scroll.verticalScrollbar != null) { var sb = scroll.verticalScrollbar; - var track = sb.GetComponent(); - if (track != null) SetClear(track); + var sbrt = sb.transform as RectTransform; + if (sbrt != null) sbrt.sizeDelta = new Vector2(6f, sbrt.sizeDelta.y); + foreach (var img in sb.GetComponentsInChildren(true)) + { + if (sb.handleRect != null && (img.gameObject == sb.handleRect.gameObject || img.transform.IsChildOf(sb.handleRect))) + continue; + SetClear(img); + } if (sb.handleRect != null) { + sb.handleRect.sizeDelta = new Vector2(0f, sb.handleRect.sizeDelta.y); var handleImg = sb.handleRect.GetComponent(); if (handleImg != null) { handleImg.sprite = MachineryStyle.White; + handleImg.type = Image.Type.Simple; + handleImg.color = Ink; + } + } + } + if (scroll.horizontalScrollbar != null) + { + var sb = scroll.horizontalScrollbar; + var sbrt = sb.transform as RectTransform; + if (sbrt != null) sbrt.sizeDelta = new Vector2(sbrt.sizeDelta.x, 6f); + foreach (var img in sb.GetComponentsInChildren(true)) + { + if (sb.handleRect != null && (img.gameObject == sb.handleRect.gameObject || img.transform.IsChildOf(sb.handleRect))) + continue; + SetClear(img); + } + if (sb.handleRect != null) + { + sb.handleRect.sizeDelta = new Vector2(sb.handleRect.sizeDelta.x, 0f); + var handleImg = sb.handleRect.GetComponent(); + if (handleImg != null) + { + handleImg.sprite = MachineryStyle.White; + handleImg.type = Image.Type.Simple; handleImg.color = Ink; } } From a5ff9418ab85017ceeba4eff1c23b8a469253a65 Mon Sep 17 00:00:00 2001 From: ZHU MINCHAO <48154958+MinchaoZhu@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:33:20 +0800 Subject: [PATCH 6/8] ui: invert child action buttons in selected table rows to light on dark --- src/Decentralized/PledgerSkin.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Decentralized/PledgerSkin.cs b/src/Decentralized/PledgerSkin.cs index 7589eff..f853de4 100644 --- a/src/Decentralized/PledgerSkin.cs +++ b/src/Decentralized/PledgerSkin.cs @@ -315,6 +315,26 @@ namespace Decentralized if (pBtn != null && pBtn.gameObject != r.Root) continue; t.color = r.Selected ? KeyText : Ink; } + if (r.Selected) + { + // 选中行整行反色(深墨底):行内的操作按钮反转为浅色底、深墨字 + foreach (var cBtn in r.Root.GetComponentsInChildren