feat(D.5.1): UiItemSlot widget (UIElement_UIItem cell port)
Behavioral leaf widget for the toolbar item cell. Draws the empty-slot sprite (0x060074CF) when unbound; draws the pre-composited icon texture when a weenie is bound via SetItem(). ConsumesDatChildren=true prevents the LayoutImporter from double-building the dat sub-elements. SpriteResolve is configurable so paperdoll equip slots can swap in per-slot silhouettes later. No Clicked/OnEvent — that wiring comes in Task 8 (ToolbarController). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e9a5248972
commit
1270596f30
2 changed files with 85 additions and 0 deletions
54
src/AcDream.App/UI/UiItemSlot.cs
Normal file
54
src/AcDream.App/UI/UiItemSlot.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace AcDream.App.UI;
|
||||
|
||||
/// <summary>
|
||||
/// One item-in-a-slot cell (port of retail UIElement_UIItem, class 0x10000032).
|
||||
/// A behavioral LEAF: it draws the empty-slot sprite when unbound, else a
|
||||
/// pre-composited icon texture (set by the controller). Holds the bound weenie
|
||||
/// guid (retail UIElement_UIItem::itemID, +0x5FC).
|
||||
/// </summary>
|
||||
public sealed class UiItemSlot : UiElement
|
||||
{
|
||||
public UiItemSlot() { ClickThrough = false; }
|
||||
|
||||
public override bool ConsumesDatChildren => true;
|
||||
|
||||
/// <summary>Bound weenie guid (0 = empty). Retail UIElement_UIItem::itemID.</summary>
|
||||
public uint ItemId { get; private set; }
|
||||
|
||||
/// <summary>Pre-composited icon GL texture for the bound item (0 = none).</summary>
|
||||
public uint IconTexture { get; private set; }
|
||||
|
||||
/// <summary>Empty-slot sprite. Default = the generic toolbar empty-slot border
|
||||
/// 0x060074CF (uiitem template 0x21000037, state ItemSlot_Empty). Configurable so
|
||||
/// paperdoll equip slots can use their per-slot silhouettes later.</summary>
|
||||
public uint EmptySprite { get; set; } = 0x060074CFu;
|
||||
|
||||
/// <summary>RenderSurface id -> (GL texture, w, h). Set by the factory/controller.</summary>
|
||||
public Func<uint, (uint tex, int w, int h)>? SpriteResolve { get; set; }
|
||||
|
||||
public void SetItem(uint itemId, uint iconTexture)
|
||||
{
|
||||
ItemId = itemId;
|
||||
IconTexture = iconTexture;
|
||||
}
|
||||
|
||||
public void Clear() { ItemId = 0; IconTexture = 0; }
|
||||
|
||||
protected override void OnDraw(UiRenderContext ctx)
|
||||
{
|
||||
if (ItemId != 0 && IconTexture != 0)
|
||||
{
|
||||
ctx.DrawSprite(IconTexture, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
return;
|
||||
}
|
||||
if (SpriteResolve is not null && EmptySprite != 0)
|
||||
{
|
||||
var (tex, _, _) = SpriteResolve(EmptySprite);
|
||||
if (tex != 0)
|
||||
ctx.DrawSprite(tex, 0f, 0f, Width, Height, 0f, 0f, 1f, 1f, Vector4.One);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
tests/AcDream.App.Tests/UI/UiItemSlotTests.cs
Normal file
31
tests/AcDream.App.Tests/UI/UiItemSlotTests.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using AcDream.App.UI;
|
||||
|
||||
namespace AcDream.App.Tests.UI;
|
||||
|
||||
public class UiItemSlotTests
|
||||
{
|
||||
[Fact]
|
||||
public void IsLeafWidget()
|
||||
=> Assert.True(new UiItemSlot().ConsumesDatChildren);
|
||||
|
||||
[Fact]
|
||||
public void DefaultEmptySprite_isToolbarBorder()
|
||||
=> Assert.Equal(0x060074CFu, new UiItemSlot().EmptySprite);
|
||||
|
||||
[Fact]
|
||||
public void Empty_whenNoItem()
|
||||
{
|
||||
var s = new UiItemSlot();
|
||||
Assert.Equal(0u, s.ItemId);
|
||||
Assert.Equal(0u, s.IconTexture);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetItem_setsIdAndTexture()
|
||||
{
|
||||
var s = new UiItemSlot();
|
||||
s.SetItem(0x5001u, 0x99u);
|
||||
Assert.Equal(0x5001u, s.ItemId);
|
||||
Assert.Equal(0x99u, s.IconTexture);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue