Make Iris layout dependencies explicit
This commit is contained in:
1 parent
2bc0ff1866
commit
3ae034a47b
25 files changed
+609
-186
No files matched your search
+209
-6
@@ -5,6 +5,7 @@
|
||||
//! CPU-side layout/move machinery LAYOUT.md is about.
|
||||
|
||||
use crate::prelude::*;
|
||||
use std::{cell::Cell, cell::RefCell, rc::Rc};
|
||||
|
||||
/// The minimal `UiRsc` a test needs: just the shared `UiData`, none of the
|
||||
/// event/window/state plumbing `DefaultRsc` carries. `pub(crate)` so
|
||||
@@ -26,14 +27,14 @@ impl UiRsc for TestRsc {
|
||||
struct FixedRect(f32);
|
||||
|
||||
impl Widget for FixedRect {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
let size = Size::from_axis(Axis::Y, Len::abs(self.0), Len::REST);
|
||||
painter.primitive_within(
|
||||
RectPrimitive::color(UiColor::WHITE),
|
||||
size.to_uivec2(painter.density())
|
||||
.align(RegionAlign::TOP_LEFT),
|
||||
);
|
||||
size
|
||||
painter.set_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +44,214 @@ struct ChildOffset {
|
||||
}
|
||||
|
||||
impl Widget for ChildOffset {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
painter.set_child_offset(self.offset);
|
||||
painter.widget(&self.child)
|
||||
let size = painter.widget(&self.child).size();
|
||||
painter.set_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
struct TracedLeaf {
|
||||
height: f32,
|
||||
trace: Rc<RefCell<Vec<&'static str>>>,
|
||||
}
|
||||
|
||||
impl Widget for TracedLeaf {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
self.trace.borrow_mut().push("child");
|
||||
painter.set_size(Size::from_axis(Axis::Y, Len::abs(self.height), Len::REST));
|
||||
}
|
||||
}
|
||||
|
||||
struct TracedParent {
|
||||
child: StrongWidget,
|
||||
reads_child_size: bool,
|
||||
trace: Rc<RefCell<Vec<&'static str>>>,
|
||||
}
|
||||
|
||||
struct CountedLeaf {
|
||||
height: f32,
|
||||
draws: Rc<Cell<u32>>,
|
||||
}
|
||||
|
||||
impl Widget for CountedLeaf {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
self.draws.set(self.draws.get() + 1);
|
||||
painter.set_size(Size::from_axis(Axis::Y, Len::abs(self.height), Len::REST));
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for TracedParent {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
self.trace.borrow_mut().push("parent");
|
||||
let child = painter.widget(&self.child);
|
||||
let size = if self.reads_child_size {
|
||||
child.size()
|
||||
} else {
|
||||
Size::REST
|
||||
};
|
||||
painter.set_size(size);
|
||||
}
|
||||
}
|
||||
|
||||
/// Minimal reproduction for a container's child-layer cursor being retained
|
||||
/// as though it were the layer on which the container itself was entered.
|
||||
///
|
||||
/// `Stack` is drawn by `Sized` on layer 0. It advances its painter to layers
|
||||
/// 1 and 2 for its two children. The retained `ActiveData` must still say the
|
||||
/// stack itself is on layer 0; otherwise an ordinary redraw of `Sized` asks
|
||||
/// for the stack on 0 again and turns the invented 2 -> 0 change into a full
|
||||
/// redraw of the stack and both children.
|
||||
#[test]
|
||||
fn a_widget_retains_its_entry_layer_not_its_child_cursor() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let back = rsc.ui.widgets.add_strong(Rect::new(UiColor::WHITE));
|
||||
let front = rsc.ui.widgets.add_strong(Rect::new(UiColor::RED));
|
||||
let stack = rsc.ui.widgets.add_strong(Stack {
|
||||
children: vec![back.any(), front.any()],
|
||||
size: StackSize::Default,
|
||||
});
|
||||
let stack_id = stack.id();
|
||||
let outer = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: stack.any(),
|
||||
x: None,
|
||||
y: None,
|
||||
});
|
||||
let outer_weak = outer.weak();
|
||||
let root = outer.any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((100.0, 100.0));
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
assert_eq!(
|
||||
render.active[&stack_id].layer, 0,
|
||||
"Stack entered on layer 0; layers 1 and 2 belong only to its children"
|
||||
);
|
||||
|
||||
render.take_counters();
|
||||
rsc.ui.widgets.get_mut(&outer_weak).unwrap().x = None;
|
||||
render.update(&root, &mut rsc);
|
||||
assert_eq!(
|
||||
render.take_counters().0,
|
||||
1,
|
||||
"redrawing the parent should retain the unchanged Stack subtree"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_size_dependent_parent_is_invalidated_before_layout_runs_downward() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let trace = Rc::new(RefCell::new(Vec::new()));
|
||||
let child = rsc.ui.widgets.add_strong(TracedLeaf {
|
||||
height: 20.0,
|
||||
trace: trace.clone(),
|
||||
});
|
||||
let child_weak = child.weak();
|
||||
let parent = rsc.ui.widgets.add_strong(TracedParent {
|
||||
child: child.any(),
|
||||
reads_child_size: true,
|
||||
trace: trace.clone(),
|
||||
});
|
||||
let parent_weak = parent.weak();
|
||||
let root = parent.any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((100.0, 100.0));
|
||||
render.update(&root, &mut rsc);
|
||||
trace.borrow_mut().clear();
|
||||
|
||||
rsc.ui.widgets.get_mut(&child_weak).unwrap().height = 40.0;
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
assert_eq!(&*trace.borrow(), &["parent", "child"]);
|
||||
assert_eq!(render.active[&parent_weak.id()].size.y, Len::abs(40.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_parent_that_ignores_child_size_is_not_invalidated_with_it() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let trace = Rc::new(RefCell::new(Vec::new()));
|
||||
let child = rsc.ui.widgets.add_strong(TracedLeaf {
|
||||
height: 20.0,
|
||||
trace: trace.clone(),
|
||||
});
|
||||
let child_weak = child.weak();
|
||||
let parent = rsc.ui.widgets.add_strong(TracedParent {
|
||||
child: child.any(),
|
||||
reads_child_size: false,
|
||||
trace: trace.clone(),
|
||||
});
|
||||
let root = parent.any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((100.0, 100.0));
|
||||
render.update(&root, &mut rsc);
|
||||
trace.borrow_mut().clear();
|
||||
|
||||
rsc.ui.widgets.get_mut(&child_weak).unwrap().height = 40.0;
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
assert_eq!(&*trace.borrow(), &["child"]);
|
||||
}
|
||||
|
||||
/// A content-sized vertical container grows vertically when one child grows,
|
||||
/// but that does not invalidate another child's retained height. Its width is
|
||||
/// the context that could change that height (for example through wrapping),
|
||||
/// and that stayed fixed.
|
||||
#[test]
|
||||
fn a_span_reuses_unchanged_sibling_sizes_when_only_its_along_extent_changes() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let changed_draws = Rc::new(Cell::new(0));
|
||||
let sibling_draws = Rc::new(Cell::new(0));
|
||||
let changed = rsc.ui.widgets.add_strong(CountedLeaf {
|
||||
height: 20.0,
|
||||
draws: changed_draws.clone(),
|
||||
});
|
||||
let changed_weak = changed.weak();
|
||||
let sibling = rsc.ui.widgets.add_strong(CountedLeaf {
|
||||
height: 20.0,
|
||||
draws: sibling_draws.clone(),
|
||||
});
|
||||
let span = rsc.ui.widgets.add_strong(Span {
|
||||
children: vec![changed.any(), sibling.any()],
|
||||
dir: Dir::DOWN,
|
||||
gap: Len::ZERO,
|
||||
});
|
||||
// `Sized` settles its child from the full offered box into the content
|
||||
// height, reproducing the retained-region change a nested content-sized
|
||||
// row sees when one of its children grows.
|
||||
let root = rsc
|
||||
.ui
|
||||
.widgets
|
||||
.add_strong(Sized {
|
||||
inner: span.any(),
|
||||
x: None,
|
||||
y: None,
|
||||
})
|
||||
.any();
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((100.0, 100.0));
|
||||
render.update(&root, &mut rsc);
|
||||
changed_draws.set(0);
|
||||
sibling_draws.set(0);
|
||||
|
||||
rsc.ui.widgets.get_mut(&changed_weak).unwrap().height = 40.0;
|
||||
render.update(&root, &mut rsc);
|
||||
|
||||
assert!(changed_draws.get() > 0, "the changed child was not redrawn");
|
||||
assert_eq!(
|
||||
sibling_draws.get(),
|
||||
0,
|
||||
"a vertical size change redrew a sibling whose width stayed fixed"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_child_coordinate_offset_moves_only_the_child_subtree() {
|
||||
let mut rsc = TestRsc {
|
||||
@@ -721,7 +924,7 @@ struct MoveThenPlace {
|
||||
}
|
||||
|
||||
impl Widget for MoveThenPlace {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
fn draw(&mut self, painter: &mut Painter) {
|
||||
let offer = UiRegion::new(
|
||||
UiSpan::FULL,
|
||||
UiSpan::new(
|
||||
@@ -738,7 +941,7 @@ impl Widget for MoveThenPlace {
|
||||
),
|
||||
);
|
||||
painter.place(&self.inner, place);
|
||||
Size::default()
|
||||
painter.set_size(Size::default());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user