Commit graph

6 commits

Author SHA1 Message Date
Erik
b2e68c2343 feat(ui): add stable authored-geometry-revision hash for plugin windows
Part of #490 part 2: plugin panels register with authoredGeometryRevision
hard-coded to 0, so a plugin author who ships a new authored panel size
(MossTank: 856x236 -> 984x271) has no way to signal the change short of
adding a manual revision-bump call site, and every user's stored layout
keeps the old size forever. Built-in retail-imported windows solve this
with an explicit incrementing int literal at each Register call; a plugin
author does not maintain that call site by hand.

RetailWindowManager.ComputeAuthoredGeometryRevision derives the revision
from the authored geometry tuple itself (width, height, minw, minh,
resizable) via a fixed FNV-1a-style combine over the values' raw IEEE-754
bit patterns -- deliberately not System.HashCode, whose per-process reseed
would make the "same" authored geometry hash differently on every launch.
The sign bit is masked off so the result is never negative (Register's own
Math.Max(0, revision) would otherwise silently fold distinct negative
hashes onto the same "unversioned" 0 bucket used by legacy saves).

Mutation shown to fail first: without this method,
RetailWindowManagerTests.ComputeAuthoredGeometryRevision_* (7 new tests)
fails to compile (CS0117, method does not exist). No wiring yet -- this
commit only adds the pure, inert helper; MountPlugins still passes no
revision. That lands next along with the comparison-semantics fix it
depends on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 17:47:04 +02:00
Erik
cd06f89e59 test(ui): cover resizable plugin windows through RetailWindowManager + persistence
Extends the resizable="true"/minw/minh markup grammar's coverage past
MarkupDocument's own parse tests to the two host seams a resizable
plugin panel actually flows through, proving no host-side wiring beyond
what MarkupDocument.Build already sets on the panel was needed:

- RetailWindowManagerTests: a resizable="true" markup panel accepts
  RetailWindowManager.ResizeTo within its minw/minh floor (and clamps
  to it below the floor); a plain (non-resizable) markup panel refuses
  — Width/Height unchanged and no Resized event, exactly today's
  fixed-size behavior.
- RetailWindowLayoutPersistenceTests: a resizable panel's dragged size
  round-trips through save/restore into a fresh session, and a saved
  size below the panel's CURRENT minw/minh floor (a legacy save, or a
  plugin update that raised its floor) clamps UP to the floor on
  restore rather than restoring the too-small legacy value.

Mutation proof: reverted MarkupDocument.cs to its pre-feature state and
reran the new tests — the two RetailWindowManagerTests cases failed
(the old UiNineSlicePanel ctor default of Resizable=true/MinWidth=40
let the "fixed" window resize and let the "resizable" window shrink
below the new floor), and the persistence floor-clamp case failed
(80x60 came back instead of clamping to 200x150). The plain
save/restore round-trip case passed either way — the old ctor default
was already resizable, so it exercises a real but coincidentally
already-covered path; kept for its own documentation value. Restoring
the implementation returns 256/257 (1 pre-existing unrelated skip) on
the full Markup/PluginSidePanel/RetailWindow/Anchor-filtered App suite
and 9/9 on the MossTank markup-filtered suite, both green.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:40:31 +02:00
Erik
06016014bc fix(ui): port retail window control feedback
Map synthetic move and resize affordances to the exact DAT cursors, make chat top chrome movable, and replace stale primary-panel height caps with a dynamic screen-edge constraint. This keeps the retained wrapper adaptation aligned with retail Dragbar/Resizebar behavior.
2026-07-17 09:40:08 +02:00
Erik
d3d1c895a0 feat(ui): finish retail toolbar controls
Discover all seven panel launchers from their DAT panel-id attributes, route mounted panels through event-driven retained window state, and ghost unavailable panels. Port Use and Examine selection/target behavior with exact Appraise dispatch and retail cursor modes.

Co-Authored-By: Codex <codex@openai.com>
2026-07-11 12:11:53 +02:00
Erik
5d9e98c118 refactor(ui): own retained controller lifetimes 2026-07-10 23:35:26 +02:00
Erik
6e9e10367f feat(ui): centralize retained window lifecycle 2026-07-10 21:31:18 +02:00