From 27819514afc79aa6b06147ba93dfeb1968c35908 Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 25 Jun 2026 20:00:09 +0200 Subject: [PATCH] =?UTF-8?q?fix(studio):=20Character=20window=20=E2=80=94?= =?UTF-8?q?=20show=20only=20the=20active=20tab=20page=20(clears=20the=20da?= =?UTF-8?q?rk=20overlay)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LayoutDesc 0x2100002E is a tabbed window; all three pages (Attributes/Skills/Titles) mount their content as overlapping root children. acdream drew all three, so the inactive pages' backdrops painted over the active content — the dim "almost opaque" cover the user reported, and it displaced the XP meter. The shared gmStatManagement ids are duplicated across pages and _byId keeps the LAST-mounted copy, so every bound widget lives in exactly one page; the controller now keeps that page visible (ContainsWidget reference-walk from the bound name element) and hides the rest. Header/attrs/XP-bar now render clean + correctly placed. Tests green. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../UI/Layout/CharacterStatController.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/AcDream.App/UI/Layout/CharacterStatController.cs b/src/AcDream.App/UI/Layout/CharacterStatController.cs index fa79cd85..fccf8508 100644 --- a/src/AcDream.App/UI/Layout/CharacterStatController.cs +++ b/src/AcDream.App/UI/Layout/CharacterStatController.cs @@ -76,6 +76,32 @@ public static class CharacterStatController rows.LinesProvider = () => AttributeRows(data()); list.AddChild(rows); } + + // ── Active-page selection (fixes the "dark overlay") ────────────────── + // 0x2100002E is a tabbed window: all three tab pages (Attributes / Skills / Titles) mount + // their content as separate root children that OVERLAP in the same content rect. Retail + // shows only the active page; acdream draws them all, so the inactive pages' backdrops paint + // over the active content (the dim "almost opaque" cover). The shared gmStatManagement ids + // are duplicated across pages and acdream's _byId keeps the LAST-mounted copy, so every widget + // we just bound lives in exactly ONE page. Keep that page visible; hide the rest. + if (layout.FindElement(NameId) is { } anchor && layout.Root is { } root) + { + foreach (var page in root.Children) + { + if (page.Children.Count == 0) continue; // tab-bar buttons are leaves — leave them + page.Visible = ContainsWidget(page, anchor); // only the bound page stays visible + } + } + } + + /// Depth-first reference search: is somewhere under + /// ? Used to find which overlapping tab page owns the bound widgets. + private static bool ContainsWidget(UiElement node, UiElement target) + { + if (ReferenceEquals(node, target)) return true; + foreach (var c in node.Children) + if (ContainsWidget(c, target)) return true; + return false; } private const float LineHeight = 18f;