Settle dirty layout from the leaves upward

This commit is contained in:
iris-ai committed 2026-09-14 15:56:44 -04:00
1 parent a640c6cce2
commit 84f589e364
5 files changed
+69 -68

No files matched your search

+37 -15
View File
@@ -74,10 +74,10 @@ impl UiRenderState {
}
}
}
self.resized = false;
if rsc.widgets().has_updates() {
self.redraw_updates(rsc);
}
self.resized = false;
}
fn redraw_all(&mut self, root: Option<&StrongWidget>, rsc: &mut dyn UiRsc) {
@@ -109,19 +109,18 @@ impl UiRenderState {
parent_move: MoveIdx,
slotted: bool,
mask: MaskIdx,
old_active: Option<ActiveData>,
old_children: Option<Vec<WidgetId>>,
rsc: &mut dyn UiRsc,
) -> Size {
let mut old_active = old_active;
let mut old_children = old_children.unwrap_or_default();
if self.active.contains_key(&id) {
if let Some(size) = self.try_reuse(id, region, parent_move, rsc) {
return size;
}
// if not, then maintain resize and track old children to remove unneeded
old_active = self.remove(id, false, rsc);
let active = self.remove(id, false, rsc).unwrap();
old_children = active.children;
}
let previous_px = old_active.as_ref().map(|active| active.px);
let old_children = old_active.map(|active| active.children).unwrap_or_default();
// draw widget
let (move_idx, local) = match slotted {
@@ -134,7 +133,6 @@ impl UiRenderState {
}
};
let px = self.px_of(move_idx, local);
let same_box = previous_px == Some(px);
rsc.widgets_mut().needs_redraw.remove(&id);
self.draw_started.insert(id);
@@ -149,7 +147,6 @@ impl UiRenderState {
children: Vec::new(),
size_deps: Vec::new(),
reads_output: false,
same_box,
move_idx,
rsc,
};
@@ -168,7 +165,6 @@ impl UiRenderState {
children,
size_deps,
reads_output,
same_box: _,
move_idx,
layer,
id,
@@ -401,12 +397,31 @@ impl UiRenderState {
}
pub fn redraw_updates(&mut self, rsc: &mut dyn UiRsc) {
while let Some(&id) = rsc.widgets().needs_redraw.iter().next() {
// A reader's answer is only valid after every dirty size it reads has
// settled. Equal-depth widgets are independent, so their order does
// not matter.
while let Some(id) = rsc
.widgets()
.needs_redraw
.iter()
.copied()
.max_by_key(|&id| self.depth(id))
{
self.redraw(id, rsc);
}
rsc.free();
}
fn depth(&self, id: WidgetId) -> usize {
let mut depth = 0;
let mut at = Some(id);
while let Some(id) = at {
at = self.active.get(&id).and_then(|active| active.parent);
depth += 1;
}
depth
}
pub fn root_changed<'a>(&self, root: impl Into<Option<&'a StrongWidget>>) -> bool {
root.into().map(|r| r.id()) != self.old_root
}
@@ -462,7 +477,9 @@ impl UiRenderState {
.active
.get(&id)
.is_some_and(|active| self.px_of(active.parent_move, active.region) != active.px);
if box_changed && let Some(top) = self.mark_readers(id, rsc) {
if (self.resized || box_changed)
&& let Some(top) = self.mark_readers(id, rsc)
{
self.redraw(top, rsc);
rsc.widgets_mut().needs_redraw.remove(&id);
return;
@@ -486,15 +503,20 @@ impl UiRenderState {
active.parent_move,
active.move_idx != active.parent_move,
active.mask,
Some(active),
Some(active.children),
rsc,
);
if size != was
&& let Some(top) = self.mark_readers(id, rsc)
&& let Some(parent) = self.active.get(&id).and_then(|active| active.parent)
&& self
.active
.get(&parent)
.is_some_and(|active| active.size_deps.contains(&id))
{
self.redraw(top, rsc);
rsc.widgets_mut().needs_redraw.remove(&id);
// Propagate one dependency edge at a time. If drawing the reader
// does not change its own size, nothing above it can observe this.
rsc.widgets_mut().needs_redraw.insert(parent);
}
}