iris: a scroll delta's sign is a screen direction, not a logical one

Positive scrolls the reader up or left and negative down or right,
whichever way the widget receiving it lays its content out (Iris,
2026-09-08: "that way it always works as the user would expect").

`LazySpan` took the delta straight into the direction-relative space its
walk works in, so a `Dir::UP` span -- whose later content is *above* --
panned the opposite way from every other scrollable in iris for the same
number. `flip_delta` is the conversion, the counterpart of the `flip_pos`
that positions already went through, and the two places that meet the
outside world (`apply_scroll` and `moved`) are the only ones that use it.

Nothing built a `Dir::UP` span yet, so this was latent; the existing sign
test could not have found it either, since it asserts in the walk's own
space where both halves agree with each other while disagreeing with the
screen. The new test compares the two `dir`s against where rows were
actually drawn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-08 21:32:30 -04:00
1 parent 00e0a63887
commit bf8658c404
4 files changed
+150 -35

No files matched your search

+21 -10
View File
@@ -23,20 +23,31 @@ was just removed.
## One convention for a delta
**Positive moves the content the positive way along the axis — the
finger's direction — which brings *earlier* content into view.**
**Positive scrolls the reader up or left; negative down or right.** The
content's pixels therefore move the positive way along the axis for a
positive delta — the finger's direction — and that is `Scroll::scroll`'s
sign, `Scroll::fling`'s, and `Widget::apply_scroll`'s, from the gesture
all the way down to a row's anchor.
That is `Scroll::scroll`'s sign, `Scroll::fling`'s, and
`Widget::apply_scroll`'s. It holds from the gesture all the way down to a
row's anchor. `LazySpan`'s internal `scroll` runs the other way (its
anchor offset says where the pinned edge *sits*), and it is private, with
the single negation inside its `apply_scroll`.
**It is a screen direction, not a logical one** (Iris, 2026-09-08:
"positive should always scroll up / left, and negative down / right ...
that way it always works as the user would expect"). The earlier wording
— "positive brings *earlier* content into view" — is true only of a span
laid out forwards: a `Dir::UP` list's earlier content is *below*, so the
same delta panned it the opposite way from every other scrollable in
iris. `LazySpan::flip_delta` is the conversion into the walk's own
direction-relative space, the exact counterpart of `flip_pos` for
positions, and its `scroll` (private) is the only thing that speaks that
space.
There used to be two public conventions under the same name, and every
call site had to know which widget it was talking to. If you add a third
scrolling thing, it takes the finger's. `a_negative_delta_moves_toward_
the_end` (in `lazy_span.rs`) pins this across the whole handoff, because
nothing else can catch a list scrolling backwards.
scrolling thing, it takes this one. Two tests pin it, and neither is
redundant: `a_negative_delta_moves_toward_the_end` follows the sign
across the whole handoff, and `a_delta_moves_both_directions_the_same_
way_on_screen` checks the two `dir`s against **where rows were drawn**
an assertion written in the walk's own space passes with the flip
deleted, because it checks the bookkeeping against itself.
## The `Widget` handoff