//! What a second frame draws again, and what it keeps. use std::{cell::Cell, rc::Rc}; use iris::harness::{Harness, assert_corners}; use iris::prelude::*; /// A leaf that counts its draws and reports whatever size it is given, so a /// test can see what the retained path skipped. struct Counted { draws: Rc>, size: Size, dependence: SizeDependence, } impl Widget for Counted { fn draw(&mut self, painter: &mut Painter) { self.draws.set(self.draws.get() + 1); painter.set_size(self.size); } fn size_dependence(&self, _: Axis) -> SizeDependence { self.dependence } } struct Counts(Rc>); impl Counts { fn get(&self) -> usize { self.0.get() } } fn counted( h: &mut Harness, size: Size, dependence: SizeDependence, ) -> (WeakWidget, Counts) { let draws = Rc::new(Cell::new(0)); let id = Counted { draws: draws.clone(), size, dependence, } .add(&mut h.rsc); (id, Counts(draws)) } /// 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); let (second, draws) = counted(h, Size::REST, rest); h.set_root((first, second).span(Dir::RIGHT)); (first, draws, second.id()) } #[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 settled = draws.get(); assert_corners!(h, second, (100, 0), (400, 200)); h.rsc[first].size = Size::from((150, 200)); h.frame(); assert_eq!( draws.get(), settled, "its box is a field to write, not a reason to draw" ); assert_corners!(h, second, (150, 0), (400, 200)); } #[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 settled = draws.get(); h.rsc[first].size = Size::from((150, 200)); h.frame(); // Twice: once for the span to measure it, once for its real box. A child // that can hint its length is spared the first, and a smaller number here // means someone has made that cheaper rather than broken it. assert_eq!(draws.get(), settled + 2); assert_corners!(h, second, (150, 0), (400, 200)); } #[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); // 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); h.set_root((hinted, asked).span(Dir::RIGHT)); assert_eq!(told_draws.get(), 1); assert_eq!( asked_draws.get(), 2, "drawn to be measured, then again to be placed" ); } #[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); h.rsc[first].size = Size::from((250, 200)); h.frame(); assert_corners!(h, first, (0, 0), (250, 200)); assert_corners!(h, second, (250, 0), (400, 200)); } #[test] fn a_placed_child_survives_the_next_frame() { let mut h = Harness::new((400, 200)); // Both children declare a length, so the span places them from their hints // rather than drawing them to find out. let top = rect(Color::RED).height(80).add(&mut h.rsc); let bottom = rect(Color::BLUE).height(120).add(&mut h.rsc); h.set_root((top, bottom).span(Dir::DOWN)); h.rsc.widgets_mut().get_dyn_mut(top.id()); h.frame(); assert_corners!(h, top, (0, 0), (400, 80)); assert_corners!(h, bottom, (0, 80), (400, 200)); }