# AcDream.App.UI — Retail-style UI toolkit This is acdream's retained-mode UI toolkit. It mirrors the **behavior** of the retail AC client (hit-testing, modal, capture, drag-drop, tooltip delay, focus routing, event type codes) without trying to byte-match the retail binary — because the retail widgets live in `keystone.dll`, which we don't decompile. ## Research All design decisions in this directory are grounded in the master synthesis + six deep-dive docs under [`docs/research/retail-ui/`](../../../docs/research/retail-ui/): | Document | Topic | |---|---| | [`00-master-synthesis.md`](../../../docs/research/retail-ui/00-master-synthesis.md) | Cross-slice synthesis + C# port plan | | [`01-architecture-and-init.md`](../../../docs/research/retail-ui/01-architecture-and-init.md) | Process entry, window, main loop | | [`02-class-hierarchy.md`](../../../docs/research/retail-ui/02-class-hierarchy.md) | CUIManager / CUIListener / CFont / CSurface | | [`03-rendering.md`](../../../docs/research/retail-ui/03-rendering.md) | Font atlas, 2D quad batch, cursor | | [`04-input-events.md`](../../../docs/research/retail-ui/04-input-events.md) | WndProc → Device → widget event routing | | [`05-panels.md`](../../../docs/research/retail-ui/05-panels.md) | Chat, attributes, spells, paperdoll, inventory | | [`06-hud-and-assets.md`](../../../docs/research/retail-ui/06-hud-and-assets.md) | Vital orbs, radar, compass + dat asset catalog | ## Files - `UiEvent.cs` — 24-byte event struct + retail-faithful type constants (`0x01` click, `0x15` drag-begin, `0x3E` drop, `0x201` WM_LBUTTONDOWN, …) - `UiElement.cs` — base widget with `OnDraw` / `OnEvent` / `OnHitTest` / `OnTick` virtuals, children list, ZOrder, focus/capture flags - `UiPanel.cs` — `UiPanel` (rect + optional bg/border), `UiLabel`, `UiButton` - `UiRenderContext.cs` — per-frame draw context with translate stack - `UiRoot.cs` — top-of-tree + "Device" responsibilities (mouse/keyboard state, focus, modal, capture, drag-drop, tooltip timer). Mirrors the retail `DAT_00837ff4` Device object's vtable. - `UiHost.cs` — one-shot wrapper: owns the `UiRoot`, a `TextRenderer`, and a default `BitmapFont`. Provides `WireMouse` / `WireKeyboard` helpers for Silk.NET plumbing. ## Integration pattern ```csharp // GameWindow.OnLoad _uiHost = new UiHost(_gl!, shadersDir, _debugFont); _uiHost.Root.WorldMouseFallThrough += (btn, x, y, flags) => HandleWorldClick(btn, x, y, flags); _uiHost.Root.WorldKeyFallThrough += (vk, lp) => HandleHotkey(vk); foreach (var mouse in _input.Mice) _uiHost.WireMouse(mouse); foreach (var kb in _input.Keyboards) _uiHost.WireKeyboard(kb); // Add panels var chat = new Panels.ChatWindow { Left = 10, Top = 400, Width = 500, Height = 250 }; _uiHost.Root.AddChild(chat); // GameWindow.OnRender — after the 3D scene _uiHost.Tick(deltaSeconds); _uiHost.Draw(new Vector2(_window!.Size.X, _window.Size.Y)); ``` ## What's scaffolded vs what still needs building ### Shipped in the scaffold (this session) - UI tree + event routing + focus + modal + capture + drag-drop - Hit-testing (children-first, Z-order tie-break) - Tooltip timer (~1000ms) - Hover enter/leave, click vs right-click, scroll, keyboard - World fall-through so existing camera/player controls still work - Simple text/rect drawing through the existing `BitmapFont` + `TextRenderer` pipeline ### To build next 1. **`AcFont`** + **`FontCache`** — load `Font` DBObjs from `portal.dat` range `0x40000000..0x40000FFF`, bake 256×256 glyph atlas from the referenced `RenderSurface` (`0x06xxxxxx`). See [slice 03 §4](../../../docs/research/retail-ui/03-rendering.md#4-fonts-in-the-dat-files). 2. **Dat sprite loader** — decode `RenderSurface` dats as GL textures; add `DrawSprite(uint datId, Rectangle dest, uint rgba)` to `UiRenderContext`. 3. **`CursorManager`** — OS cursor + dat-sourced custom cursors via [slice 03 §7](../../../docs/research/retail-ui/03-rendering.md#7-cursor). 4. **Scissor clipping** — for panels with scrollable interiors (chat, inventory grid). `GL_SCISSOR_TEST` wrapped in `UiRenderContext.PushScissor` / `PopScissor`. 5. **First concrete panel — `ChatWindow`** since we have all 6 wire messages parsed already. See [slice 05 §1](../../../docs/research/retail-ui/05-panels.md#1-chat-window). 6. **Vital orbs HUD** once the server sends `GameMessagePrivateUpdateVital`. See [slice 06 A.1](../../../docs/research/retail-ui/06-hud-and-assets.md#a1-health--stamina--mana-globes). ## Retail magic numbers the scaffold preserves Because hand-ported panel code will copy the retail switch-case structure, we keep the magic constants: ```csharp // Event types UiEventType.Click == 0x01 // chunk_00470000.c ~11140 UiEventType.Tooltip == 0x07 // chunk_00460000.c ~6253 (~1000ms delay) UiEventType.DragBegin == 0x15 // chunk_004A0000.c ~2707 UiEventType.DragEnter == 0x21 // chunk_004A0000.c ~2714 UiEventType.DragOver == 0x1C // chunk_004A0000.c ~2723 UiEventType.DropReleased == 0x3E // chunk_004A0000.c ~2754 UiEventType.MouseDown == 0x201 // WM_LBUTTONDOWN UiEventType.MouseUp == 0x202 // WM_LBUTTONUP // Event IDs // Widget event IDs live in the 0x10000000+ range (retail convention). // UiRoot auto-assigns EventIds starting at 0x10000001. ```