feat(ui): D.5.3/B.1 — toolbar drag handler stub + spine wiring (TS-33)

Implements Task 4 of the drag-drop spine: ToolbarController now satisfies
IItemListDragHandler. The ctor loop wires RegisterDragHandler(this) on every
slot list and stamps Cell.SlotIndex + Cell.SourceKind=ShortcutBar, matching
retail's gmToolbarUI::PostInit/RegisterItemListDragHandler pattern. OnDragOver
accepts any non-empty payload (TS-33 stub; eligibility gate is Stream B.2).
HandleDropRelease logs and returns (no AddShortcut 0x019C / RemoveShortcut
0x019D wire yet). Three new B.1 xUnit tests cover handler registration, accept,
and inert-stub semantics. All 490 app tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-20 13:00:20 +02:00
parent 595c4bdac4
commit 3d04f61451
3 changed files with 86 additions and 2 deletions

View file

@ -23,7 +23,7 @@ namespace AcDream.App.UI.Layout;
/// <c>CreateObject</c> resolves a formerly-unknown guid.
/// </para>
/// </summary>
public sealed class ToolbarController
public sealed class ToolbarController : IItemListDragHandler
{
// Slot element ids in slot-index order (toolbar LayoutDesc 0x21000016, pre-dump).
// Row 1 = slots 0-8 (0x100001A7..0x100001AF), Row 2 = slots 9-17 (0x100006B7..0x100006BF).
@ -96,7 +96,15 @@ public sealed class ToolbarController
{
_slots[i] = layout.FindElement(SlotIds[i]) as UiItemList;
if (_slots[i] is { } list)
{
WireClick(list);
// B.1 drag-drop spine: this controller is the drop handler for every
// toolbar slot list; each cell knows its slot index + that it's a
// shortcut-bar source (retail UIElement_ItemList::RegisterItemListDragHandler).
list.RegisterDragHandler(this);
list.Cell.SlotIndex = i;
list.Cell.SourceKind = ItemDragSource.ShortcutBar;
}
}
// Cache the four mutually-exclusive combat-mode indicator elements.
@ -287,4 +295,22 @@ public sealed class ToolbarController
_useItem(list.Cell.ItemId);
};
}
// ── IItemListDragHandler (B.1 spine) ─────────────────────────────────────
// Retail: gmToolbarUI is the m_dragHandler for every shortcut slot list.
// The accept/reject gate (IsShortcutEligible) and the AddShortcut/RemoveShortcut
// wire are Stream B.2; this stub accepts any real item and LOGS the drop (TS-33).
/// <inheritdoc/>
public bool OnDragOver(UiItemList targetList, UiItemSlot targetCell, ItemDragPayload payload)
=> payload.ObjId != 0;
/// <inheritdoc/>
public void HandleDropRelease(UiItemList targetList, UiItemSlot targetCell, ItemDragPayload payload)
{
// TS-33: no wire yet. Stream B.2 replaces this with the ShortcutStore mutation +
// AddShortcut 0x019C / RemoveShortcut 0x019D sends (gmToolbarUI::HandleDropRelease :197971).
Console.WriteLine($"[B.2 TODO] drop obj 0x{payload.ObjId:X8} from {payload.SourceKind} " +
$"slot {payload.SourceSlot} → toolbar slot {targetCell.SlotIndex}");
}
}