Retain layout sizes by pixel axis
This commit is contained in:
1 parent
82fa6c1123
commit
b1b3eca1c0
11 files changed
+371
-69
No files matched your search
+87
-6
@@ -23,7 +23,10 @@ pub struct Painter<'a> {
|
||||
pub(super) children: Vec<WidgetId>,
|
||||
/// The children whose size this widget read while drawing.
|
||||
pub(super) size_deps: Vec<WidgetId>,
|
||||
pub(super) reads_output: bool,
|
||||
/// Offered pixel axes which can affect the size this draw reports.
|
||||
pub(super) size_box_inputs: [bool; 2],
|
||||
pub(super) size_output_inputs: [bool; 2],
|
||||
pub(super) reads_output: [bool; 2],
|
||||
/// The slot this widget's primitives are positioned through: its own if
|
||||
/// its parent placed it, otherwise the nearest ancestor that has one.
|
||||
pub(super) move_idx: MoveIdx,
|
||||
@@ -158,7 +161,7 @@ impl<'a> Painter<'a> {
|
||||
Some(hint) => {
|
||||
#[cfg(feature = "layout-diagnostics")]
|
||||
diag::bump(Counter::HintHits);
|
||||
self.depend_on_size(id);
|
||||
self.depend_on_size(id, false);
|
||||
Some(hint)
|
||||
}
|
||||
None => {
|
||||
@@ -169,10 +172,66 @@ impl<'a> Painter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn depend_on_size<W: ?Sized>(&mut self, child: &StrongWidget<W>) {
|
||||
/// A retained child length valid under the region it is about to be
|
||||
/// offered. Unlike a hint, this is contextual: it is kept only when none
|
||||
/// of the offered pixel axes which produced it changed.
|
||||
pub fn known_len<W: ?Sized>(
|
||||
&mut self,
|
||||
child: &StrongWidget<W>,
|
||||
axis: Axis,
|
||||
region: UiRegion,
|
||||
) -> Option<Len> {
|
||||
if let Some(hint) = self.size_hint(child, axis) {
|
||||
return Some(hint);
|
||||
}
|
||||
self.retained_size(child, region)
|
||||
.map(|size| size.axis(axis))
|
||||
}
|
||||
|
||||
fn retained_size<W: ?Sized>(
|
||||
&mut self,
|
||||
child: &StrongWidget<W>,
|
||||
region: UiRegion,
|
||||
) -> Option<Size> {
|
||||
let region = region.within(&self.region);
|
||||
let (size, box_inputs, output_inputs) =
|
||||
self.state
|
||||
.retained_size(child.id(), region, self.move_idx, self.rsc.widgets())?;
|
||||
#[cfg(feature = "layout-diagnostics")]
|
||||
diag::bump(Counter::RetainedSizeHits);
|
||||
self.depend_on_size_inputs(child, box_inputs, output_inputs);
|
||||
Some(size)
|
||||
}
|
||||
|
||||
fn depend_on_size<W: ?Sized>(&mut self, child: &StrongWidget<W>, inherit_inputs: bool) {
|
||||
let (box_inputs, output_inputs) = match inherit_inputs {
|
||||
true => self
|
||||
.state
|
||||
.active
|
||||
.get(&child.id())
|
||||
.map_or(([false; 2], [false; 2]), |active| {
|
||||
(active.size_box_inputs, active.size_output_inputs)
|
||||
}),
|
||||
false => ([false; 2], [false; 2]),
|
||||
};
|
||||
self.depend_on_size_inputs(child, box_inputs, output_inputs);
|
||||
}
|
||||
|
||||
fn depend_on_size_inputs<W: ?Sized>(
|
||||
&mut self,
|
||||
child: &StrongWidget<W>,
|
||||
box_inputs: [bool; 2],
|
||||
output_inputs: [bool; 2],
|
||||
) {
|
||||
if !self.size_deps.contains(&child.id()) {
|
||||
self.size_deps.push(child.id());
|
||||
}
|
||||
for (own, child) in self.size_box_inputs.iter_mut().zip(box_inputs) {
|
||||
*own |= child;
|
||||
}
|
||||
for (own, child) in self.size_output_inputs.iter_mut().zip(output_inputs) {
|
||||
*own |= child;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_text(
|
||||
@@ -220,19 +279,41 @@ impl<'a> Painter<'a> {
|
||||
/// The output's size in pixels. A widget that reads it draws again when
|
||||
/// the output changes, since nothing else can put that right.
|
||||
pub fn output_size(&mut self) -> Vec2 {
|
||||
self.reads_output = true;
|
||||
self.reads_output = [true; 2];
|
||||
self.size_output_inputs = [true; 2];
|
||||
self.state.output_size
|
||||
}
|
||||
|
||||
/// One axis of the output in pixels. Prefer this to [`Self::output_size`]
|
||||
/// when the other axis cannot affect the size this widget reports.
|
||||
pub fn output_len(&mut self, axis: Axis) -> f32 {
|
||||
self.reads_output[axis as usize] = true;
|
||||
self.size_output_inputs[axis as usize] = true;
|
||||
self.state.output_size.axis(axis)
|
||||
}
|
||||
|
||||
/// This widget's box in pixels. Resolved against the output's size and
|
||||
/// the boxes it sits within, so a widget that reads it draws again when
|
||||
/// the output changes.
|
||||
pub fn px_size(&mut self) -> Vec2 {
|
||||
self.reads_output = true;
|
||||
self.reads_output = [true; 2];
|
||||
self.size_box_inputs = [true; 2];
|
||||
let region = self.state.moves.resolve(self.move_idx, self.region);
|
||||
region.size().to_abs(self.state.output_size)
|
||||
}
|
||||
|
||||
/// One axis of this widget's box in pixels. Prefer this to
|
||||
/// [`Self::px_size`] when the other axis cannot affect the reported size.
|
||||
pub fn px_len(&mut self, axis: Axis) -> f32 {
|
||||
self.reads_output[axis as usize] = true;
|
||||
self.size_box_inputs[axis as usize] = true;
|
||||
let region = self.state.moves.resolve(self.move_idx, self.region);
|
||||
region
|
||||
.size()
|
||||
.axis(axis)
|
||||
.to_abs(self.state.output_size.axis(axis))
|
||||
}
|
||||
|
||||
pub fn text_data(&mut self) -> &mut TextData {
|
||||
&mut self.rsc.ui_mut().text
|
||||
}
|
||||
@@ -270,7 +351,7 @@ impl<W: ?Sized> DrawResult<'_, '_, W> {
|
||||
diag::bump(Counter::SizeReads);
|
||||
diag::size_read(self.child.id(), self.painter.id, self.size);
|
||||
}
|
||||
self.painter.depend_on_size(self.child);
|
||||
self.painter.depend_on_size(self.child, true);
|
||||
self.size
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user