A widget that resolves a window length in pixels depends on that window wherever the length is a fraction of it, and nothing was recording that: Painter::to_px replaces window_px_len and pins the window it read, while a length that is only pixels is that many pixels in any window and pins nothing. Span still states the range it actually branched on, which replaces the pin with something wider. Scroll is where it showed: its content's answer is a window length now, so a viewport whose own box does not change with the window -- 40 px of a branch's box -- kept an end-snapped offset from the window before. Seed 942 at depth 6 under resize, pinned as unsettled::resizing_under_a_short_scroll_snaps_its_window_tall_content_again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
104 lines
3.8 KiB
Rust
104 lines
3.8 KiB
Rust
//! 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.extent_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"
|
|
);
|
|
}
|
|
}
|