iris: List becomes LazySpan, and takes a Dir
First of three steps agreed with Iris for getting scrolling out of the list and into `Scroll`, so that `.scrollable()` is the one way anything in iris scrolls. docs/IRIS_TODO.md's "In progress" block carries the whole plan and the decisions behind it; this step is the rename and the direction. `List` -> `LazySpan`, and it moves in beside `Span` under `widget/position/`. It is what `Span` is -- a sequence of children along an axis -- laid out lazily from an anchor instead of eagerly from the start, and the name says the one thing that matters about it. It also stops colliding with `BlockKind::List` in the markdown code. `ListRow` -> `LazyItem`; `RowKey` keeps its name, since rows are the vocabulary in transcript-ui. `Axis` -> `Dir`, with the sign meaning what it means in `Span`: which end of the box item 0 sits at. **That is a different question from which end the view is pinned to**, and conflating them would stand a transcript on its head -- its oldest message is item 0 and sits at the top (`Dir::DOWN`) while the view clings to the bottom. So the pin is its own constructor argument, `LazySpan::new(dir, at_end)`, spelled the same way as `Scroll::new`'s. Making `Dir::UP` real rather than nominal is most of the diff. The walk now works entirely in direction-relative pixels from the leading edge -- `Edge::Top`/`Bottom` are `Leading`/`Trailing`, `Placement` likewise, and `RowExtent`'s fields and every local are `lead`/`trail` -- with two places converting: `abs_region`, which flips the box for `Sign::Neg`, and `flip_pos`, which converts the screen-space positions the public helpers speak in (`note_tap`, `key_at`, `extent`, all fed by pointer events) into the walk's space. Without the second, a reversed span would hit-test at the mirror of where it drew. `a_dir_up_span_grows_upward_from_item_zero` asserts on where each row was **actually drawn** (`UiRenderState::active`), not on `extents`: the first version of it read `extent()` and passed with `abs_region`'s flip deleted -- checking the bookkeeping against itself while every row painted at the mirror of where it belonged. It now fails with the flip removed (row 2 at 80..100 instead of 0..20), which is the check that matters. Verified: cargo fmt --check, clippy --workspace --all-targets clean, cargo test --workspace green (21 suites), including the phone-shaped fixture tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
76fcbdccb9
commit
8e5928cc6a
30 files changed
+526
-329
No files matched your search
+3
-3
@@ -883,7 +883,7 @@ set once from `DisplayMetrics.density` in `android::view::new_peer`; the
|
||||
desktop backend has no per-monitor density wired up yet and stays at
|
||||
`1.0`. Every layout call site that used to call `.apply_rest()`/
|
||||
`.to_uivec2()` now passes `painter.density()` (nine call sites — `Span`,
|
||||
`Sized`, `MaxSize`, `Aligned`, `Scroll`, `List::place`, and
|
||||
`Sized`, `MaxSize`, `Aligned`, `Scroll`, `LazySpan::place`, and
|
||||
`UiRenderState::reposition` itself). This also meant the Android
|
||||
boundary's global logical-space stopgap could come out entirely: window
|
||||
size, touch coordinates and insets are physical pixels again, matching
|
||||
@@ -1095,7 +1095,7 @@ cost of a tool group's 4dp inset).
|
||||
|
||||
**A widget offered a box it does not fit is drawn again at the box its
|
||||
own reported size implies, in the same frame.** Not next frame. The
|
||||
temptation to defer is real — `List::place` offers a row its *cached*
|
||||
temptation to defer is real — `LazySpan::place` offers a row its *cached*
|
||||
height precisely so that an unchanged row hits `draw_inner`'s cheap
|
||||
skip-or-move path, and `Scroll` sizes its child region from last frame's
|
||||
content length for the same reason. But a `Rect` fills whatever region it
|
||||
@@ -1112,5 +1112,5 @@ safe to apply everywhere: the second draw happens only on the frame a
|
||||
widget's own size actually changes, which is a frame that was already
|
||||
redrawing it. A widget whose reported size is a function of the box it
|
||||
was *offered* would disagree every frame and redraw every frame — which
|
||||
is why `List` requires content-sized rows, and has since long before
|
||||
is why `LazySpan` requires content-sized rows, and has since long before
|
||||
this.
|
||||
Reference in new issue
Block a user