diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 3d4ac64..c23956b 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -192,14 +192,19 @@ impl UiRenderState { diag::draw_request(id, info.parent, region, info.px, info.region_node); } let align = rsc.widgets().alignment(id); - let replace_answer = self.answer_invalid.remove(&id) - || (self.replace_answers - && (rsc.widgets().needs_redraw.contains(&id) - || self.dirty_size_under(id, rsc.widgets()))); - let retained = match replace_answer { + // Nothing this widget has is an answer while something it measured + // is dirty: settling that changes what it would report, and a widget + // settled inside its parent's draw tells nobody -- the comparison + // that marks a reader is in `redraw`, which is not what asked here. + // Both retained routes are an answer, so the question is asked once + // rather than by each of them. + let stale = + rsc.widgets().needs_redraw.contains(&id) || self.dirty_size_under(id, rsc.widgets()); + let replace_answer = self.answer_invalid.remove(&id) || (self.replace_answers && stale); + let retained = match replace_answer || stale { true => None, false => self - .retained_answer(id, info, rsc.widgets()) + .retained_answer(id, info) .or_else(|| self.try_reuse(id, region, info, rsc)), }; let answer = retained.unwrap_or_else(|| { @@ -489,16 +494,9 @@ impl UiRenderState { /// The answer to an ask can be retained independently of where its /// drawing ended up. Alignment is exactly that case: the first box is the - /// question and the smaller placed box holds the drawing. - fn retained_answer( - &self, - id: WidgetId, - info: DrawInfo, - widgets: &Widgets, - ) -> Option<(Size, [Holds; 2])> { - if widgets.needs_redraw.contains(&id) || self.dirty_size_under(id, widgets) { - return None; - } + /// question and the smaller placed box holds the drawing. Whether the + /// answer is stale at all is its caller's question, asked once there. + fn retained_answer(&self, id: WidgetId, info: DrawInfo) -> Option<(Size, [Holds; 2])> { let active = self.active.get(&id)?; let has_region_node = active.move_idx != active.parent_move; if !active.drawn @@ -512,9 +510,11 @@ impl UiRenderState { } /// Whether anything whose size this widget's own size was read from is - /// dirty. Not needed for the answer to come right -- a changed size - /// reaches its reader in any order -- but a reader that asks first - /// lays out once rather than twice. + /// dirty, which makes what it would answer not yet known. It also keeps + /// a reader that asks first from laying out twice, which is all it was + /// here for while a changed size was thought to reach its reader in any + /// order; it does not, where the change settles inside the reader's own + /// draw. fn dirty_size_under(&self, id: WidgetId, widgets: &Widgets) -> bool { self.active.get(&id).is_some_and(|active| { active.size_deps.iter().any(|child| {