Say what a leftover means where nothing divides it

Bryan's rule, generalising the max he gave for Scroll's content length on
2026-09-18: a leftover under a parent that does not divide is still a leftover
and acts as a minimum, so the length is max(box, px + rel*box) -- it fills the
rest where the fixed parts are shorter and overflows where they are longer.

Measured against a span, which implements it, and against the non-dividing path,
which drops the overflow in the one row where the fixed part is longer than the
box. Recorded with the cause and the window contract a fix needs; not fixed,
because what a length means is Bryan's to settle and nothing here mixes the two
outside the span's own test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-20 04:09:27 -04:00
1 parent 8adad924b9
commit da6b003a1e
2 files changed
+45

No files matched your search

+6
View File
@@ -177,6 +177,12 @@ glyphs do not follow a shortened entry.
other layout system does that; confirm it is wanted.
- A span can overflow itself without bound, so boxes of negative length reach
children and nothing states what a widget may assume about one.
- A `leftover` under a parent that does not divide is a minimum size --
`max(box, px + rel*box)` (Bryan, 2026-09-20). A span does that; the
non-dividing path drops the overflow where the fixed part is longer than
the box. Measured in `docs/LAYOUT_LOG.md` under the ninth sweep, with the
window contract a fix needs. Nothing here mixes the two, so nothing is
wrong on screen.
- `Fixed::div` by zero answers `MIN`/`MAX` while `ratio` answers `ZERO`; both
are caller bugs under `debug_assert`, but the fallbacks differ.
- `docs/LAYOUT.md` §4, §5 and the density section name `Painter::place`,
+39
View File
@@ -37,6 +37,45 @@ either way at `77ed7a2`. The alternative reading -- a hint narrows even under a
share rule -- would mean changing that comment instead, and is Bryan's to
prefer if he does.
**What a leftover means where nothing divides it** (Bryan, 2026-09-20, on the
finding above). A leftover under a parent that does not divide is still a
leftover, acting as a minimum: where the `px` and `rel` parts come to less than
the box it fills the rest, and where they come to more they overflow as normal.
The length is `max(box, px + rel*box)` -- which is the same `max` he gave for
`Scroll`'s content length on 2026-09-18, generalised to every non-dividing
parent.
Measured at `c2b8bf8`, a probe recording the box it is asked in, in a 400 px
window, under `.wrapper()` against a one-child span:
rule nothing divides a span divides
leftover(1) 400 400
px(50) + leftover(1) 400 400
px(500) + leftover(1) 400 500
rel(0.5) + leftover(1) 400 400
px(500), no leftover 500 500
One row disagrees. A leftover whose fixed part is longer than the box loses the
overflow where nothing divides it. The span is right and says so in place --
"One that also asked for pixels or a fraction keeps those and overflows" -- and
`only_a_pure_leftover_child_disappears_when_nothing_is_left` asserts it at
100..120 of a 100 px row. The cause is that `LayoutLen::declared` refuses to
answer for anything carrying leftover weight, so the non-dividing path never
learns the fixed part and falls back to the offer. The same length without the
share does overflow (drawn -50..450, its alignment centring it), so what
swallows it is the share and not the overflow.
Fixing it means answering the longer of the offer and the fixed part, which is
not a `Len`: a maximum of two linear forms is not linear in the box, so it has
to be resolved where the box is known and the crossover pinned as a window
contract -- which is exactly what `Span` does with `has_room` and
`painter.window_holds(axis, holds.through(room))`. In `widget_at` that range
belongs to the parent, whose box decides it, so a parent of such a child would
redraw across the crossover. **Not done: it is what a length means, and it is
Bryan's to say whether that cost is wanted.** Nothing in the repository mixes
`px` or `rel` with `leftover` outside the span's own test, so nothing is wrong
on screen today.
**Marking a widget for redraw had no name.** Twenty-one sites under `tests/`
said it as `widgets_mut().get_dyn_mut(id);` with the widget thrown away: five
with a `let _ =` in front, one with a comment explaining what the line was for