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>
This commit is contained in:
Erik 2026-07-11 12:11:53 +02:00
parent 21fefce0e0
commit d3d1c895a0
19 changed files with 478 additions and 72 deletions

View file

@ -128,6 +128,8 @@ public sealed class RetailUiRuntime : IDisposable
MountCharacter();
MountPlugins();
MountInventory();
Host.WindowManager.WindowVisibilityChanged += OnWindowVisibilityChanged;
BindToolbarPanelButtons();
SyncToolbarWindowButtons();
if (bindings.Persistence is { } persistence)
@ -197,22 +199,34 @@ public sealed class RetailUiRuntime : IDisposable
public void RestoreLayout() => _persistence?.RestoreAll();
public bool ToggleWindow(string name)
{
bool visible = Host.ToggleWindow(name);
SyncToolbarWindowButtons();
return visible;
}
=> Host.ToggleWindow(name);
public void CloseWindow(string name)
{
Host.HideWindow(name);
SyncToolbarWindowButtons();
}
=> Host.HideWindow(name);
public void SyncToolbarWindowButtons()
{
ToolbarController?.SetInventoryOpen(Host.IsWindowVisible(WindowNames.Inventory));
ToolbarController?.SetCharacterOpen(Host.IsWindowVisible(WindowNames.Character));
if (ToolbarController is null) return;
foreach (var (panelId, windowName) in RetailPanelCatalog.MountedPanels)
ToolbarController.SetPanelOpen(panelId, Host.IsWindowVisible(windowName));
}
private void BindToolbarPanelButtons()
{
ToolbarController?.BindPanelButtons(
panelId => RetailPanelCatalog.TryGetWindowName(panelId, out string name)
&& Host.WindowManager.TryGet(name, out _),
panelId =>
{
if (RetailPanelCatalog.TryGetWindowName(panelId, out string name))
ToggleWindow(name);
});
}
private void OnWindowVisibilityChanged(string windowName, bool visible)
{
if (RetailPanelCatalog.TryGetPanelId(windowName, out uint panelId))
ToolbarController?.SetPanelOpen(panelId, visible);
}
private ImportedLayout? Import(uint layoutId)
@ -374,6 +388,7 @@ public sealed class RetailUiRuntime : IDisposable
peace, war, empty, b.ItemInteraction, b.SendAddShortcut, b.SendRemoveShortcut,
toggleCombat: b.ToggleCombat,
selectItem: guid => b.Selection.Select(guid, SelectionChangeSource.Toolbar),
selectedObjectId: () => b.Selection.SelectedObjectId ?? 0u,
playerGuid: b.PlayerGuid,
sendPutItemInContainer: b.SendPutItemInContainer);
ToolbarInputController = new ToolbarInputController(ToolbarController, b.Selection);
@ -420,9 +435,6 @@ public sealed class RetailUiRuntime : IDisposable
SelectedObjectController),
});
ConfigureToolbarCollapse(layout, (UiCollapsibleFrame)handle.OuterFrame, root.Height);
ToolbarController.BindWindowToggles(
() => ToggleWindow(WindowNames.Inventory),
() => ToggleWindow(WindowNames.Character));
Console.WriteLine("[D.5.1] retail toolbar window from LayoutDesc importer (0x21000016).");
}
@ -635,6 +647,7 @@ public sealed class RetailUiRuntime : IDisposable
if (_disposed) return;
_disposed = true;
_persistence?.Dispose();
Host.WindowManager.WindowVisibilityChanged -= OnWindowVisibilityChanged;
Host.Dispose();
}
}