Keep retained masks and reparented drawings alive, and advance collapsed slots

This commit is contained in:
iris-ai committed 2026-09-19 13:43:11 -04:00
1 parent cadfba05dd
commit add6774980
6 files changed
+229 -9

No files matched your search

+1
View File
@@ -53,6 +53,7 @@ pub struct ActiveData {
/// Its primitives, each keeping the box it was written in -- in this
/// widget's extent coordinates, which is what a move recomposes from.
pub primitives: Vec<RetainedPrimitive>,
/// An owned mask holds one reference independently of its primitives.
pub mask_region: Option<UiRegion>,
pub children: Vec<WidgetId>,
/// The children whose size this widget read while drawing.
+17 -3
View File
@@ -35,6 +35,8 @@ pub struct Painter<'a> {
pub(super) textures: Vec<TextureHandle>,
pub(super) primitives: Vec<RetainedPrimitive>,
pub(super) mask_region: Option<UiRegion>,
/// The previous drawing's owned mask, available for this draw to reclaim.
pub(super) mask_slot: Option<MaskIdx>,
/// Only children whose answers were read constrain this widget's answer.
pub(super) answer_under: LayoutHolds,
pub(super) children: Vec<WidgetId>,
@@ -104,7 +106,6 @@ impl<'a> Painter<'a> {
fn push_primitive(&mut self, h: RetainedPrimitive) {
if self.mask != MaskIdx::NONE {
// TODO: I have no clue if this works at all :joy:
self.rsc.ui_mut().masks.push_ref(self.mask);
}
self.primitives.push(h);
@@ -129,10 +130,23 @@ impl<'a> Painter<'a> {
assert!(self.mask == MaskIdx::NONE);
let resolved = self.resolve(region);
let move_idx = self.move_idx;
self.mask = self.rsc.ui_mut().masks.push(Mask {
let mask = Mask {
region: resolved,
move_idx,
});
};
let masks = &mut self.rsc.ui_mut().masks;
self.mask = match self.mask_slot.take() {
Some(idx) => {
*masks.get_mut(idx) = mask;
idx
}
None => {
let idx = masks.push(mask);
// The owner keeps the slot alive even with no primitives.
masks.push_ref(idx);
idx
}
};
}
/// Draws a widget in the whole of this widget's own box, with the frame
+22 -6
View File
@@ -223,6 +223,10 @@ impl UiRenderState {
mut old: Option<ActiveData>,
rsc: &mut dyn UiRsc,
) -> (Size, LayoutHolds, LayoutHolds) {
let old_parent = old
.as_ref()
.or_else(|| self.active.get(&id))
.and_then(|a| a.parent);
let part = info.part;
#[cfg(feature = "layout-diagnostics")]
{
@@ -275,12 +279,9 @@ impl UiRenderState {
active.part = part;
active.placed = info.placed;
active.own_align = align;
// A subtree can be reused whole under a different parent -- same box,
// same layer, same region node -- and nothing in the drawing says it
// changed hands. Two things read who its parent is: a deferral, which
// marks whoever has it to draw, and the old parent's list of children,
// which its next draw undraws whatever is missing from.
let old_parent = std::mem::replace(&mut active.parent, info.parent);
// The previous parent must stop owning the subtree before it can
// undraw it, whether changing hands reused the drawing or replaced it.
active.parent = info.parent;
if old_parent != info.parent
&& let Some(old_parent) = old_parent
&& let Some(old_parent) = self.active.get_mut(&old_parent)
@@ -312,6 +313,9 @@ impl UiRenderState {
// Reusing its index sooner could make an old parent look current.
false => (info.parent_move, extent, self.slots.remove(&id)),
};
let mask_slot = old
.as_ref()
.and_then(|old| old.mask_region.map(|_| old.mask));
let old_children = old.map_or_else(Vec::new, |old| old.children);
rsc.widgets_mut().needs_redraw.remove(&id);
let px = info.px;
@@ -330,6 +334,7 @@ impl UiRenderState {
textures: Vec::new(),
primitives: Vec::new(),
mask_region: None,
mask_slot,
children: Vec::new(),
size_deps: Vec::new(),
window_own: [Holds::ANY; 2],
@@ -363,6 +368,7 @@ impl UiRenderState {
textures,
primitives,
mask_region,
mask_slot,
extent_own,
extent_len,
answer_under,
@@ -421,6 +427,9 @@ impl UiRenderState {
self.undraw_rec(*c, rsc);
}
}
if let Some(idx) = mask_slot {
rsc.ui_mut().masks.remove(idx);
}
if let Some(idx) = retired_move {
self.moves.remove(idx);
}
@@ -605,6 +614,9 @@ impl UiRenderState {
}
return None;
}
if active.parent_mask != info.mask {
return None;
}
// Drawn somewhere else in the tree: its box is in coordinates it no
// longer sits in, and its slot names the wrong parent.
if active.parent_move != info.parent_move {
@@ -826,6 +838,9 @@ impl UiRenderState {
rsc.ui_mut().masks.remove(mask);
}
}
if undraw && active.mask_region.take().is_some() {
rsc.ui_mut().masks.remove(active.mask);
}
active.primitives.clear();
active.textures.clear();
rsc.ui_mut().textures.free();
@@ -913,6 +928,7 @@ impl UiRenderState {
self.slots.clear();
self.moves.clear();
self.layers.clear();
rsc.ui_mut().masks = Default::default();
rsc.widgets_mut().needs_redraw.clear();
self.free(rsc);
}