feat(ui): port favorite spell bar overflow

Import the retail arrow-only spell bar scrollbar from LayoutDesc, preserve authored end-button extents and HideDisabled behavior in the shared retained widget, and bind each favorite list to its sole horizontal pixel-scroll model. Match retail selection exposure for off-screen spells and pin the behavior with real-fixture conformance tests.

Document the six-slice world-interaction completion program as the active pre-M4 work order.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-23 06:35:53 +02:00
parent 20e2998adb
commit 02c29e67c8
12 changed files with 582 additions and 45 deletions

View file

@ -128,6 +128,60 @@ public class UiScrollbarTests
Assert.True(bar.OnEvent(new UiEvent(0u, bar, UiEventType.MouseUp, Data1: 144)));
}
[Fact]
public void HorizontalModel_UsesAuthoredArrowExtentsAndOneCellStep()
{
var model = new UiScrollable
{
ContentHeight = 640,
ViewHeight = 320,
LineHeight = 32,
};
model.SetScrollY(64);
var bar = new UiScrollbar
{
Width = 160f,
Height = 36f,
Horizontal = true,
Model = model,
DecrementButtonExtent = 23f,
IncrementButtonExtent = 29f,
};
Assert.True(bar.OnEvent(new UiEvent(
0u, bar, UiEventType.MouseDown, Data1: 22)));
Assert.Equal(32, model.ScrollY);
Assert.True(bar.OnEvent(new UiEvent(
0u, bar, UiEventType.MouseDown, Data1: 131)));
Assert.Equal(64, model.ScrollY);
}
[Fact]
public void ModelWithoutOverflow_IsDisabledAndHideDisabledSuppressesPresentation()
{
var model = new UiScrollable
{
ContentHeight = 320,
ViewHeight = 320,
LineHeight = 32,
};
var bar = new UiScrollbar
{
Width = 160f,
Height = 36f,
Horizontal = true,
Model = model,
HideWhenDisabled = true,
};
Assert.True(bar.IsModelDisabled);
Assert.False(bar.IsPresentationVisible);
Assert.False(bar.OnEvent(new UiEvent(
0u, bar, UiEventType.MouseDown, Data1: 159)));
Assert.Equal(0, model.ScrollY);
}
[Theory]
[InlineData(0f, 0f, 0f)]
[InlineData(0.5f, 0f, 50f)]