acdream/docs/research/2026-08-13-display-block-test-script.md
Erik 2153bee247 fix #390: retail display-change UI cascade — clamp + per-res reload
Decomp-first per the block's rule: the research doc
(docs/research/2026-08-13-retail-ui-display-change.md, committed here)
pulled retail's actual mechanism before any code. A display change runs
UIElementManager::RefreshEvent @0x0045C530 ->
UIElement::UpdateForParentSizeChange @0x00462640, which unconditionally
re-applies every floating window's own clamping MoveTo override
(x = max(0, min(x, parentW - selfW)) - top-left priority, oversized
windows pin to 0), then broadcasts global message 0xE whose sole
listener reloads the per-resolution auto layout. No proportional moves,
no resets; retail saves layouts only via @saveui.

Port: RetailWindowLayoutPersistence.ClampAllToScreen() is the cascade
clamp (no store I/O; _restoring suppresses the per-move save so a live
drag-resize cannot write settings.json per frame), and
RetailUiRuntime.Draw carries a two-step screen-size edge detector:
change frame -> clamp; first stable frame -> one
RestoreAll(saveBack:false) per-resolution reload (the 0xE analog; no
lazy save-back, matching retail's save-only-on-command). The login
restore path already used retail's exact clamp math (Apply) - the live
trigger was the missing half, which is precisely the stranding the user
reported.

Deliberate deviation, register AD-91: retail's gmFloatyChatUI windows
have NO clamp and can strand; the block's requirement ("UI windows must
stay reachable") clamps every registered window uniformly.

Tests: 5 new persistence facts (clamp/top-left-pin/no-move/no-save-on-
clamp/no-save-on-live-reload). App suite 4,967/3 skips. Gate script
section D3 filled in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 17:42:50 +02:00

83 lines
4.4 KiB
Markdown
Raw 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.

# Display & resolution block — connected-gate test script
**Status: slices D1 (#389 FOV) and D2 (#391 curated list) are LANDED and
testable now; D3 (#390 UI reposition) and D4D6 (fullscreen family
#377/#376/#388) fill in as they land.** Launch with `ACDREAM_RETAIL_UI=1`
against local ACE, **Release** build for anything you judge by feel or
frame rate. The resize/display chain logs evidence permanently — after any
step you can cross-check `display: resolution pick`, `window: framebuffer
resize event`, and `vulkan: swapchain recreated` lines in the launch log.
---
## §D1 — Widescreen FOV feel (#389, SmartboxFOV)
The world camera now uses retail's law: your horizontal view stays roughly
constant (~84° at 16:9) and wide screens trim the vertical slice instead of
bloating the sides. Your stored Field of View migrates 60 → 90 (the retail
default) on first load.
1. **Just look at the world** on your 16:9 window at your usual spot
(Holtburg outdoors is ideal). Compared to yesterday: the view should
feel slightly more "zoomed"/framed — retail's framing — rather than the
old wide-angle look. If you have retail side-by-side, the framing should
now match it at the same window shape.
2. **Resize the window across shapes** (drag it narrow, then wide). The
world must stay geometrically true at every shape — no squish, no
stretch, circles stay circles (pre-#389, mid-session resizes distorted
the world in chase mode; that bug is dead).
3. **F11 → Config → Field of View slider.** It now means retail's gameFOV
in degrees (10160, default 90) and applies LIVE as you drag —
the world widens/narrows immediately, no restart. Defaults restores 90.
4. Set it back to 90 when done (or click Defaults).
## §D2 — Curated resolution list (#391)
1. **F11 → Config → Resolution dropdown.** The list is now your monitor's
real modes, modern widescreen only: no 800x600, no 1024x768, nothing
your 2560x1440 desktop can't host (no 3840x2160 entry). Expect roughly:
1280x720 / 1366x768 / 1600x900 / 1920x1080 / 2560x1440 — exactly what
your monitor reports, one entry per size.
2. **Pick a few.** Every pick must land exactly (window resizes AND
re-renders crisp — §the #387 chain), including 2560x1440.
3. **Click Defaults.** The Resolution row restores **2560x1440** (your
desktop's own mode — the deliberate replacement for retail's 800x600
default; register row IA-22), and the dropdown shows it selected.
## §D3 — UI windows stay reachable on downscale (#390)
Retail's rule, ported exactly: on a display change every floating window
re-clamps to `x = max(0, min(x, screenW windowW))` — top-left priority —
and the per-resolution saved layout for the NEW size reloads (without
saving anything until you save).
1. **At 2560x1440, drag several windows to the edges** — chat to the
bottom-right corner, the Options panel far right, a floating chat too.
2. **Pick 1280x720 in the Resolution dropdown.** Every window must end up
fully inside the new screen — anything that was past the new bounds
slides in flush with the edge; nothing needs a window-resize to fetch
back. (This includes floating chat windows — retail actually strands
those; we clamp them by the block's own requirement, register AD-91.)
3. **Drag-resize the window edge smaller** (not via the dropdown). Windows
must stay reachable continuously while you drag — the clamp runs live.
4. **Per-resolution memory:** at 1280x720 move a window somewhere
distinctive, pick 2560x1440, then pick 1280x720 again — the window
returns to where 1280x720 last had it (each resolution keeps its own
layout, like retail's per-resolution auto layouts — YOUR drags save
immediately under the current resolution; the automatic clamp/reload on
a resolution change never writes anything).
## §D4§D6 — Fullscreen family (#377/#376/#388) — PENDING SLICES
*(To be filled in when the fullscreen slices land. Will include: fullscreen
on/off via the Config checkbox, resolution picks while fullscreen becoming
REAL display-mode switches — **[BLACK-SCREEN RISK]** steps will be flagged:
have Alt+F4 / the physical power of patience ready — and the #388 crash
scenario surviving: a fullscreen-state settings apply must never take the
client down.)*
---
**Carried context for the gate:** the FPS cost of large windows is real
physics (more pixels = more GPU work) — judge frame rate in Release only.
The title bar shows live FPS.