fix(chargen): Campaign CC gate round 1 re-test 2 — R3-4/R3-7 scrollbar thumb
Retail authors TWO distinct UIElement_Scrollbar thumb shapes. DatWidgetFactory.BuildScrollbar's existing vertical-thumb detection was built against chat's own scrollbar (0x10000012) — a 3-slice composite where the thumb child carries no media of its own and three Type-3 grandchildren supply the top-cap/middle/bottom-cap sprites. The chargen Skills listbox scrollbar (0x100003f8), Summary's OVERVIEW listbox scrollbar (0x10000401), the Summary how-to box's scrollbar (0x100002e7), and the shade slider (0x10000321) all instead author a SIMPLE single-sprite thumb: the same structural child (Type 1, id 1, not the inc/dec button) carries its OWN direct media and has ZERO children — the 3-slice-only search found nothing for this shape, so every Thumb*Sprite stayed 0 regardless of overflow. Fixed by falling back to the thumb's own DefaultImage when the slice search finds nothing — additive; a thumb WITH real slice children (chat) is unaffected. This one fix covers R3-4's three listbox thumbs, R3-7, and — as a natural consequence of the same structural shape — the shade-slider indicator half of R3-5(c); no separate fix was needed there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7f6e93033f
commit
c9313edc63
2 changed files with 128 additions and 0 deletions
|
|
@ -315,6 +315,31 @@ public static class DatWidgetFactory
|
|||
if (slices.Length > 0) bar.ThumbTopSprite = DefaultImage(slices[0]);
|
||||
if (slices.Length > 1) bar.ThumbSprite = DefaultImage(slices[1]);
|
||||
if (slices.Length > 2) bar.ThumbBotSprite = DefaultImage(slices[^1]);
|
||||
|
||||
// R3-4/R3-7 (Campaign CC gate round 1 re-test 2): retail authors
|
||||
// TWO distinct thumb shapes for UIElement_Scrollbar (Type 11) —
|
||||
// chat's own scrollbar (0x10000012) is the 3-slice composite the
|
||||
// block above was built against (the thumb CHILD carries no media
|
||||
// of its own; three Type-3 grandchildren supply the top-cap/
|
||||
// middle/bottom-cap sprites) — but the chargen Skills listbox
|
||||
// (0x100003f8), Summary's OVERVIEW listbox (0x10000401), and the
|
||||
// Summary how-to box (0x100002e7 under 0x10000404) all author a
|
||||
// SIMPLE single-sprite thumb instead: the SAME structural child
|
||||
// (Type 1, id 1, not the inc/dec button) carries its OWN direct
|
||||
// Normal/Normal_rollover/Normal_pressed media and has ZERO
|
||||
// children (live-DAT-probe-confirmed against all three — no
|
||||
// slice grandchildren to find, so `slices` above is always
|
||||
// empty for this shape and every Thumb*Sprite stayed 0,
|
||||
// matching the reported "track+arrows render, no thumb"
|
||||
// symptom). <see cref="UiScrollbar.OnDraw"/> already falls back
|
||||
// to a single tiled `ThumbSprite` blit when the cap sprites are
|
||||
// unset (`ThumbTopSprite != 0 && ThumbBotSprite != 0` gate), so
|
||||
// the only missing piece is feeding it the thumb's OWN media
|
||||
// when it has no slice children — additive: a thumb WITH real
|
||||
// slice children (chat) is unaffected since `slices.Length == 0`
|
||||
// is false for that shape.
|
||||
if (slices.Length == 0)
|
||||
bar.ThumbSprite = DefaultImage(thumb);
|
||||
}
|
||||
|
||||
return bar;
|
||||
|
|
|
|||
|
|
@ -637,6 +637,109 @@ public class DatWidgetFactoryTests
|
|||
Assert.Equal(0u, bar.ThumbSprite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// R3-4/R3-7 (Campaign CC gate round 1 re-test 2): a VERTICAL scrollbar
|
||||
/// whose thumb child carries its OWN direct media (Normal/
|
||||
/// Normal_rollover/Normal_pressed) and has NO slice children — the
|
||||
/// exact live-DAT shape of the chargen Skills listbox scrollbar
|
||||
/// (0x100003f8), Summary's OVERVIEW listbox scrollbar (0x10000401),
|
||||
/// and the how-to box's own scrollbar (0x100002e7). Before this fix
|
||||
/// ThumbSprite stayed 0 (the 3-slice-children search this factory was
|
||||
/// originally built against — chat's scrollbar shape, see
|
||||
/// <see cref="ChatLayoutConformanceTests.ChatFixture_ScrollbarImportsInheritedMediaRoles"/>
|
||||
/// — found nothing to select), so the track and arrows rendered but
|
||||
/// the thumb never did, regardless of overflow.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Type11_VerticalScrollbar_SingleSpriteThumbWithNoSliceChildren_SetsThumbSprite()
|
||||
{
|
||||
const uint Thumb = 0x06005A11u;
|
||||
const uint DecrementId = 0x10000071u;
|
||||
const uint IncrementId = 0x10000072u;
|
||||
var decrement = new ElementInfo { Id = DecrementId, Type = 1u, Y = 83f, Width = 37f, Height = 17f };
|
||||
decrement.StateMedia["Normal"] = (0x06004C69u, 1);
|
||||
var increment = new ElementInfo { Id = IncrementId, Type = 1u, Y = 0f, Width = 37f, Height = 17f };
|
||||
increment.StateMedia["Normal"] = (0x06004C6Cu, 1);
|
||||
var thumb = new ElementInfo { Id = 1u, Type = 1u, Width = 37f, Height = 39f };
|
||||
thumb.StateMedia["Normal"] = (Thumb, 1);
|
||||
thumb.StateMedia["Normal_rollover"] = (0x06005A12u, 1);
|
||||
thumb.StateMedia["Normal_pressed"] = (0x06005A13u, 1);
|
||||
thumb.States[1u] = new UiStateInfo { Id = 1u, Name = "Normal", Image = new UiImageMedia(Thumb, 1) };
|
||||
|
||||
var info = new ElementInfo
|
||||
{
|
||||
Type = 11u,
|
||||
Width = 37f,
|
||||
Height = 307f,
|
||||
Children = [decrement, increment, thumb],
|
||||
};
|
||||
var state = new UiStateInfo { Id = UiStateInfo.DirectStateId };
|
||||
state.Properties.Values[0x77u] = new UiPropertyValue
|
||||
{ Kind = UiPropertyKind.Enum, UnsignedValue = IncrementId };
|
||||
state.Properties.Values[0x78u] = new UiPropertyValue
|
||||
{ Kind = UiPropertyKind.Enum, UnsignedValue = DecrementId };
|
||||
info.States[UiStateInfo.DirectStateId] = state;
|
||||
|
||||
var bar = Assert.IsType<UiScrollbar>(DatWidgetFactory.Create(info, NoTex, null));
|
||||
|
||||
Assert.False(bar.Horizontal);
|
||||
Assert.Equal(Thumb, bar.ThumbSprite);
|
||||
Assert.Equal(0u, bar.ThumbTopSprite);
|
||||
Assert.Equal(0u, bar.ThumbBotSprite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Negative companion: a VERTICAL thumb WITH real 3-slice children
|
||||
/// (chat's own shape) is unaffected by the R3-4/R3-7 fallback — the
|
||||
/// `slices.Length == 0` gate never triggers, so ThumbSprite/Top/Bot
|
||||
/// come from the slice children exactly as before.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Type11_VerticalScrollbar_ThumbWithSliceChildren_StillUsesSliceMedia()
|
||||
{
|
||||
const uint Top = 0x06004C60u;
|
||||
const uint Mid = 0x06004C63u;
|
||||
const uint Bot = 0x06004C66u;
|
||||
var decrement = new ElementInfo { Id = 0x10000071u, Type = 1u, Y = 0f, Width = 16f, Height = 16f };
|
||||
decrement.StateMedia["Normal"] = (0x06004C69u, 1);
|
||||
var increment = new ElementInfo { Id = 0x10000072u, Type = 1u, Y = 32f, Width = 16f, Height = 16f };
|
||||
increment.StateMedia["Normal"] = (0x06004C6Cu, 1);
|
||||
var thumb = new ElementInfo { Id = 1u, Type = 1u, Width = 16f, Height = 16f };
|
||||
var topCap = new ElementInfo { Id = 0x10000364u, Type = 3u, Y = 0f, Width = 16f, Height = 3f };
|
||||
topCap.StateMedia["Normal"] = (Top, 1);
|
||||
topCap.States[1u] = new UiStateInfo { Id = 1u, Name = "Normal", Image = new UiImageMedia(Top, 1) };
|
||||
var mid = new ElementInfo { Id = 0x10000365u, Type = 3u, Y = 3f, Width = 16f, Height = 10f };
|
||||
mid.StateMedia["Normal"] = (Mid, 1);
|
||||
mid.States[1u] = new UiStateInfo { Id = 1u, Name = "Normal", Image = new UiImageMedia(Mid, 1) };
|
||||
var botCap = new ElementInfo { Id = 0x10000366u, Type = 3u, Y = 13f, Width = 16f, Height = 3f };
|
||||
botCap.StateMedia["Normal"] = (Bot, 1);
|
||||
botCap.States[1u] = new UiStateInfo { Id = 1u, Name = "Normal", Image = new UiImageMedia(Bot, 1) };
|
||||
thumb.Children.Add(topCap);
|
||||
thumb.Children.Add(mid);
|
||||
thumb.Children.Add(botCap);
|
||||
|
||||
var info = new ElementInfo
|
||||
{
|
||||
Type = 11u,
|
||||
Width = 16f,
|
||||
Height = 73f,
|
||||
Children = [decrement, increment, thumb],
|
||||
};
|
||||
var state = new UiStateInfo { Id = UiStateInfo.DirectStateId };
|
||||
state.Properties.Values[0x77u] = new UiPropertyValue
|
||||
{ Kind = UiPropertyKind.Enum, UnsignedValue = 0x10000072u };
|
||||
state.Properties.Values[0x78u] = new UiPropertyValue
|
||||
{ Kind = UiPropertyKind.Enum, UnsignedValue = 0x10000071u };
|
||||
info.States[UiStateInfo.DirectStateId] = state;
|
||||
|
||||
var bar = Assert.IsType<UiScrollbar>(DatWidgetFactory.Create(info, NoTex, null));
|
||||
|
||||
Assert.False(bar.Horizontal);
|
||||
Assert.Equal(Top, bar.ThumbTopSprite);
|
||||
Assert.Equal(Mid, bar.ThumbSprite);
|
||||
Assert.Equal(Bot, bar.ThumbBotSprite);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetailToolbarFixture_buildsEditableStackEntry_andAuthoredHorizontalSlider()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue