fix #378: Config-tab dropdown menus render bare with no popup chrome

Root cause: DatWidgetFactory builds Config-tab Type-0x10000038 menu
leaves as bare UiMenu instances (matching the vendor/chat channel menu
pattern), but unlike those two controllers, ConfigOptionsPageController
never wired the menu's sprite/font/geometry properties after Bind — so
every dropdown rendered as plain text with no button well, no arrow
cap, and opened no popup on click (#374's fix only corrected click
ROUTING, not the missing chrome).

Fix: ConfigOptionsPageController.ApplyMenuChrome wires every Config-tab
menu row with the SAME retail sprite ids VendorUiController/
ChatWindowController's channel menu already use for this shared popup
catalog (LayoutDesc 0x21000043), verified against the live DAT via
OptionsPanelLiveMountProbeTests' ProbeConfigMenuChrome/
ProbeConfigMenuPopupChrome probes. Regressed by
ConfigOptionsPageControllerTests.MenuRow_SoundFeatures_OpensAndSelects
ThroughRealHitPath_UsingAuthoredPopupGeometry, which drives the real
click-to-open + item-pick path through the authored popup geometry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-11 23:00:29 +02:00
parent 28bef4e03b
commit c121842664
6 changed files with 524 additions and 35 deletions

View file

@ -73,20 +73,43 @@ scope the controller's application set to it.
## #378 — Config-tab dropdown menus render bare (no button well, no arrow) and no popup opens on click
**Status:** OPEN — filed 2026-08-11 at Campaign OP gate 4 (user
screenshots: retail's Resolution row shows a sunken value well + green
arrow cap; acdream's same rows — Resolution, Sound Features, all the
Config menus — render as bare text like "Stereo"/"1280x720" with NO
button chrome, and clicking produces NO visible dropdown). This is the
user-facing residual behind #374: the pointer-routing fix landed, but the
menu widget itself isn't presenting at the live mount. Candidate family
(to CONFIRM with the live-mount probe, not assume): the Config row
template's Type-6 menu element's button-face/arrow/popup sprites not
resolving at build (so the popup may even "open" while drawing nothing) —
the same fixture-green/live-broken class as #372/#375. The probe must
dump the built UiMenu's sprite ids + SpriteResolve wiring for a Config
row versus the working chat-channel menu. Blocks the OP6 gate's
resolution step (#374's re-test) and every other Config menu row.
**Status:** ROOT-CAUSED + FIXED (this commit) — pending the user's
re-gate. Filed 2026-08-11 at Campaign OP gate 4 (user screenshots:
retail's Resolution row shows a sunken value well + green arrow cap;
acdream's same rows rendered as bare text with no button chrome).
**ROOT CAUSE — nothing wired the Config-tab `UiMenu` leaves at all.**
`ConfigOptionsPageController.BuildMenuRow`/`BuildStringMenuRow` built the
row's `UiMenu` widget from the template but never touched a single one of
its sprite/geometry properties — `SpriteResolve` stayed null and every
sprite id stayed 0, so `OnDraw`/`OnDrawOverlay` early-returned on every
frame (drawing literal nothing) even though click ROUTING (#374) was
already correct. A live-DAT probe (raw `ElementDesc` walk against
`DatCollectionAdapter`, bypassing the widget layer) traced the menu
leaf's (`0x10000224`) full retail inheritance chain — base `0x10000353`
in LayoutDesc `0x21000043`, retail's shared popup/dropdown catalog — and
found it BYTE-IDENTICAL in every sprite id to `VendorUiController`'s own
already-fixed dropdown (base `0x1000034B`, same layout): arrow cap
`0x060012B1`/`B2`, face/row sprite `0x060012B3`/`B4`, and the full
6-sprite scrollbar chrome `0x06004C5F/60/63/66/69/6C`. Attribute 7 (the
popup catalog LayoutDesc) is `0x21000043` for BOTH menus — not an
approximation, a measured fact, so no register row was needed. **Fix:**
`ConfigOptionsPageController.ApplyMenuChrome` wires the SAME chrome
`VendorUiController` already established, threaded from
`RetailUiRuntime`'s existing `Assets.ResolveSprite`/`DefaultFont`/
`DebugFont` bindings through `ConfigOptionsPageController.Bind`'s three
new optional parameters. Regressed by
`tests/AcDream.App.Tests/UI/Layout/ConfigOptionsPageControllerTests.cs`
(`MenuRow_SoundFeatures_OpensAndSelectsThroughRealHitPath_UsingAuthoredPopupGeometry`
— asserts every sprite id is non-zero, drives the real click-to-open +
item-pick event path, and confirms the applied value reaches
`AudioSettings`) and extended live-mount probes in
`OptionsPanelLiveMountProbeTests.cs` (`ProbeConfigMenuChrome`/
`ProbeConfigMenuPopupChrome`).
**Re-gate (§OP6 step 8, and every other Config-tab dropdown): every
Config menu row should now show the sunken value-well face + green arrow
cap and open a real bordered, scrollable popup on click.**
## #377 — Startup CRASH (0xC0000005 in Glfw.GetVideoMode) when settings.json has `fullscreen: true`