feat(ui): complete retail quick-slot input

Port global toolbar use/select/create actions, migrate the collapsed Ctrl-number bindings, and route them through a focused retained-UI controller. Preserve shortcut aliases as aliases across inventory and paperdoll drops with retail's neutral/accept/reject drag states, preventing physical item moves such as unwielding an equipped helmet.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 08:59:49 +02:00
parent 6fcc510d5d
commit e65119f0c6
24 changed files with 650 additions and 69 deletions

View file

@ -99,8 +99,29 @@ public class PaperdollControllerTests
SeedPackItem(objects, 0xC01u, EquipMask.HeadWear); // a helm in the pack
var ctrl = Bind(layout, objects);
var payload = new ItemDragPayload(0xC01u, ItemDragSource.Inventory, 0, lists[HeadSlot].Cell);
Assert.True(ctrl.OnDragOver(lists[HeadSlot], lists[HeadSlot].Cell, payload)); // helm → head OK
Assert.False(ctrl.OnDragOver(lists[ShieldSlot], lists[ShieldSlot].Cell, payload)); // helm → shield NO
Assert.Equal(ItemDragAcceptance.Accept,
ctrl.OnDragOver(lists[HeadSlot], lists[HeadSlot].Cell, payload)); // helm → head OK
Assert.Equal(ItemDragAcceptance.Reject,
ctrl.OnDragOver(lists[ShieldSlot], lists[ShieldSlot].Cell, payload)); // helm → shield NO
}
[Fact]
public void ShortcutAlias_isNeutral_andNeverWieldsThroughPaperdoll()
{
var (layout, lists) = BuildLayout();
var objects = new ClientObjectTable();
SeedPackItem(objects, 0xC02u, EquipMask.HeadWear);
var wields = new List<(uint item, uint mask)>();
var ctrl = Bind(layout, objects, wields);
var payload = new ItemDragPayload(
0xC02u, ItemDragSource.ShortcutBar, 2, lists[HeadSlot].Cell);
Assert.Equal(ItemDragAcceptance.None,
ctrl.OnDragOver(lists[HeadSlot], lists[HeadSlot].Cell, payload));
ctrl.HandleDropRelease(lists[HeadSlot], lists[HeadSlot].Cell, payload);
Assert.Empty(wields);
Assert.Equal(EquipMask.None, objects.Get(0xC02u)!.CurrentlyEquippedLocation);
}
[Fact]