//! What a retained drawing costs in accuracy when it is moved instead of made //! again. A subtree's stored regions are the only record of where it is, so a //! move that works from the last answer rather than from the box it is now in //! integrates its own rounding, and nothing later recomputes it. Re-expressing //! each part as the same fraction of the new box is what keeps a long-lived //! layout on the one a cold start produces. use iris::harness::Harness; use iris::prelude::*; /// A row of a fixed height under a bar, so changing the bar's height moves the /// row without changing the box it is given: the move path, repeatedly. fn plant(h: &mut Harness, bar_height: f32) -> (WeakWidget, WeakWidget) { let bar = rect(Color::RED).height(bar_height).add(&mut h.rsc); let inner = rect(Color::BLUE).add(&mut h.rsc); let row = (inner, rect(Color::GREEN)).span(Dir::RIGHT).height(100); h.set_root((bar, row).span(Dir::DOWN)); (bar, inner) } /// Enough moves to pass the 0.05 physical pixels layout treats as the same /// place, for a move that adds an offset to the last answer. Measured on this /// fixture on 2026-09-15: adding the offset to both ends of a span shortened /// the row by 0.071 over this many moves and by 0.712 over ten times as many, /// growing with the count rather than settling. Placing the far end from the /// near one instead left 0.069, because the length is re-derived either way. const MOVES: usize = 20_000; #[test] fn a_subtree_moved_many_times_stays_where_a_cold_layout_puts_it() { let mut warm = Harness::new((640, 900)); let (bar, inner) = plant(&mut warm, 40.0); let mut height = 40.0; for step in 0..MOVES { height = 40.0 + (step % 300) as f32 * 0.37; warm.set_len(bar, Axis::Y, height); warm.frame(); } let mut cold = Harness::new((640, 900)); let (_, cold_inner) = plant(&mut cold, height); cold.frame(); assert_eq!(warm.region(&inner), cold.region(&cold_inner)); }