feat(D.5.1): ToolbarController — bind 18 slots, populate, deferred rebind, click-to-use
Port of gmToolbarUI::PostInit (slot wiring) + UpdateFromPlayerDesc (flush-and-bind shortcuts from PlayerDescription) + SetDelayedShortcutNum (deferred ItemAdded rebind) + UseShortcut (click → useItem callback). UiItemSlot gains Clicked (Action?) + OnEvent override (MouseDown → Clicked?.Invoke()) matching the retail UIElement_UIItem click dispatch pattern. UiEvent is a positional record struct so the OnEvent override reads e.Type (int) against UiEventType.MouseDown (const int 0x201) — confirmed from UiEvent.cs + UiText.cs before writing. Three tests green (populate bound slot, deferred rebind on ItemAdded, click fires useItem). Full suite: 0 failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9327fb64bf
commit
383a969c70
3 changed files with 235 additions and 0 deletions
85
tests/AcDream.App.Tests/UI/Layout/ToolbarControllerTests.cs
Normal file
85
tests/AcDream.App.Tests/UI/Layout/ToolbarControllerTests.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using Xunit;
|
||||
|
||||
namespace AcDream.App.Tests.UI.Layout;
|
||||
|
||||
public class ToolbarControllerTests
|
||||
{
|
||||
private static readonly uint[] Row1 =
|
||||
{ 0x100001A7,0x100001A8,0x100001A9,0x100001AA,0x100001AB,0x100001AC,0x100001AD,0x100001AE,0x100001AF };
|
||||
private static readonly uint[] Row2 =
|
||||
{ 0x100006B7,0x100006B8,0x100006B9,0x100006BA,0x100006BB,0x100006BC,0x100006BD,0x100006BE,0x100006BF };
|
||||
|
||||
private static (ImportedLayout layout, Dictionary<uint, UiItemList> slots) FakeToolbar()
|
||||
{
|
||||
var dict = new Dictionary<uint, UiElement>();
|
||||
var slots = new Dictionary<uint, UiItemList>();
|
||||
var root = new UiPanel();
|
||||
foreach (var id in Row1) AddSlot(id);
|
||||
foreach (var id in Row2) AddSlot(id);
|
||||
return (new ImportedLayout(root, dict), slots);
|
||||
|
||||
void AddSlot(uint id)
|
||||
{
|
||||
var list = new UiItemList(_ => (0u, 0, 0)) { Width = 32, Height = 32 };
|
||||
dict[id] = list; slots[id] = list; root.AddChild(list);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Populate_bindsShortcutToCorrectSlot()
|
||||
{
|
||||
var (layout, slots) = FakeToolbar();
|
||||
var repo = new ItemRepository();
|
||||
repo.AddOrUpdate(new ItemInstance { ObjectId = 0x5001u, WeenieClassId = 1u, IconId = 0x06001234u });
|
||||
var shortcuts = new List<PlayerDescriptionParser.ShortcutEntry>
|
||||
{ new(Index: 0, ObjectGuid: 0x5001u, SpellId: 0, Layer: 0) };
|
||||
|
||||
ToolbarController.Bind(layout, repo, () => shortcuts,
|
||||
iconIds: (_,_,_) => 0x77u, useItem: _ => { });
|
||||
|
||||
Assert.Equal(0x5001u, slots[Row1[0]].Cell.ItemId);
|
||||
Assert.Equal(0x77u, slots[Row1[0]].Cell.IconTexture);
|
||||
Assert.Equal(0u, slots[Row1[1]].Cell.ItemId); // others empty
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeferredRebind_whenItemArrivesLate()
|
||||
{
|
||||
var (layout, slots) = FakeToolbar();
|
||||
var repo = new ItemRepository(); // item NOT present yet
|
||||
var shortcuts = new List<PlayerDescriptionParser.ShortcutEntry>
|
||||
{ new(Index: 2, ObjectGuid: 0x5002u, SpellId: 0, Layer: 0) };
|
||||
|
||||
ToolbarController.Bind(layout, repo, () => shortcuts,
|
||||
iconIds: (_,_,_) => 0x88u, useItem: _ => { });
|
||||
Assert.Equal(0u, slots[Row1[2]].Cell.ItemId); // not bound yet
|
||||
|
||||
repo.AddOrUpdate(new ItemInstance { ObjectId = 0x5002u, WeenieClassId = 1u, IconId = 0x06005678u });
|
||||
|
||||
Assert.Equal(0x5002u, slots[Row1[2]].Cell.ItemId); // rebound on ItemAdded
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Click_emitsUseForBoundItem()
|
||||
{
|
||||
var (layout, slots) = FakeToolbar();
|
||||
var repo = new ItemRepository();
|
||||
repo.AddOrUpdate(new ItemInstance { ObjectId = 0x5001u, WeenieClassId = 1u, IconId = 0x06001234u });
|
||||
var shortcuts = new List<PlayerDescriptionParser.ShortcutEntry>
|
||||
{ new(Index: 0, ObjectGuid: 0x5001u, SpellId: 0, Layer: 0) };
|
||||
uint used = 0;
|
||||
|
||||
ToolbarController.Bind(layout, repo, () => shortcuts,
|
||||
iconIds: (_,_,_) => 0x77u, useItem: g => used = g);
|
||||
// UiEvent is a positional record struct: (SourceId, Target, Type, Data0..3, Payload)
|
||||
slots[Row1[0]].Cell.OnEvent(new UiEvent(0u, null, UiEventType.MouseDown));
|
||||
|
||||
Assert.Equal(0x5001u, used);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue