Keep retained masks and reparented drawings alive, and advance collapsed slots
This commit is contained in:
1 parent
cadfba05dd
commit
add6774980
6 files changed
+229
-9
No files matched your search
@@ -1342,3 +1342,154 @@ fn extent_frames_keep_fractional_reports_and_numeric_dependencies_valid() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct OptionalMask {
|
||||
inner: StrongWidget,
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl Widget for OptionalMask {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
if self.enabled {
|
||||
painter.set_mask(UiRegion::FULL);
|
||||
}
|
||||
painter.widget(&self.inner);
|
||||
Size::LEFTOVER
|
||||
}
|
||||
}
|
||||
|
||||
fn primitive_masks(h: &Harness, id: WidgetId) -> Vec<MaskIdx> {
|
||||
h.render.active[&id]
|
||||
.primitives
|
||||
.iter()
|
||||
.map(|primitive| {
|
||||
let handle = &primitive.handle;
|
||||
h.render.layers[handle.layer].primitives()[handle.kind as usize]
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.instances()[handle.inst_idx]
|
||||
.mask_idx
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_redrawn_mask_keeps_reused_primitives_clipped_when_it_moves() {
|
||||
for node in [false, true] {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let first = rect(Color::RED).height(50).add(&mut h.rsc);
|
||||
let inner = rect(Color::BLUE).add(&mut h.rsc);
|
||||
let draws = Rc::new(Cell::new(0));
|
||||
let child = Stretchy {
|
||||
inner: inner.add_strong(&mut h.rsc),
|
||||
draws: draws.clone(),
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
let masked = child.masked().add(&mut h.rsc);
|
||||
h.rsc.widgets_mut().set_region_node(masked, node);
|
||||
h.set_root((first, masked).span(Dir::DOWN));
|
||||
let mask = h.render.active[&masked.id()].mask;
|
||||
let settled = draws.get();
|
||||
h.rsc.widgets_mut().get_dyn_mut(masked.id());
|
||||
h.frame();
|
||||
assert_eq!(primitive_masks(&h, inner.id()), vec![mask]);
|
||||
assert_eq!(draws.get(), settled, "a mask repaint must reuse its child");
|
||||
assert_eq!(h.render.active[&masked.id()].mask, mask);
|
||||
h.set_len(first, Axis::Y, 10);
|
||||
h.frame();
|
||||
let clip = h.rsc.ui().masks[mask.idx()];
|
||||
let clip = h
|
||||
.render
|
||||
.moves
|
||||
.resolve(clip.move_idx, clip.region)
|
||||
.to_px(h.render.output_size());
|
||||
assert_eq!(clip, h.region(&masked).unwrap());
|
||||
assert_corners!(h, inner, (0, 10), (400, 200));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adding_and_removing_a_mask_updates_existing_primitives() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let inner = rect(Color::BLUE).add(&mut h.rsc);
|
||||
let masked = OptionalMask {
|
||||
inner: inner.add_strong(&mut h.rsc),
|
||||
enabled: false,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
h.set_root(masked);
|
||||
for enabled in [true, false, true, false] {
|
||||
h.rsc[masked].enabled = enabled;
|
||||
h.frame();
|
||||
let mask = h.render.active[&masked.id()].mask;
|
||||
assert_eq!(mask == MaskIdx::NONE, !enabled);
|
||||
assert_eq!(primitive_masks(&h, inner.id()), vec![mask]);
|
||||
}
|
||||
assert_eq!(h.rsc.ui().masks.len(), 1, "retired slots must be reusable");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_empty_masks_slot_is_released_when_the_mask_is_removed_or_undrawn() {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let (inner, _) = counted(&mut h, Size::LEFTOVER, false);
|
||||
let masked = OptionalMask {
|
||||
inner: inner.add_strong(&mut h.rsc),
|
||||
enabled: true,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
let row = (masked,).span(Dir::DOWN).add(&mut h.rsc);
|
||||
h.set_root(row);
|
||||
for _ in 0..3 {
|
||||
h.rsc[masked].enabled = false;
|
||||
h.frame();
|
||||
h.rsc[masked].enabled = true;
|
||||
h.frame();
|
||||
let child = h.rsc[row].pop().unwrap();
|
||||
h.frame();
|
||||
h.rsc[row].push(child);
|
||||
h.frame();
|
||||
}
|
||||
assert_eq!(h.rsc.ui().masks.len(), 1);
|
||||
}
|
||||
|
||||
struct SharedChild(Rc<StrongWidget>);
|
||||
|
||||
impl Widget for SharedChild {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
painter.widget(self.0.as_ref()).size()
|
||||
}
|
||||
}
|
||||
|
||||
struct SwitchParent {
|
||||
choices: [StrongWidget; 2],
|
||||
choice: usize,
|
||||
}
|
||||
|
||||
impl Widget for SwitchParent {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
painter.widget(&self.choices[self.choice]).size()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_redrawn_subtree_is_not_undrawn_by_the_parent_it_left() {
|
||||
for node in [false, true] {
|
||||
let mut h = Harness::new((400, 200));
|
||||
let leaf = rect(Color::RED).width(40).add(&mut h.rsc);
|
||||
let held: StrongWidget = leaf.add_strong(&mut h.rsc);
|
||||
let shared = Rc::new(held);
|
||||
let first = SharedChild(shared.clone()).add_strong(&mut h.rsc);
|
||||
let second = SharedChild(shared).add_strong(&mut h.rsc);
|
||||
h.rsc.widgets_mut().set_region_node(&second, node);
|
||||
let root = SwitchParent {
|
||||
choices: [first, second],
|
||||
choice: 0,
|
||||
}
|
||||
.add(&mut h.rsc);
|
||||
h.set_root(root);
|
||||
let before = h.region(&leaf);
|
||||
h.rsc[root].choice = 1;
|
||||
h.frame();
|
||||
assert_eq!(h.region(&leaf), before);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user