- Add ChatLayoutFixtureGenerator.cs (Skip-by-default) to regenerate
chat_21000006.json from the live portal.dat via LayoutImporter.ImportInfos
- Commit generated fixture chat_21000006.json (13 KB, 400 lines) — dat-free,
auto-copied to test output via existing *.json csproj glob
- Refactor FixtureLoader: extract shared LoadInfos(fileName) helper; add
LoadChat() + LoadChatInfos() mirroring the vitals pattern; LoadVitalsInfos()
now delegates to the shared loader (behavior unchanged, vitals tests green)
- Add ChatLayoutConformanceTests: ResolvesKnownElements + ResolvedTypes_MatchRetailRegistry
Confirmed resolved Types from live dat:
0x10000011 (transcript) → Type 12 (style-prototype, skipped by factory)
0x10000016 (input) → Type 12 (style-prototype, skipped by factory)
0x10000014 (menu) → Type 6
0x10000012 (scrollbar) → Type 11
0x10000019 (send) → Type 1
0x1000046F (max/min) → Type 1
Also fix pre-existing build break: UiChatInput.MoveCaret(int delta) was made
private in ce848c1 but UiChatInputTests.Backspace_DeletesBeforeCaret called it
as public. Expose a public MoveCaret(int) overload (no-shift) alongside the
private MoveCaret(int,bool) — restores the intended test surface.
Full suite: 398 passed, 2 skipped (generator + pre-existing), 0 failed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the retail UIElement_Text editable single-line field:
- Focused = "write mode": draws the gold lit field sprite (0x060011AB, the
Normal_focussed state) instead of the flat translucent rect; Enter submits
AND blurs (exits write mode).
- Single-line SELECTION: click-drag, Shift+Arrows, Shift+Home/End, Ctrl+A;
translucent-blue highlight behind the span; typing/Backspace/Delete/Paste
replace the selection first.
- CLIPBOARD: Ctrl+C copy, Ctrl+X cut, Ctrl+V paste at the caret (control chars
stripped — single-line). Wired to the keyboard device for clipboard + Ctrl/
Shift state.
- Held-key AUTO-REPEAT (Silk delivers one KeyDown per press): Backspace /
Delete / Left / Right repeat via a 0.4s-delay, ~25/s OnTick timer.
- Horizontal SCROLL + clip: keeps the caret in the field and draws only the
glyph window that fits inside it, so long input scrolls within the box
instead of spilling past Send into the 3D world.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports retail UIElement_Text editable one-line mode (caret = glyph index;
caret pixel-X = sum of glyph advances via UiDatFont) and ChatInterface's
100-entry command history (up/down arrow; sentinel -1 = live line).
Submit (Enter/KeypadEnter) fires OnSubmit callback, clears, pushes history.
Draws via DrawStringDat (dat font) or DrawString (BitmapFont) fallback.
AcceptsFocus=true + IsEditControl=true so UiRoot routes Char/KeyDown to it
and suppresses global hotkeys while typing. 6 new tests, all green.
Decomp refs: UIElement_Text::MoveCursor @0x468d00,
UIElement_Text::FindPixelsFromPos @0x472b40,
ChatInterface::ProcessCommand @0x4f5100
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>