diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 3ec5ff5..8667dcf 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -2,7 +2,7 @@ use crate::layout_diagnostics::{self as diag, Counter, ReuseOutcome, TimerKind}; use crate::{ ActiveData, Axis, DrawLayers, IdLike, MaskIdx, MoveIdx, Moves, OnResize, Painter, PixelRegion, - Size, StrongWidget, UiRegion, UiRsc, WidgetId, Widgets, + Size, StrongWidget, UiRegion, UiRsc, UiScalar, UiSpan, WidgetId, Widgets, util::{HashMap, HashSet, Vec2}, }; @@ -19,6 +19,8 @@ pub struct UiRenderState { pub(super) output_size: Vec2, old_root: Option, + /// The slot every chain bottoms out in, holding the output as a box. + root_move: MoveIdx, resized: [bool; 2], /// Content/state dirtiness whose retained size cannot answer a layout /// question until that widget has drawn again. @@ -50,6 +52,22 @@ impl UiRenderState { draw_started: Default::default(), slots: Default::default(), moves: Default::default(), + root_move: MoveIdx::NONE, + } + } + + /// The window as a box, so a chain bottoms out in one rather than in a + /// multiplication applied after it. Composing through a box held in + /// pixels leaves everything below it in pixels, which is why nothing + /// downstream has to know the output's size to resolve a position. + fn write_root(&mut self) { + let region = UiRegion::new( + UiSpan::new(UiScalar::ZERO, UiScalar::px(self.output_size.x)), + UiSpan::new(UiScalar::ZERO, UiScalar::px(self.output_size.y)), + ); + match self.root_move == MoveIdx::NONE { + true => self.root_move = self.moves.push(MoveIdx::NONE, region), + false => self.moves.set(self.root_move, region), } } @@ -59,6 +77,7 @@ impl UiRenderState { *resized |= size.axis(axis) != self.output_size.axis(axis); } self.output_size = size; + self.write_root(); } pub fn output_size(&self) -> Vec2 { @@ -149,6 +168,7 @@ impl UiRenderState { let _layout = diag::timer(TimerKind::FullLayout); self.clear(rsc); // free all resources & cache + self.write_root(); if let Some(id) = root { self.draw_inner( 0, @@ -156,7 +176,7 @@ impl UiRenderState { UiRegion::FULL, None, 1, - MoveIdx::NONE, + self.root_move, false, MaskIdx::NONE, None, @@ -589,6 +609,7 @@ impl UiRenderState { } self.slots.clear(); self.moves.clear(); + self.root_move = MoveIdx::NONE; self.layers.clear(); self.invalid_sizes.clear(); self.resize_marks.clear(); diff --git a/tests/layout.rs b/tests/layout.rs index 569e9d3..6e88906 100644 --- a/tests/layout.rs +++ b/tests/layout.rs @@ -180,5 +180,9 @@ fn only_a_container_that_places_its_children_lengthens_the_chain() { h.set_root((bar, buried).span(Dir::RIGHT)); let slot = h.render.active[&leaf.id()].parent_move; - assert_eq!(h.render.moves.depth(slot), 1, "one span above the leaf"); + assert_eq!( + h.render.moves.depth(slot), + 2, + "the span above the leaf, and the root the window is held in" + ); }