pub fn accumulate_wheel(
wheels: MessageReader<'_, '_, MouseWheel>,
hovered: Query<'_, '_, Entity, With<Hovered>>,
parents: Query<'_, '_, &ChildOf>,
children_q: Query<'_, '_, (&ChildOf, &Transform)>,
transforms: Query<'_, '_, &Transform>,
sliders: Query<'_, '_, (), With<SliderValue>>,
scrolls: Query<'_, '_, (Entity, &mut Scroll, &mut ScrollOffset)>,
)Expand description
Accumulate wheel deltas into the ScrollOffset of the innermost
scrollable ancestor of whatever entity the pointer is hovering
that can still scroll in the event’s direction (spec section 16.5).
Why bubbling at all: hit_test picks the deepest candidate under
the cursor (so a tile beats its column container), but the Scroll
component lives on the container, not on the leaf - so we walk the
[ChildOf] chain upward. Nested-scroll routing (Qt propagation
model): the innermost hovered scroll area handles the wheel first;
when it is already at its limit on the event’s direction (or the
event’s axes don’t intersect its allowed ScrollAxis), it does
not consume the event and the next scrollable ancestor gets it.
An inner list pinned at its bottom + wheel-down therefore scrolls
the outer page, while wheel-up still scrolls the inner list.
If no scroll ancestor on the chain can consume the event (every
scroller is pinned at its limit for this direction), the event is
routed to the innermost scroller anyway so overshoot / rubber-band
handling still observes the gesture - clamp_scroll_offsets keeps
the offset in bounds, so this is a visual no-op on hard-clamp
platforms. The cursor being over chrome with no Scroll ancestor
at all keeps the old fallback: the world’s first Scroll entity,
so wheel still does something sensible in single-scroller apps.
Drains the MouseWheel buffer into a local vec first to avoid losing
events during archetype churn (the previous single_mut version did).