diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 9160c3b..531fa26 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -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`, diff --git a/docs/LAYOUT_LOG.md b/docs/LAYOUT_LOG.md index f2b3988..73f92da 100644 --- a/docs/LAYOUT_LOG.md +++ b/docs/LAYOUT_LOG.md @@ -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