fix(ui): restore retail magic shortcut bar
Port the retail horizontal ItemList empty-slot padding and share UIItem shortcut-number graphics with the status toolbar. Preserve all authored face children on compound DAT buttons so the three-piece Cast control reflows and renders as one complete button. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
0527325b25
commit
e3605672bb
12 changed files with 466 additions and 62 deletions
|
|
@ -11,6 +11,60 @@ public sealed class SpellcastingUiControllerTests
|
|||
{
|
||||
private static (uint, int, int) NoTex(uint _) => (0u, 0, 0);
|
||||
|
||||
[Fact]
|
||||
public void ImportedFixture_UsesRetailEmptyCells_ShortcutDigits_AndCompleteCastButton()
|
||||
{
|
||||
ImportedLayout layout = LayoutImporter.Build(
|
||||
FixtureLoader.LoadCombatInfos(), NoTex, datFont: null);
|
||||
ApplyAnchors(layout.Root);
|
||||
var spellbook = new Spellbook();
|
||||
spellbook.OnSpellLearned(42u, 1f);
|
||||
spellbook.SetFavorite(0, 0, 42u);
|
||||
var objects = new ClientObjectTable();
|
||||
objects.AddOrUpdate(new ClientObject { ObjectId = 1u, Name = "Player" });
|
||||
uint[] regular = [101u, 102u, 103u, 104u, 105u, 106u, 107u, 108u, 109u];
|
||||
uint[] ghosted = [201u, 202u, 203u, 204u, 205u, 206u, 207u, 208u, 209u];
|
||||
uint[] empty = [301u, 302u, 303u, 304u, 305u, 306u, 307u, 308u, 309u];
|
||||
var graphics = new UiShortcutSlotGraphics(regular, ghosted, empty, 0x060074CFu);
|
||||
|
||||
using SpellcastingUiController controller = Bind(
|
||||
layout, spellbook, objects, _ => { }, shortcutGraphics: graphics)!;
|
||||
|
||||
UiElement group = layout.FindElement(0x100000AAu)!;
|
||||
UiItemList list = Descendants(group).OfType<UiItemList>().First();
|
||||
Assert.True(list.SingleRow);
|
||||
Assert.True(list.FillVisibleEmptySlots);
|
||||
Assert.Equal(439f, list.Width);
|
||||
Assert.Equal(13, list.GetNumUIItems());
|
||||
|
||||
UiCatalogSlot favorite = Assert.IsType<UiCatalogSlot>(list.GetItem(0));
|
||||
Assert.Equal(42u, favorite.EntryId);
|
||||
Assert.Equal(0, favorite.ShortcutNum);
|
||||
Assert.Same(regular, favorite.ActiveDigitArray());
|
||||
|
||||
for (int i = 1; i < 9; i++)
|
||||
{
|
||||
UiCatalogSlot slot = Assert.IsType<UiCatalogSlot>(list.GetItem(i));
|
||||
Assert.True(slot.IsEmptySlot);
|
||||
Assert.Equal(i, slot.ShortcutNum);
|
||||
Assert.Same(empty, slot.ActiveDigitArray());
|
||||
}
|
||||
for (int i = 9; i < 13; i++)
|
||||
Assert.Equal(-1, list.GetItem(i)!.ShortcutNum);
|
||||
|
||||
var cast = Assert.IsType<UiButton>(
|
||||
layout.FindElement(SpellcastingUiController.CastButtonId));
|
||||
Assert.Equal((525f, 75f), (cast.Left, cast.Width));
|
||||
Assert.Equal(3, cast.FaceSegmentCount);
|
||||
Assert.Equal(
|
||||
[
|
||||
new UiPixelRect(0, 0, 31, 31),
|
||||
new UiPixelRect(32, 0, 42, 31),
|
||||
new UiPixelRect(43, 0, 74, 31),
|
||||
],
|
||||
cast.FaceSegmentRectsForTest());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ImportedFixture_BindsAllTabs_AndTracksEquippedEndowment()
|
||||
{
|
||||
|
|
@ -167,7 +221,8 @@ public sealed class SpellcastingUiControllerTests
|
|||
Spellbook spellbook,
|
||||
ClientObjectTable objects,
|
||||
Action<uint> useItem,
|
||||
Action<int, int, uint>? addFavorite = null)
|
||||
Action<int, int, uint>? addFavorite = null,
|
||||
UiShortcutSlotGraphics? shortcutGraphics = null)
|
||||
{
|
||||
var casting = new SpellCastingController(
|
||||
spellbook, () => null, () => 1u, () => { }, _ => { }, (_, _) => { }, _ => { });
|
||||
|
|
@ -178,7 +233,17 @@ public sealed class SpellcastingUiControllerTests
|
|||
useItem,
|
||||
new SelectionState(),
|
||||
addFavorite ?? ((_, _, _) => { }),
|
||||
(_, _) => { });
|
||||
(_, _) => { },
|
||||
shortcutGraphics);
|
||||
}
|
||||
|
||||
private static void ApplyAnchors(UiElement parent)
|
||||
{
|
||||
foreach (UiElement child in parent.Children)
|
||||
{
|
||||
child.ApplyAnchor(parent.Width, parent.Height);
|
||||
ApplyAnchors(child);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<UiElement> Descendants(UiElement root)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,38 @@ public class UiItemListTests
|
|||
Assert.Equal((17, 9), (received.Value.X, received.Value.Y));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetailHorizontalEmptySlots_FillViewport_AndShrinkOnlyEmptyTail()
|
||||
{
|
||||
var list = new UiItemList
|
||||
{
|
||||
Width = 130f,
|
||||
Height = 32f,
|
||||
CellWidth = 32f,
|
||||
CellHeight = 32f,
|
||||
SingleRow = true,
|
||||
FillVisibleEmptySlots = true,
|
||||
EmptySlotFactory = () => new UiCatalogSlot(),
|
||||
};
|
||||
list.Flush();
|
||||
list.AddItem(new UiCatalogSlot { EntryId = 42u });
|
||||
list.LayoutCells();
|
||||
|
||||
Assert.Equal(4, list.GetNumUIItems());
|
||||
Assert.Equal((0f, 32f, 64f, 96f),
|
||||
(list.GetItem(0)!.Left, list.GetItem(1)!.Left,
|
||||
list.GetItem(2)!.Left, list.GetItem(3)!.Left));
|
||||
|
||||
list.Width = 65f;
|
||||
list.LayoutCells();
|
||||
Assert.Equal(2, list.GetNumUIItems());
|
||||
Assert.Equal(42u, Assert.IsType<UiCatalogSlot>(list.GetItem(0)).EntryId);
|
||||
|
||||
list.Width = 16f;
|
||||
list.LayoutCells();
|
||||
Assert.Single(list.Children); // the occupied cell is never discarded
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScrollItemIntoView_moves_only_when_row_is_outside_viewport()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue