feat(D.2b): cut GameWindow over to the data-driven chat window
Replace the hand-authored chat block (UiNineSlicePanel + inline UiChatView + local BuildRetailChatLines/RetailChatColor statics) with ChatWindowController.Bind(LayoutDesc 0x21000006) — the same LayoutImporter path as the vitals window. The controller places UiChatView (transcript) + UiChatInput (text entry, on-submit) + UiChatScrollbar + UiChannelMenu inside the dat-authored chrome. The dead local statics are deleted. Wired to _commandBus (same LiveCommandBus as the ImGui ChatPanel) so type+Enter dispatches SendChatCmd server-ward. Transcript keyboard set from _uiHost.Keyboard (set by WireKeyboard above the chat block) for Ctrl+C/Ctrl+A. Divergence register: added AD-28 (two-widget split vs UIElement_Text), AP-38 (no in-element word-wrap), AP-39 (per-line colour vs per-glyph runs), AP-40 (no opacity fade / shared vitalsDatFont), TS-30 (tab buttons no-op), TS-31 (no squelch); updated IA-15 to cover both vitals + chat importer paths. Build: 0 errors/warnings. Tests: 392 passed, 1 skipped (expected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9d9e036e4c
commit
12ab9663d2
3 changed files with 48 additions and 52 deletions
|
|
@ -1833,58 +1833,47 @@ public sealed class GameWindow : IDisposable
|
|||
Console.WriteLine("[D.2b] vitals: LayoutDesc 0x2100006C not found — vitals unavailable.");
|
||||
}
|
||||
|
||||
// Retail chat window — a draggable/resizable nine-slice frame hosting a
|
||||
// scrollable transcript (UiChatView). Read-only + wheel-scroll for now;
|
||||
// drag-select + Ctrl+C copy land in the next D.2b sub-step. A dedicated
|
||||
// ChatVM with a deeper tail (200) feeds the scrollback; it shares the
|
||||
// same live ChatLog (Chat) as the ImGui panel.
|
||||
// Retail chat window — data-driven from LayoutDesc 0x21000006 (gmMainChatUI),
|
||||
// the same importer path as vitals. ChatWindowController binds the transcript,
|
||||
// input, scrollbar and channel menu and routes through ChatVM + ChatCommandRouter.
|
||||
var retailChatVm = new AcDream.UI.Abstractions.Panels.Chat.ChatVM(Chat, displayLimit: 200);
|
||||
var chatWindow = new AcDream.App.UI.UiNineSlicePanel(ResolveChrome)
|
||||
AcDream.App.UI.Layout.ElementInfo? chatRootInfo;
|
||||
AcDream.App.UI.Layout.ImportedLayout? chatLayout;
|
||||
lock (_datLock)
|
||||
{
|
||||
Left = 10, Top = 432, Width = 440, Height = 184,
|
||||
MinWidth = 180, MinHeight = 80,
|
||||
};
|
||||
var chatView = new AcDream.App.UI.UiChatView
|
||||
{
|
||||
Left = 8, Top = 8, Width = 424, Height = 168,
|
||||
Anchors = AcDream.App.UI.AnchorEdges.Left | AcDream.App.UI.AnchorEdges.Top
|
||||
| AcDream.App.UI.AnchorEdges.Right | AcDream.App.UI.AnchorEdges.Bottom,
|
||||
Font = _debugFont,
|
||||
LinesProvider = () => BuildRetailChatLines(retailChatVm),
|
||||
// Drag-select + Ctrl+C copy need the keyboard for clipboard +
|
||||
// modifier state. UiHost.Keyboard is set during WireKeyboard above.
|
||||
Keyboard = _uiHost.Keyboard,
|
||||
};
|
||||
chatWindow.AddChild(chatView);
|
||||
_uiHost.Root.AddChild(chatWindow);
|
||||
|
||||
// Map the VM's formatted tail into coloured view lines. Per-ChatKind
|
||||
// palette (retail-ish): speech white, tells magenta, channels blue,
|
||||
// system yellow, emotes grey, combat orange. Refined later if needed.
|
||||
static System.Collections.Generic.IReadOnlyList<AcDream.App.UI.UiChatView.Line> BuildRetailChatLines(
|
||||
AcDream.UI.Abstractions.Panels.Chat.ChatVM vm)
|
||||
{
|
||||
var detailed = vm.RecentLinesDetailed();
|
||||
var result = new AcDream.App.UI.UiChatView.Line[detailed.Count];
|
||||
for (int i = 0; i < detailed.Count; i++)
|
||||
result[i] = new AcDream.App.UI.UiChatView.Line(
|
||||
detailed[i].Text, RetailChatColor(detailed[i].Kind));
|
||||
return result;
|
||||
chatRootInfo = AcDream.App.UI.Layout.LayoutImporter.ImportInfos(
|
||||
_dats!, AcDream.App.UI.Layout.ChatWindowController.LayoutId);
|
||||
chatLayout = chatRootInfo is null ? null
|
||||
: AcDream.App.UI.Layout.LayoutImporter.Build(chatRootInfo, ResolveChrome, vitalsDatFont);
|
||||
}
|
||||
|
||||
static System.Numerics.Vector4 RetailChatColor(AcDream.Core.Chat.ChatKind kind) => kind switch
|
||||
if (chatRootInfo is not null && chatLayout is not null)
|
||||
{
|
||||
AcDream.Core.Chat.ChatKind.LocalSpeech => new(1f, 1f, 1f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.RangedSpeech => new(1f, 0.95f, 0.8f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.Channel => new(0.6f, 0.8f, 1f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.Tell => new(1f, 0.5f, 1f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.System => new(1f, 1f, 0.45f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.Popup => new(1f, 0.85f, 0.4f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.Emote => new(0.8f, 0.8f, 0.7f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.SoulEmote => new(0.8f, 0.8f, 0.7f, 1f),
|
||||
AcDream.Core.Chat.ChatKind.Combat => new(1f, 0.6f, 0.25f, 1f),
|
||||
_ => new(0.9f, 0.9f, 0.9f, 1f),
|
||||
};
|
||||
var chatController = AcDream.App.UI.Layout.ChatWindowController.Bind(
|
||||
chatRootInfo, chatLayout, retailChatVm, _commandBus ?? (AcDream.UI.Abstractions.ICommandBus)AcDream.UI.Abstractions.NullCommandBus.Instance,
|
||||
vitalsDatFont, _debugFont, ResolveChrome);
|
||||
if (chatController is not null)
|
||||
{
|
||||
// Ctrl+C / Ctrl+A on the transcript need the keyboard for clipboard + modifiers.
|
||||
// _uiHost.Keyboard is set by WireKeyboard above — it is non-null here.
|
||||
chatController.Transcript.Keyboard = _uiHost.Keyboard;
|
||||
// Top-level retail window: user-positioned at the bottom-left, movable + resizable.
|
||||
// KEEP the dat-authored size (do NOT override Width/Height) so the child anchors
|
||||
// capture their dat margins on the first layout — the same reason the vitals root
|
||||
// keeps its dat size. The user resizes/moves from there.
|
||||
var chatRoot = chatController.Root;
|
||||
chatRoot.Left = 10;
|
||||
chatRoot.Top = 460; // bottom-left default; pending the user's visual review
|
||||
chatRoot.Anchors = AcDream.App.UI.AnchorEdges.None;
|
||||
chatRoot.Draggable = true;
|
||||
chatRoot.Resizable = true;
|
||||
chatRoot.MinWidth = 200f;
|
||||
chatRoot.MinHeight = 80f;
|
||||
_uiHost.Root.AddChild(chatRoot);
|
||||
Console.WriteLine("[D.2b] retail chat window from LayoutDesc importer (0x21000006).");
|
||||
}
|
||||
else Console.WriteLine("[D.2b] chat: required role elements missing in 0x21000006.");
|
||||
}
|
||||
else Console.WriteLine("[D.2b] chat: LayoutDesc 0x21000006 not found.");
|
||||
|
||||
// Drain plugin-registered markup panels (buffered before the GL
|
||||
// window opened) into the same UiRoot tree. A faulty plugin markup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue