feat(ui): port retail selected-stack quantity

Bind the authored stack count entry and horizontal slider to one Core split-quantity owner, preserve retail count-first naming and exact 1000-step rounding, refresh on stack changes, and consume the selected amount during merges. Conformance covers the production DAT fixture and retained pointer/focus paths.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 10:07:25 +02:00
parent dc1649c493
commit a20e5c68c7
19 changed files with 595 additions and 51 deletions

View file

@ -199,6 +199,42 @@ public class DatWidgetFactoryTests
Assert.IsType<UiScrollbar>(e);
}
[Fact]
public void Type11_HorizontalScrollbar_usesDirectRetailTrackAndThumbChildren()
{
const uint Track = 0x06004CF6u;
const uint Thumb = 0x06005DC3u;
var info = new ElementInfo { Type = 11, Id = 0x100001A4u, Width = 90, Height = 14 };
var track = new ElementInfo { Id = 4u, Type = 3u, Width = 90, Height = 14 };
track.States[UiStateInfo.DirectStateId] = new UiStateInfo
{ Id = UiStateInfo.DirectStateId, Image = new UiImageMedia(Track, 1) };
var thumb = new ElementInfo { Id = 1u, Type = 3u, Width = 16, Height = 14 };
thumb.States[UiStateInfo.DirectStateId] = new UiStateInfo
{ Id = UiStateInfo.DirectStateId, Image = new UiImageMedia(Thumb, 1) };
info.Children.Add(track);
info.Children.Add(thumb);
var bar = Assert.IsType<UiScrollbar>(DatWidgetFactory.Create(info, NoTex, null));
Assert.True(bar.Horizontal);
Assert.Equal(Track, bar.TrackSprite);
Assert.Equal(Thumb, bar.ThumbSprite);
Assert.Equal(0u, bar.UpSprite);
Assert.Equal(0u, bar.DownSprite);
}
[Fact]
public void RetailToolbarFixture_buildsEditableStackEntry_andAuthoredHorizontalSlider()
{
ImportedLayout layout = FixtureLoader.LoadToolbar();
Assert.IsType<UiField>(layout.FindElement(0x100001A3u));
var bar = Assert.IsType<UiScrollbar>(layout.FindElement(0x100001A4u));
Assert.True(bar.Horizontal);
Assert.Equal(0x06004CF6u, bar.TrackSprite);
Assert.Equal(0x06005DC3u, bar.ThumbSprite);
}
// ── Test 5e: Type 3 is NOT registered — chrome/containers stay generic ────
//
// Retail Type 3 = UIElement_Field, but acdream's Type-3 dat elements (vitals/chat