fix(ui): disabled scrollbars keep retail hover hot-tracking
Owner report + live [ui-hover] probe (2026-08-24): hovering a
content-fits scrollbar did nothing because IsModelDisabled made the
whole bar hit-TRANSPARENT — every hover over it reported
widget=<none>. Retail's arrows and thumb are real child elements whose
Normal_rollover hot-tracking keeps running while the scrollbar is
disabled (UpdateLayout @0x004710d0 only hides the page-click regions,
children 4-7, and — with attribute 0x79 — the whole bar); scrolling
stays inert through geometry, not an input gate: a full-track thumb has
zero travel and the line/page steps clamp against nothing.
OnHitTest and the input path now gate on presentation visibility only.
A visible disabled bar hover-highlights and consumes clicks without
scrolling; a HideWhenDisabled bar stays inert. New root-level hover
tests drive real UiRoot hit-test dispatch (bare widget + the mounted
production character fixture) so this class of "state machine green,
pointer never arrives" bug fails loudly.
User-verified live 2026-08-24 ("bar works now").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8fd3d1a9f0
commit
2d6333f84c
3 changed files with 141 additions and 2 deletions
|
|
@ -208,8 +208,21 @@ public sealed class UiScrollbar : UiElement
|
|||
|
||||
internal bool IsPresentationVisible => !HideWhenDisabled || !IsModelDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// A content-fits (disabled) bar is still hit-testable and still
|
||||
/// hover-highlights — retail's arrows and thumb are real child elements
|
||||
/// whose Normal_rollover hot-tracking keeps running when the scrollbar
|
||||
/// disables; the disabled state only hides the page-click regions
|
||||
/// (UpdateLayout @0x004710d0's children 4-7) and, with attribute 0x79,
|
||||
/// the whole bar. Scrolling input stays inert through geometry: with a
|
||||
/// full-track thumb there is no travel and the line/page steps clamp to
|
||||
/// nothing. The previous IsModelDisabled hit gate made the bar
|
||||
/// hit-TRANSPARENT, which is why hovering it "did nothing" (2026-08-24
|
||||
/// live probe: hovers over the bar reported widget=<none>).
|
||||
/// Only a presentation-hidden bar (0x79 + disabled) ignores the pointer.
|
||||
/// </summary>
|
||||
protected override bool OnHitTest(float localX, float localY)
|
||||
=> !IsModelDisabled && base.OnHitTest(localX, localY);
|
||||
=> IsPresentationVisible && base.OnHitTest(localX, localY);
|
||||
|
||||
/// <summary>
|
||||
/// Computes the thumb rectangle (local y origin and height) within the track area
|
||||
|
|
@ -520,7 +533,11 @@ public sealed class UiScrollbar : UiElement
|
|||
return false; // informational — never consumes
|
||||
}
|
||||
|
||||
if (IsModelDisabled)
|
||||
// Only a presentation-HIDDEN bar ignores input (see OnHitTest's own
|
||||
// doc): a visible disabled bar keeps hover/pressed visuals exactly
|
||||
// like retail's still-hot-tracking button/thumb children, while its
|
||||
// scroll operations no-op through zero travel.
|
||||
if (!IsPresentationVisible)
|
||||
{
|
||||
_draggingThumb = false;
|
||||
_hoveredThumb = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue