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>
This commit is contained in:
parent
8463d64311
commit
2153bee247
7 changed files with 620 additions and 10 deletions
|
|
@ -616,7 +616,41 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
_automation?.Tick(deltaSeconds);
|
||||
}
|
||||
|
||||
public void Draw(System.Numerics.Vector2 screenSize) => Host.Draw(screenSize);
|
||||
private System.Numerics.Vector2 _lastScreenSize;
|
||||
private bool _screenSizeSettling;
|
||||
|
||||
public void Draw(System.Numerics.Vector2 screenSize)
|
||||
{
|
||||
// #390: retail's display-change UI cascade, ported as a two-step edge
|
||||
// detector on the per-frame screen size:
|
||||
// - the frame a change is seen: re-clamp every floating window into
|
||||
// the new bounds (retail's unconditional clamping MoveTo cascade,
|
||||
// UIElementManager::RefreshEvent @0x0045C530) — cheap, no I/O,
|
||||
// keeps windows reachable through a live drag-resize;
|
||||
// - the first frame the size REPEATS after a change: one reload of
|
||||
// the per-resolution saved layout (retail's post-change global
|
||||
// message 0xE → per-resolution auto-layout reload), without the
|
||||
// login path's lazy save-back (retail saves only via @saveui).
|
||||
// The first-ever frame seeds the size silently — the login restore
|
||||
// owns initial placement.
|
||||
if (_lastScreenSize == default)
|
||||
{
|
||||
_lastScreenSize = screenSize;
|
||||
}
|
||||
else if (screenSize != _lastScreenSize)
|
||||
{
|
||||
_persistence?.ClampAllToScreen();
|
||||
_lastScreenSize = screenSize;
|
||||
_screenSizeSettling = true;
|
||||
}
|
||||
else if (_screenSizeSettling)
|
||||
{
|
||||
_screenSizeSettling = false;
|
||||
_persistence?.RestoreAll(saveBack: false);
|
||||
}
|
||||
|
||||
Host.Draw(screenSize);
|
||||
}
|
||||
|
||||
public bool HandleInputAction(AcDream.UI.Abstractions.Input.InputAction action)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue