diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 7ae756c..62c64c9 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -1,5 +1,5 @@ use crate::{ - ActiveData, Axis, DrawLayers, IdLike, MaskIdx, Painter, PixelRegion, Size, SizeDependence, + ActiveData, Axis, DrawLayers, IdLike, MaskIdx, OnResize, Painter, PixelRegion, Size, StrongWidget, UiRegion, UiRsc, WidgetId, Widgets, util::{HashMap, HashSet, Vec2, forget_ref}, }; @@ -93,6 +93,7 @@ impl UiRenderState { } // draw widget + rsc.widgets_mut().needs_redraw.remove(&id); self.draw_started.insert(id); let mut painter = Painter { @@ -202,7 +203,7 @@ impl UiRenderState { return Some(size); } if self.reusable(id, region, rsc) { - // Its drawing stands; the box is written into the primitives. + // Its drawing stands; the new box is remapped into the primitives. self.mov(id, was, region); return Some(size); } @@ -223,12 +224,15 @@ impl UiRenderState { [Axis::X, Axis::Y].into_iter().all(|axis| { let offered = region.axis_mut(axis).len(); let had = was.axis_mut(axis).len(); - match widget.size_dependence(axis) { - SizeDependence::None => true, - // `Internal` could also keep its drawing when only the room - // around it changed, but that is a translation rather than a - // remap, so it waits for the move chain. - SizeDependence::Internal | SizeDependence::External => offered == had, + match widget.on_resize(axis) { + OnResize::Scale => true, + // `Translate` is not acted on yet, and cannot be until a + // drawing can sit somewhere other than its box. `region` is + // both the box a widget was given and the box its primitives + // are in, and `mov` remaps from it -- so carrying a drawing at + // its old size while the box grows makes the next move stretch + // it. The offset chain is what separates the two. + OnResize::Translate | OnResize::Redraw => offered == had, } }) } @@ -350,14 +354,19 @@ impl UiRenderState { /// redraws a widget that's currently active (drawn) pub fn redraw(&mut self, id: WidgetId, rsc: &mut dyn UiRsc) { - rsc.widgets_mut().needs_redraw.remove(&id); self.draw_started.remove(&id); // Whoever read this widget's size may be a different size now, so the - // highest reader is what draws; it reaches this one on the way down. + // highest reader is what draws; it reaches this one on the way down, + // where the mark is what stops it being reused as it stands. Clearing + // it here would hide the change from the draw that came to apply it. if let Some(top) = self.highest_reader(id) { self.redraw(top, rsc); + // Cleared by that draw if it reached here; if it did not, this is + // no longer drawn and asking again would not end. + rsc.widgets_mut().needs_redraw.remove(&id); return; } + rsc.widgets_mut().needs_redraw.remove(&id); if self.draw_started.contains(&id) { return; diff --git a/core/src/widget/mod.rs b/core/src/widget/mod.rs index f7b72aa..d821147 100644 --- a/core/src/widget/mod.rs +++ b/core/src/widget/mod.rs @@ -15,20 +15,25 @@ 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. +/// What may be done to a widget's drawing when the box it was given changes +/// on this axis, instead of drawing it again. Asked per axis, because wrapped +/// text reads the width it is offered and not 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. +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] - Internal, - /// The extent of the box itself, used or not. - External, + Redraw, } pub trait Widget: Any { @@ -42,8 +47,8 @@ pub trait Widget: Any { None } - fn size_dependence(&self, _axis: Axis) -> SizeDependence { - SizeDependence::Internal + fn on_resize(&self, _axis: Axis) -> OnResize { + OnResize::Translate } } @@ -56,8 +61,8 @@ impl Widget for () { Some(Len::ZERO) } - fn size_dependence(&self, _axis: Axis) -> SizeDependence { - SizeDependence::None + fn on_resize(&self, _axis: Axis) -> OnResize { + OnResize::Scale } } diff --git a/src/widget/image.rs b/src/widget/image.rs index 84620e8..5c0d991 100644 --- a/src/widget/image.rs +++ b/src/widget/image.rs @@ -15,8 +15,8 @@ impl Widget for Image { Some(Len::abs(self.handle.size().axis(axis))) } - fn size_dependence(&self, _: Axis) -> SizeDependence { - SizeDependence::None + fn on_resize(&self, _: Axis) -> OnResize { + OnResize::Scale } } diff --git a/src/widget/mask.rs b/src/widget/mask.rs index 27f014b..7cf3633 100644 --- a/src/widget/mask.rs +++ b/src/widget/mask.rs @@ -12,7 +12,7 @@ impl Widget for Masked { } /// It clips to the box it was given, not to the part its child used. - fn size_dependence(&self, _: Axis) -> SizeDependence { - SizeDependence::External + fn on_resize(&self, _: Axis) -> OnResize { + OnResize::Redraw } } diff --git a/src/widget/rect.rs b/src/widget/rect.rs index f139ae8..995456a 100644 --- a/src/widget/rect.rs +++ b/src/widget/rect.rs @@ -43,8 +43,8 @@ impl Widget for Rect { } /// Its box is its primitive's own region, so a new one is written there. - fn size_dependence(&self, _: Axis) -> SizeDependence { - SizeDependence::None + fn on_resize(&self, _: Axis) -> OnResize { + OnResize::Scale } } diff --git a/src/widget/text/edit.rs b/src/widget/text/edit.rs index 55f9599..299946c 100644 --- a/src/widget/text/edit.rs +++ b/src/widget/text/edit.rs @@ -88,8 +88,8 @@ impl Widget for TextEdit { ); } - fn size_dependence(&self, axis: Axis) -> SizeDependence { - self.view.size_dependence(axis) + fn on_resize(&self, axis: Axis) -> OnResize { + self.view.on_resize(axis) } } diff --git a/src/widget/text/mod.rs b/src/widget/text/mod.rs index 08208d0..ca04fa2 100644 --- a/src/widget/text/mod.rs +++ b/src/widget/text/mod.rs @@ -93,15 +93,15 @@ impl TextView { /// a taller one does not. Alignment matters too, and separately: glyphs /// anchored to the start of an axis stay put when that extent changes, /// but centred or end-aligned ones move even though the shaping stands. - pub fn size_dependence(&self, axis: Axis) -> SizeDependence { + pub fn on_resize(&self, axis: Axis) -> OnResize { let reshapes = axis == Axis::X && self.attrs.wrap; let anchored = match axis { Axis::X => self.align.x, Axis::Y => self.align.y, } == AxisAlign::Neg; match reshapes || !anchored { - true => SizeDependence::External, - false => SizeDependence::Internal, + true => OnResize::Redraw, + false => OnResize::Translate, } } @@ -133,8 +133,8 @@ impl Widget for Text { painter.set_size(size); } - fn size_dependence(&self, axis: Axis) -> SizeDependence { - self.view.size_dependence(axis) + fn on_resize(&self, axis: Axis) -> OnResize { + self.view.on_resize(axis) } } diff --git a/tests/retained.rs b/tests/retained.rs index 3f306df..84db42e 100644 --- a/tests/retained.rs +++ b/tests/retained.rs @@ -10,7 +10,7 @@ use iris::prelude::*; struct Counted { draws: Rc>, size: Size, - dependence: SizeDependence, + dependence: OnResize, } impl Widget for Counted { @@ -19,7 +19,7 @@ impl Widget for Counted { painter.set_size(self.size); } - fn size_dependence(&self, _: Axis) -> SizeDependence { + fn on_resize(&self, _: Axis) -> OnResize { self.dependence } } @@ -32,11 +32,7 @@ impl Counts { } } -fn counted( - h: &mut Harness, - size: Size, - dependence: SizeDependence, -) -> (WeakWidget, Counts) { +fn counted(h: &mut Harness, size: Size, dependence: OnResize) -> (WeakWidget, Counts) { let draws = Rc::new(Cell::new(0)); let id = Counted { draws: draws.clone(), @@ -49,8 +45,8 @@ fn counted( /// A fixed-width leaf beside one that takes the rest, so changing the first /// hands the second a different box without the output changing. -fn pair(h: &mut Harness, rest: SizeDependence) -> (WeakWidget, Counts, WidgetId) { - let (first, _) = counted(h, Size::from((100, 200)), SizeDependence::Internal); +fn pair(h: &mut Harness, rest: OnResize) -> (WeakWidget, Counts, WidgetId) { + let (first, _) = counted(h, Size::from((100, 200)), OnResize::Translate); let (second, draws) = counted(h, Size::REST, rest); h.set_root((first, second).span(Dir::RIGHT)); (first, draws, second.id()) @@ -59,7 +55,7 @@ fn pair(h: &mut Harness, rest: SizeDependence) -> (WeakWidget, Counts, #[test] fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() { let mut h = Harness::new((400, 200)); - let (first, draws, second) = pair(&mut h, SizeDependence::None); + let (first, draws, second) = pair(&mut h, OnResize::Scale); let settled = draws.get(); assert_corners!(h, second, (100, 0), (400, 200)); @@ -77,7 +73,7 @@ fn a_leaf_that_ignores_its_box_is_not_drawn_again_when_the_box_changes() { #[test] fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() { let mut h = Harness::new((400, 200)); - let (first, draws, second) = pair(&mut h, SizeDependence::External); + let (first, draws, second) = pair(&mut h, OnResize::Redraw); let settled = draws.get(); h.rsc[first].size = Size::from((150, 200)); @@ -93,8 +89,8 @@ fn a_leaf_that_depends_on_its_box_is_drawn_again_when_the_box_changes() { #[test] fn a_span_child_that_declares_its_length_is_drawn_once() { let mut h = Harness::new((400, 200)); - let (told, told_draws) = counted(&mut h, Size::from((100, 200)), SizeDependence::Internal); - let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), SizeDependence::Internal); + let (told, told_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate); + let (asked, asked_draws) = counted(&mut h, Size::from((100, 200)), OnResize::Translate); // The span takes one child's length from its hint and has to draw the // other to find out, so only the second is drawn before it is placed. let hinted = told.width(100).add(&mut h.rsc); @@ -111,7 +107,7 @@ fn a_span_child_that_declares_its_length_is_drawn_once() { #[test] fn a_span_relays_out_when_a_child_it_measured_changes() { let mut h = Harness::new((400, 200)); - let (first, _, second) = pair(&mut h, SizeDependence::Internal); + let (first, _, second) = pair(&mut h, OnResize::Translate); h.rsc[first].size = Size::from((250, 200)); h.frame();