iris: one ScrollController, a Scrollable trait, and Pin
Iris's three points on docs/SCROLL.md, in the shape she proposed: a controller both scrolling widgets *contain*, rather than a protocol between them. "I don't like adding methods to widget, it seems like we can structure things better instead." `Scroll` becomes `ScrollArea`, because it only scrolls a predefined area. `ScrollController` holds everything that is not a particular widget's layout -- the position, the pending delta, the travel left each way, the pin, the DragGesture and the Flinger -- and `Scrollable` is the trait over it, one required pair of methods with the rest defaulted. `Widget` loses `scrolls_itself`, `apply_scroll` and `scroll_offset`. They existed only so a `Scroll` could drive a `LazySpan` it had no business wrapping; the span owns its own controller now, so the wrapper, the measure/apply/place dance between two widgets and `amt`'s two meanings all go with them. The transcript's tree loses a node: `list` is the layout and the position. `.scrollable(axis, pin)` replaces `scrollable`/`scrollable_on`/ `scrollable_to_end` -- one mechanism whose arguments had been hidden in three names. `LazySpan` has an inherent `scrollable()` that shadows it, since Rust resolves inherent methods before trait ones: the same word at the call site, and the wrapping version cannot reach the one widget that must not be wrapped. `Pin` says which end either way round: `Start`/`End` are content-relative and `Neg`/`Pos` axis-absolute, so a caller can say "the bottom" and mean it whichever way the content runs. They differ only for a reversed span, which is the whole reason both exist. One behaviour changes: a delta is applied by the next draw rather than where it arrives, since the layout is the only thing that knows where the content ends. Nothing on screen differs -- input is followed by a frame -- but `amt` no longer moves between draws, which several tests were reading. This also closes SCROLL.md's open question about the pin living in two places. Verified: cargo test --workspace (all green, including the layer-1 transcript-fixture fling/selection/top-edge tests), clippy --all-targets clean, fmt clean, `cargo ndk` check of android-app, and `run-headless.sh phone --phone --replay flick-120hz.touch`, whose before/after screenshots show the recorded flick carrying the transcript back from turn 270 to turn 258 on the Vulkan adapter. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bf8658c404
commit
4fdabc39d0
33 files changed
+1725
-1435
No files matched your search
@@ -76,11 +76,12 @@ Module-by-module intent is in `docs/PLAN.md`'s "Backend layout".
|
||||
public API** -- Iris, 2026-09-08), working list, decisions log,
|
||||
layout/render design, and texture-atlas design, and the client-core
|
||||
crate's design, respectively.
|
||||
- `docs/SCROLL.md` — how anything in iris scrolls: `Scroll` owns the
|
||||
position, the gesture and the fling; a child either gets moved or
|
||||
answers `Widget::scrolls_itself` and is handed deltas. Read it before
|
||||
touching `scroll.rs`, `lazy_span.rs`, or anything that pans, flings
|
||||
or lays out a long list.
|
||||
- `docs/SCROLL.md` — how anything in iris scrolls: one
|
||||
`ScrollController` holds the position, the gesture, the fling and the
|
||||
pin, and the two widgets that scroll (`ScrollArea`, `LazySpan`) own
|
||||
one each through the `Scrollable` trait. Read it before touching
|
||||
`scrollable.rs`, `scroll_area.rs`, `lazy_span.rs`, or anything that
|
||||
pans, flings or lays out a long list.
|
||||
- `.dev-updater.ron` — what Dev Updater builds here: the server (run as
|
||||
`service: Managed(…)`, supervised by Dev Updater's own implementation
|
||||
rather than a script kept here) and the APK, in parallel. It points at
|
||||
|
||||
Reference in new issue
Block a user