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

@ -0,0 +1,48 @@
namespace AcDream.App.UI;
/// <summary>
/// Retail toolbar panel ids carried by DAT property <c>0x10000029</c>.
/// Retail reference: <c>gmToolbarUI::PostInit @ 0x004BEA80</c> discovers the
/// seven buttons and reads this property from each one.
/// Only panels mounted in the retained runtime are mapped; other authored
/// toolbar buttons remain present but ghosted until their panel ships.
/// </summary>
public static class RetailPanelCatalog
{
public const uint Inventory = 7u;
public const uint Character = 11u;
private static readonly (uint PanelId, string WindowName)[] Mounted =
{
(Inventory, WindowNames.Inventory),
(Character, WindowNames.Character),
};
public static IReadOnlyList<(uint PanelId, string WindowName)> MountedPanels => Mounted;
public static bool TryGetWindowName(uint panelId, out string windowName)
{
foreach (var entry in Mounted)
{
if (entry.PanelId != panelId) continue;
windowName = entry.WindowName;
return true;
}
windowName = string.Empty;
return false;
}
public static bool TryGetPanelId(string windowName, out uint panelId)
{
foreach (var entry in Mounted)
{
if (!string.Equals(entry.WindowName, windowName, StringComparison.Ordinal)) continue;
panelId = entry.PanelId;
return true;
}
panelId = 0;
return false;
}
}