Measure container children without intermediate placement
This commit is contained in:
1 parent
c330ecec2b
commit
7601aa2a5d
6 files changed
+81
-38
No files matched your search
+20
-16
@@ -139,7 +139,7 @@ impl<'a> Painter<'a> {
|
||||
/// around one child wants, since its box is the child's.
|
||||
pub fn widget<'s, W: ?Sized>(&'s mut self, id: &'s StrongWidget<W>) -> DrawResult<'s, 'a, W> {
|
||||
let own = self.placement;
|
||||
self.widget_at_inner(id, UiRegion::FULL, [Some(own.x), Some(own.y)], true)
|
||||
self.widget_at_inner(id, UiRegion::FULL, [Some(own.x), Some(own.y)], true, false)
|
||||
}
|
||||
|
||||
/// What a widget's rules declare its lengths to be, which whoever draws
|
||||
@@ -191,7 +191,7 @@ impl<'a> Painter<'a> {
|
||||
region: UiRegion,
|
||||
placement: [Option<UiSpan>; 2],
|
||||
) -> DrawResult<'s, 'a, W> {
|
||||
self.widget_at_inner(id, region, placement, false)
|
||||
self.widget_at_inner(id, region, placement, false, false)
|
||||
}
|
||||
|
||||
fn widget_at_inner<'s, W: ?Sized>(
|
||||
@@ -200,6 +200,7 @@ impl<'a> Painter<'a> {
|
||||
region: UiRegion,
|
||||
placement: [Option<UiSpan>; 2],
|
||||
inherited: bool,
|
||||
measuring: bool,
|
||||
) -> DrawResult<'s, 'a, W> {
|
||||
if inherited {
|
||||
if !self.inherited_children.contains(&id.id()) {
|
||||
@@ -266,6 +267,7 @@ impl<'a> Painter<'a> {
|
||||
placement,
|
||||
},
|
||||
None,
|
||||
measuring,
|
||||
self.rsc,
|
||||
);
|
||||
// Whatever the child's answer holds for keeps this one to the boxes
|
||||
@@ -321,32 +323,34 @@ impl<'a> Painter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A child's length in the region it is about to be offered, if it can
|
||||
/// be had without drawing it: from its hint, or from a drawing it already
|
||||
/// has that holds for that box.
|
||||
pub fn known_len<W: ?Sized>(
|
||||
/// Measures a child's length from its hint, a retained answer, or `draw`.
|
||||
/// A fresh draw evaluates the offer without placing its answer. The caller
|
||||
/// must later place or undraw the child.
|
||||
pub fn measure_len<W: ?Sized>(
|
||||
&mut self,
|
||||
child: &StrongWidget<W>,
|
||||
axis: Axis,
|
||||
region: UiRegion,
|
||||
placement: [Option<UiSpan>; 2],
|
||||
) -> Option<LayoutLen> {
|
||||
) -> LayoutLen {
|
||||
let offered = placement;
|
||||
let declared = self.declared_lens(child);
|
||||
let align = self.rsc.widgets().alignment(child.id());
|
||||
let (local, placement) = ask_box(region, declared, align, placement);
|
||||
let first_ask = self.at_offer && !self.offered.contains(&child.id());
|
||||
|
||||
if let Some(hint) = self.size_hint(child, axis) {
|
||||
return Some(hint);
|
||||
return hint;
|
||||
}
|
||||
let px = local.size().to_px(self.px);
|
||||
let (size, holds) = self.state.retained_size(
|
||||
child.id(),
|
||||
px,
|
||||
placement,
|
||||
self.move_idx,
|
||||
self.rsc.widgets(),
|
||||
)?;
|
||||
let retained =
|
||||
self.state
|
||||
.retained_size(child.id(), px, placement, self.move_idx, self.rsc.widgets());
|
||||
let Some((size, holds)) = retained else {
|
||||
return self
|
||||
.widget_at_inner(child, region, offered, false, true)
|
||||
.len(axis);
|
||||
};
|
||||
#[cfg(feature = "layout-diagnostics")]
|
||||
diag::bump(Counter::RetainedSizeHits);
|
||||
self.depend_on(child);
|
||||
@@ -364,7 +368,7 @@ impl<'a> Painter<'a> {
|
||||
for (axis, under) in AXES.into_iter().zip(self.under.iter_mut()) {
|
||||
*under = under.and(holds[axis as usize].through(local.axis(axis).len()));
|
||||
}
|
||||
Some(in_parent_frame(size, local.size(), declared).axis(axis))
|
||||
in_parent_frame(size, local.size(), declared).axis(axis)
|
||||
}
|
||||
|
||||
/// Whether this is the first box a child is asked about in during a draw
|
||||
|
||||
+15
-10
@@ -193,7 +193,7 @@ impl UiRenderState {
|
||||
if let Some(id) = root {
|
||||
let region = Self::root_region(id.id(), rsc.widgets());
|
||||
let info = self.root_info(region);
|
||||
self.draw_inner(id.id(), region, info, None, rsc);
|
||||
self.draw_inner(id.id(), region, info, None, false, rsc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +213,7 @@ impl UiRenderState {
|
||||
region: UiRegion,
|
||||
info: DrawInfo,
|
||||
mut old: Option<ActiveData>,
|
||||
measuring: bool,
|
||||
rsc: &mut dyn UiRsc,
|
||||
) -> (Size, LayoutHolds) {
|
||||
#[cfg(feature = "layout-diagnostics")]
|
||||
@@ -239,16 +240,20 @@ impl UiRenderState {
|
||||
self.draw_at(id, region, info.offered_placement(), info, old.take(), rsc)
|
||||
});
|
||||
|
||||
let declared = declared_lens(rsc.widgets(), id);
|
||||
// Where the drawing goes, in the region's own coordinates: what the
|
||||
// parent chose, and on any axis it left open, what the answer took of
|
||||
// the region placed by the widget's alignment. The region itself does
|
||||
// not change, so nothing under it resolves a fraction a second time.
|
||||
let lens = placed_lens(answer.0, declared, info.decided());
|
||||
let own = placed_box(UiRegion::FULL, lens, align);
|
||||
let placement = UiRegion {
|
||||
x: info.placement[0].unwrap_or(own.x),
|
||||
y: info.placement[1].unwrap_or(own.y),
|
||||
let placement = if measuring {
|
||||
info.offered_placement()
|
||||
} else {
|
||||
let declared = declared_lens(rsc.widgets(), id);
|
||||
let lens = placed_lens(answer.0, declared, info.decided());
|
||||
let own = placed_box(UiRegion::FULL, lens, align);
|
||||
UiRegion {
|
||||
x: info.placement[0].unwrap_or(own.x),
|
||||
y: info.placement[1].unwrap_or(own.y),
|
||||
}
|
||||
};
|
||||
self.place(id, region, placement, info, rsc);
|
||||
|
||||
@@ -1137,7 +1142,7 @@ impl UiRenderState {
|
||||
#[cfg(feature = "layout-diagnostics")]
|
||||
diag::bump(Counter::LocalRedraws);
|
||||
let old = self.remove(id, false, rsc);
|
||||
self.draw_inner(id, region, info, old, rsc);
|
||||
self.draw_inner(id, region, info, old, false, rsc);
|
||||
return true;
|
||||
};
|
||||
let (given_px, offered_px) = self.asked_px(id);
|
||||
@@ -1179,9 +1184,9 @@ impl UiRenderState {
|
||||
placement: info.offer_placement,
|
||||
..info
|
||||
};
|
||||
let answer = self.draw_inner(id, given, offered, old, rsc);
|
||||
let answer = self.draw_inner(id, given, offered, old, false, rsc);
|
||||
if info.placement != offered.placement {
|
||||
self.draw_inner(id, given, info, None, rsc);
|
||||
self.draw_inner(id, given, info, None, false, rsc);
|
||||
}
|
||||
if Some(answer) != was_answer {
|
||||
// Its parent chose its box knowing the old answer, so it lays out
|
||||
|
||||
Reference in new issue
Block a user