Owner report (2026-08-24): our scrollbar arrows pointed the wrong way, the thumb vanished when there was nothing to scroll, and neither the thumb nor the arrow buttons reacted to hover/press. All three are one retail mechanism we had not ported: 1. Seating: UIElement_Scrollbar::UpdateScrollingArea @0x00470AA0 moves the INCREMENT designee (attribute 0x77) to the top/left corner and the DECREMENT designee (0x78) to the bottom/right, ignoring authored positions. The vertical base skin (0x10000455 in layout 0x2100003E) authors the DOWN-arrow decrement at Y=0 and the UP-arrow increment at Y=32 (live-DAT probed; sprite art visually verified from decoded PNGs), so our authored-Y ordering drew both arrows upside down. DatWidgetFactory now seats by designation; the hand-wired sites (CharacterStatController, ExternalContainerController, the Config/Vendor menu chrome) share the new RetailScrollbarChrome catalog instead of local constants. 2. Full-track thumb: UpdateLayout @0x004710d0 sizes the thumb from proportion attribute 0x88, which DEFAULTS to 1.0 — a content-fits bar shows a thumb filling the whole track; disabled only removes input and the page regions. Our draw skipped the thumb entirely on !HasOverflow. 3. States: every arrow button and thumb slice authors Normal (red gem / dark navy), Normal_rollover (amber gem / bright blue) and Normal_pressed (gold highlight / dark) media. The widget now tracks thumb hover and selects rollover media on hover and pressed media while dragging; the factory extracts the thumb-state media for both the 3-slice and single-sprite thumb shapes. ScrollbarSkinLiveDatTests pins the designations and state media against the installed DAT so a revision or importer regression fails loudly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
108 lines
5.1 KiB
C#
108 lines
5.1 KiB
C#
namespace AcDream.App.UI;
|
|
|
|
/// <summary>
|
|
/// The base scrollbar skin from LayoutDesc <c>0x2100003E</c>, seated the way
|
|
/// retail seats it at runtime. <c>UIElement_Scrollbar::UpdateScrollingArea
|
|
/// @0x00470AA0</c> ignores the buttons' authored positions: it moves the
|
|
/// INCREMENT button (attribute <c>0x77</c>) to the top/left corner
|
|
/// (<c>MoveTo(0,0)</c>) and the DECREMENT button (attribute <c>0x78</c>) to
|
|
/// the bottom/right corner. The vertical skin (element <c>0x10000455</c>)
|
|
/// designates <c>0x77=0x10000072</c> (the UP-arrow art, authored at Y=32)
|
|
/// and <c>0x78=0x10000071</c> (the DOWN-arrow art, authored at Y=0) — so
|
|
/// seating by authored Y renders both arrows upside down (the 2026-08-24
|
|
/// owner report). Each button and thumb slice authors three states:
|
|
/// Normal (red center gem / dark navy thumb), Normal_rollover (amber gem /
|
|
/// bright blue thumb), Normal_pressed (gold highlight gem / dark thumb) —
|
|
/// all live-DAT probed 2026-08-24.
|
|
/// </summary>
|
|
internal static class RetailScrollbarChrome
|
|
{
|
|
// ── Vertical skin (element 0x10000455, 16 px) ────────────────────────
|
|
internal const uint Track = 0x06004C5Fu;
|
|
|
|
/// <summary>Top button = the INCREMENT designee 0x10000072 (up arrow).</summary>
|
|
internal const uint UpNormal = 0x06004C6Cu;
|
|
internal const uint UpRollover = 0x06004C6Du;
|
|
internal const uint UpPressed = 0x06004C6Eu;
|
|
|
|
/// <summary>Bottom button = the DECREMENT designee 0x10000071 (down arrow).</summary>
|
|
internal const uint DownNormal = 0x06004C69u;
|
|
internal const uint DownRollover = 0x06004C6Au;
|
|
internal const uint DownPressed = 0x06004C6Bu;
|
|
|
|
internal const uint ThumbTopNormal = 0x06004C60u;
|
|
internal const uint ThumbTopRollover = 0x06004C61u;
|
|
internal const uint ThumbTopPressed = 0x06004C62u;
|
|
internal const uint ThumbMidNormal = 0x06004C63u;
|
|
internal const uint ThumbMidRollover = 0x06004C64u;
|
|
internal const uint ThumbMidPressed = 0x06004C65u;
|
|
internal const uint ThumbBotNormal = 0x06004C66u;
|
|
internal const uint ThumbBotRollover = 0x06004C67u;
|
|
internal const uint ThumbBotPressed = 0x06004C68u;
|
|
|
|
// ── Horizontal skin (element 0x1000036D, 16 px) ──────────────────────
|
|
internal const uint HTrack = 0x06004C7Fu;
|
|
|
|
/// <summary>Left button = the INCREMENT designee 0x1000036C.</summary>
|
|
internal const uint LeftNormal = 0x06004C8Cu;
|
|
internal const uint LeftRollover = 0x06004C8Du;
|
|
internal const uint LeftPressed = 0x06004C8Eu;
|
|
|
|
/// <summary>Right button = the DECREMENT designee 0x1000036B.</summary>
|
|
internal const uint RightNormal = 0x06004C89u;
|
|
internal const uint RightRollover = 0x06004C8Au;
|
|
internal const uint RightPressed = 0x06004C8Bu;
|
|
|
|
internal const uint HThumbTopNormal = 0x06004C80u;
|
|
internal const uint HThumbTopRollover = 0x06004C81u;
|
|
internal const uint HThumbTopPressed = 0x06004C82u;
|
|
internal const uint HThumbMidNormal = 0x06004C83u;
|
|
internal const uint HThumbMidRollover = 0x06004C84u;
|
|
internal const uint HThumbMidPressed = 0x06004C85u;
|
|
internal const uint HThumbBotNormal = 0x06004C86u;
|
|
internal const uint HThumbBotRollover = 0x06004C87u;
|
|
internal const uint HThumbBotPressed = 0x06004C88u;
|
|
|
|
/// <summary>Wires the full retail vertical skin onto <paramref name="bar"/>.</summary>
|
|
internal static void ApplyVertical(UiScrollbar bar)
|
|
{
|
|
bar.TrackSprite = Track;
|
|
bar.UpSprite = UpNormal;
|
|
bar.UpRolloverSprite = UpRollover;
|
|
bar.UpPressedSprite = UpPressed;
|
|
bar.DownSprite = DownNormal;
|
|
bar.DownRolloverSprite = DownRollover;
|
|
bar.DownPressedSprite = DownPressed;
|
|
bar.ThumbTopSprite = ThumbTopNormal;
|
|
bar.ThumbTopRolloverSprite = ThumbTopRollover;
|
|
bar.ThumbTopPressedSprite = ThumbTopPressed;
|
|
bar.ThumbSprite = ThumbMidNormal;
|
|
bar.ThumbRolloverSprite = ThumbMidRollover;
|
|
bar.ThumbPressedSprite = ThumbMidPressed;
|
|
bar.ThumbBotSprite = ThumbBotNormal;
|
|
bar.ThumbBotRolloverSprite = ThumbBotRollover;
|
|
bar.ThumbBotPressedSprite = ThumbBotPressed;
|
|
}
|
|
|
|
/// <summary>Wires the full retail horizontal skin onto <paramref name="bar"/>.
|
|
/// The leading (<see cref="UiScrollbar.UpSprite"/>) slot is the LEFT edge.</summary>
|
|
internal static void ApplyHorizontal(UiScrollbar bar)
|
|
{
|
|
bar.TrackSprite = HTrack;
|
|
bar.UpSprite = LeftNormal;
|
|
bar.UpRolloverSprite = LeftRollover;
|
|
bar.UpPressedSprite = LeftPressed;
|
|
bar.DownSprite = RightNormal;
|
|
bar.DownRolloverSprite = RightRollover;
|
|
bar.DownPressedSprite = RightPressed;
|
|
bar.ThumbTopSprite = HThumbTopNormal;
|
|
bar.ThumbTopRolloverSprite = HThumbTopRollover;
|
|
bar.ThumbTopPressedSprite = HThumbTopPressed;
|
|
bar.ThumbSprite = HThumbMidNormal;
|
|
bar.ThumbRolloverSprite = HThumbMidRollover;
|
|
bar.ThumbPressedSprite = HThumbMidPressed;
|
|
bar.ThumbBotSprite = HThumbBotNormal;
|
|
bar.ThumbBotRolloverSprite = HThumbBotRollover;
|
|
bar.ThumbBotPressedSprite = HThumbBotPressed;
|
|
}
|
|
}
|