//! A measurement that decides control flow. //! //! Comparing boxes catches a widget that moved. It does not catch a widget //! that measured a child, believed a different answer from the one a cold //! start would give, and took the other branch -- which is the same defect //! arriving somewhere it cannot be ignored. A widget here branches on what it //! measured, so a disagreement shows up as a different tree. use iris::harness::Harness; use iris::prelude::*; /// Measures `probe` across `axis` and draws one of two children on the /// answer. Its own configuration never changes, so which child is drawn is a /// property of the layout alone. struct BranchesOnMeasurement { probe: StrongWidget, wide: StrongWidget, narrow: StrongWidget, threshold: f32, } impl Widget for BranchesOnMeasurement { fn draw(&mut self, painter: &mut Painter) -> Size { let cut = Len::from_parts(Rel::ZERO, Px::from_int(40)); let top = Place::Within(Part::From(UiSpan::new(Len::ZERO, cut))); let measured = painter .widget_at(&self.probe, [None; 2], [Place::Within(Part::All), top]) .len(Axis::X); let px = painter.to_px(measured.apply_leftover(), Axis::X); let below = Place::Within(Part::From(UiSpan::new(cut, painter.region_len(Axis::Y)))); let place = [Place::Within(Part::All), below]; match px > Px::from_f32(self.threshold) { true => painter.widget_at(&self.wide, [None; 2], place), false => painter.widget_at(&self.narrow, [None; 2], place), }; Size::LEFTOVER } } fn plant(h: &mut Harness, threshold: f32) -> (WidgetId, WidgetId) { let words = "the quick brown fox jumps over the lazy dog and keeps running"; let probe = wtext(words).size(16).wrap(true).add(&mut h.rsc); let wide = rect(Color::RED).add(&mut h.rsc); let narrow = rect(Color::BLUE).add(&mut h.rsc); let branch = BranchesOnMeasurement { probe: probe.add_strong(&mut h.rsc), wide: wide.add_strong(&mut h.rsc), narrow: narrow.add_strong(&mut h.rsc), threshold, } .add(&mut h.rsc); let side = rect(Color::GREEN).width(120).add(&mut h.rsc); h.set_root((side, branch).span(Dir::RIGHT)); (wide.id(), narrow.id()) } /// Which of the two branches drew, as a pair a test can compare. fn taken(h: &Harness, wide: WidgetId, narrow: WidgetId) -> (bool, bool) { (h.region(&wide).is_some(), h.region(&narrow).is_some()) } #[test] fn a_branch_taken_on_a_measurement_holds_across_repaints() { for threshold in [0.0, 200.0, 400.0, 600.0, 779.0, 780.0, 781.0, 2000.0] { let mut h = Harness::new((900, 600)); let (wide, narrow) = plant(&mut h, threshold); let first = taken(&h, wide, narrow); assert_ne!(first, (false, false), "threshold {threshold}: neither drew"); for frame in 0..4 { h.rsc.widgets_mut().get_dyn_mut(wide); h.rsc.widgets_mut().get_dyn_mut(narrow); h.frame(); assert_eq!( taken(&h, wide, narrow), first, "threshold {threshold}, repaint {frame}: the branch moved when nothing did" ); } } } #[test] fn a_branch_taken_on_a_measurement_is_the_one_a_cold_start_takes() { for threshold in [0.0, 200.0, 400.0, 600.0, 779.0, 780.0, 781.0, 2000.0] { let mut warm = Harness::new((900, 600)); let (wide, narrow) = plant(&mut warm, threshold); warm.resize((640, 480)); warm.frame(); warm.rsc.widgets_mut().get_dyn_mut(wide); warm.frame(); let mut cold = Harness::new((640, 480)); let (cwide, cnarrow) = plant(&mut cold, threshold); assert_eq!( taken(&warm, wide, narrow), taken(&cold, cwide, cnarrow), "threshold {threshold}: warm and cold took different branches" ); } }