diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index 24fdce8..e1a7248 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -161,7 +161,7 @@ impl<'a> Painter<'a> { Some(hint) => { #[cfg(feature = "layout-diagnostics")] diag::bump(Counter::HintHits); - self.depend_on_size(id, false); + self.depend_on_hint(id); Some(hint) } None => { @@ -203,17 +203,22 @@ impl<'a> Painter<'a> { Some(size) } - fn depend_on_size(&mut self, child: &StrongWidget, inherit_inputs: bool) { - let (box_inputs, output_inputs) = match inherit_inputs { - true => self - .state - .active - .get(&child.id()) - .map_or(([false; 2], [false; 2]), |active| { - (active.size_box_inputs, active.size_output_inputs) - }), - false => ([false; 2], [false; 2]), - }; + /// Depends on a length the child gave without being drawn. A hint is + /// context-free, so this depends on the child but on no pixel axis. + fn depend_on_hint(&mut self, child: &StrongWidget) { + self.depend_on_size_inputs(child, [false; 2], [false; 2]); + } + + /// Depends on a size the child produced by drawing, which carries + /// whatever the child read to produce it. + fn depend_on_drawn_size(&mut self, child: &StrongWidget) { + let (box_inputs, output_inputs) = self + .state + .active + .get(&child.id()) + .map_or(([false; 2], [false; 2]), |active| { + (active.size_box_inputs, active.size_output_inputs) + }); self.depend_on_size_inputs(child, box_inputs, output_inputs); } @@ -351,7 +356,7 @@ impl DrawResult<'_, '_, W> { diag::bump(Counter::SizeReads); diag::size_read(self.child.id(), self.painter.id, self.size); } - self.painter.depend_on_size(self.child, true); + self.painter.depend_on_drawn_size(self.child); self.size } diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 5c52aff..06bc266 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -27,6 +27,9 @@ pub struct UiRenderState { /// content dirtiness, these may retain an answer whose observed pixel /// axes did not change. resize_marks: HashSet, + /// What has already been drawn during the pass under way, so a widget + /// reached by redrawing an ancestor is not drawn again on its own + /// account. Emptied when the pass ends. draw_started: HashSet, /// A widget's move slot, which outlives any one `ActiveData`: a redraw /// replaces that while its children go on pointing at the slot. @@ -138,6 +141,7 @@ impl UiRenderState { self.resized = [false; 2]; self.invalid_sizes.clear(); self.resize_marks.clear(); + self.draw_started.clear(); } fn redraw_all(&mut self, root: Option<&StrongWidget>, rsc: &mut dyn UiRsc) { @@ -574,6 +578,7 @@ impl UiRenderState { self.layers.clear(); self.invalid_sizes.clear(); self.resize_marks.clear(); + self.draw_started.clear(); rsc.widgets_mut().needs_redraw.clear(); rsc.free(); } diff --git a/core/src/widget/mod.rs b/core/src/widget/mod.rs index a702f47..af24f7b 100644 --- a/core/src/widget/mod.rs +++ b/core/src/widget/mod.rs @@ -21,6 +21,9 @@ pub use widgets::*; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum OnResize { Scale, + /// Reserved: nothing reads this yet, so a widget saying it is redrawn. + /// Keeping an unchanged drawing in a bigger box needs the widget to say + /// *where* in that box it should sit, which is the alignment work. Translate, #[default] Redraw,