Return the size from draw, and fold placing back into drawing

Review response.

`Painter::set_size` is gone: `Widget::draw` returns the `Size` instead, so
a widget that does not say what it used cannot compile rather than
panicking at the widget that forgot. That also settles setting it twice --
a branch that learns something late just returns a different value.

`Painter::place` and `UiRenderState::place` are gone too. `draw_inner`
already tried to reuse an active widget's drawing before redrawing it, so
`place` was `widget_within` with its own bookkeeping bolted on; drawing a
child a second time now *is* how a parent puts it where it belongs, and a
child is deduplicated in `children` because listing one twice would move
it twice. The unification also drops `place`'s use of `ActiveData::layer`,
which is the layer a widget's own `child_layer()` left the painter on
rather than the layer it was drawn into.

What `place` did unconditionally and `widget_within` did not is record the
size dependency, so `Painter::size_hint` now records one: reading a
child's length to lay out around it is reading its size, whether it came
from a draw or from a hint. `tests/retained.rs` has a parent that only
ever reads the hint, which is the case no existing widget exercises.

`()` sizes itself `Size::default()` -- rest -- rather than zero, so it is
a gap that takes an even share of a span; `WidgetPtr` with nothing in it
does the same, since it is the same situation. `Widget::on_resize`'s
default body said `Translate` while the enum's `#[default]` said `Redraw`;
it now defers to the enum.

`was` is `old` throughout, the `OnResize` variant comments are gone, and
so are two empty `impl` blocks.

Checked: fmt, clippy and 27 tests across the workspace; `tabs` on each of
its five tabs, and `tabs` with a replay that adds two images, all
byte-identical to `upstream/main`; `view` and `minimal` likewise; and the
`text` example rendered at 1920x1200 and 900x1200 to see the paragraph
reflow and its container follow.
This commit is contained in:
iris-ai committed 2026-09-14 00:39:39 -04:00
1 parent b108645240
commit 9520996623
20 files changed
+143 -151

No files matched your search

+7 -16
View File
@@ -20,25 +20,15 @@ pub use widgets::*;
/// text reads the width it is offered and not the height.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum OnResize {
/// Stretched to the new box, which is all its drawing ever was.
Scale,
/// Carried to the new box at the size it drew, which it keeps.
Translate,
/// Nothing doing: it draws again.
///
/// The default, because it is the only answer that is right without
/// knowing anything about the widget. The other two are claims that the
/// drawing does not change when the box does, and a widget that inherited
/// such a claim by accident would be quietly wrong -- `SetSize` reports
/// one size and hands its child the whole box, so its pixels very much do
/// change.
#[default]
Redraw,
}
pub trait Widget: Any {
/// Draws the widget, and states what it used with `Painter::set_size`.
fn draw(&mut self, painter: &mut Painter);
/// Draws the widget, and returns what it used of the box it was given.
fn draw(&mut self, painter: &mut Painter) -> Size;
/// An exact length the widget can give without a painter or its children.
/// Optional, and saves a draw rather than changing one: a hint that
@@ -48,17 +38,18 @@ pub trait Widget: Any {
}
fn on_resize(&self, _axis: Axis) -> OnResize {
OnResize::Translate
OnResize::default()
}
}
impl Widget for () {
fn draw(&mut self, painter: &mut Painter) {
painter.set_size(Size::ZERO);
/// A gap: nothing drawn, at the default length, so a span gives it a share.
fn draw(&mut self, _: &mut Painter) -> Size {
Size::default()
}
fn size_hint(&self, _axis: Axis) -> Option<Len> {
Some(Len::ZERO)
Some(Len::default())
}
fn on_resize(&self, _axis: Axis) -> OnResize {