Size a widget while drawing it, not in a pass of its own
`desired_width`/`desired_height`, `WidgetAxisFns`, `SizeCtx` and the size cache are gone. A widget states what it used with `Painter::set_size` while it draws, and `Painter::widget` hands back a `DrawResult` whose `size()` both reads the child and records that this widget's size depends on it. Reading nothing keeps the parent independent of what the child came to. `Span` is what the change is for. It takes each child's `size_hint` where there is one, draws only the children that cannot answer, allocates the flexible space, then places everything -- which deletes `desired_ortho`, whose own comment said it "literally copies draw ... which makes this slow and not cool". Invalidation follows the dependency edges the draw recorded: a widget that needs redrawing hands off to the highest ancestor that read its size, instead of re-running a measurement to find out whether anything changed. `Widget::size_dependence(axis)` says how much of its box a widget's drawing depends on -- none of it, its own extent, or the whole box -- so the retained path can keep a drawing and write a new box into it. Asked per axis, because wrapped text depends on the width it is offered and not on the height. `Internal` does not yet buy more than `External`: keeping a drawing when only the room around it changed is a translation, which waits for the move chain. `tests/retained.rs` covers the second frame rather than the first, which is where the bugs were: a placed child that was not recorded as one got pruned as departed on the next draw. `examples/text.rs` is new, since wrapping was the one thing here with no way to see it on its own.
This commit is contained in:
1 parent
43ce8c7d02
commit
f192f75b25
24 files changed
+610
-523
No files matched your search
+35
-18
@@ -1,4 +1,4 @@
|
||||
use crate::{Axis, AxisT, Len, Painter, SizeCtx};
|
||||
use crate::{Axis, Len, Painter, Size};
|
||||
use std::any::Any;
|
||||
|
||||
mod data;
|
||||
@@ -15,32 +15,49 @@ pub use tag::*;
|
||||
pub use view::*;
|
||||
pub use widgets::*;
|
||||
|
||||
/// How much of the box a widget was handed its drawing depends on, and so
|
||||
/// what has to change before it must be drawn again. Asked per axis, because
|
||||
/// wrapped text depends on the width it is offered and not on the height.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum SizeDependence {
|
||||
/// None of it: the box only says where the primitives go, so a new one is
|
||||
/// written into them instead of drawn.
|
||||
None,
|
||||
/// Its own extent, whatever box that sits in. Reusable in any box that
|
||||
/// leaves that extent unchanged, including a larger one it does not fill.
|
||||
#[default]
|
||||
Internal,
|
||||
/// The extent of the box itself, used or not.
|
||||
External,
|
||||
}
|
||||
|
||||
pub trait Widget: Any {
|
||||
/// Draws the widget, and states what it used with `Painter::set_size`.
|
||||
fn draw(&mut self, painter: &mut Painter);
|
||||
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||
}
|
||||
|
||||
pub trait WidgetAxisFns {
|
||||
fn desired_len<A: AxisT>(&mut self, ctx: &mut SizeCtx) -> Len;
|
||||
}
|
||||
/// 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
|
||||
/// disagrees with the eventual draw fails a debug assertion.
|
||||
fn size_hint(&self, _axis: Axis) -> Option<Len> {
|
||||
None
|
||||
}
|
||||
|
||||
impl<W: Widget + ?Sized> WidgetAxisFns for W {
|
||||
fn desired_len<A: AxisT>(&mut self, ctx: &mut SizeCtx) -> Len {
|
||||
match A::get() {
|
||||
Axis::X => self.desired_width(ctx),
|
||||
Axis::Y => self.desired_height(ctx),
|
||||
}
|
||||
fn size_dependence(&self, _axis: Axis) -> SizeDependence {
|
||||
SizeDependence::Internal
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for () {
|
||||
fn draw(&mut self, _: &mut Painter) {}
|
||||
fn desired_width(&mut self, _: &mut SizeCtx) -> Len {
|
||||
Len::ZERO
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
painter.set_size(Size::ZERO);
|
||||
}
|
||||
fn desired_height(&mut self, _: &mut SizeCtx) -> Len {
|
||||
Len::ZERO
|
||||
|
||||
fn size_hint(&self, _axis: Axis) -> Option<Len> {
|
||||
Some(Len::ZERO)
|
||||
}
|
||||
|
||||
fn size_dependence(&self, _axis: Axis) -> SizeDependence {
|
||||
SizeDependence::None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user