Retain layout sizes by pixel axis

This commit is contained in:
iris-ai committed 2026-09-14 17:47:21 -04:00
1 parent 82fa6c1123
commit b1b3eca1c0
11 files changed
+371 -69

No files matched your search

+19 -5
View File
@@ -7,17 +7,31 @@ pub struct Aligned {
impl Widget for Aligned {
fn draw(&mut self, painter: &mut Painter) -> Size {
// Drawn where it may be too big, then given its aligned box once its
// size is known.
let size = painter.place(&self.inner, UiRegion::FULL).size();
let known = match self.align.tuple() {
(Some(_), Some(_)) => painter
.known_len(&self.inner, Axis::X, UiRegion::FULL)
.zip(painter.known_len(&self.inner, Axis::Y, UiRegion::FULL))
.map(|(x, y)| Size { x, y }),
(Some(_), None) => painter
.known_len(&self.inner, Axis::X, UiRegion::FULL)
.map(|x| Size { x, y: Len::REST }),
(None, Some(_)) => painter
.known_len(&self.inner, Axis::Y, UiRegion::FULL)
.map(|y| Size { x: Len::REST, y }),
(None, None) => Some(Size::REST),
};
// Drawn where it may be too big only when the aligned axes are not
// already known, then given its aligned box once its size is known.
let had_size = known.is_some();
let size = known.unwrap_or_else(|| painter.place(&self.inner, UiRegion::FULL).size());
let region = match self.align.tuple() {
(Some(x), Some(y)) => size.to_uivec2().align(RegionAlign { x, y }),
(Some(x), None) => UiRegion::new(size.x.apply_rest().align(x), UiSpan::FULL),
(None, Some(y)) => UiRegion::new(UiSpan::FULL, size.y.apply_rest().align(y)),
(None, None) => UiRegion::FULL,
};
painter.place(&self.inner, region);
size
let placed = painter.place(&self.inner, region).size();
if had_size { placed } else { size }
}
/// The aligned box is a fraction of its own, so the child keeps its
+11 -9
View File
@@ -11,13 +11,15 @@ pub struct Scroll {
impl Widget for Scroll {
fn draw(&mut self, painter: &mut Painter) -> Size {
let output_len = painter.output_size().axis(self.axis);
let container_len = UiScalar::abs(painter.px_size().axis(self.axis));
// Draw in the whole container to learn the content's length, then
// place it at the scrolled offset.
let child = painter.place(&self.inner, UiRegion::FULL).size();
let content_len = child
.axis(self.axis)
let output_len = painter.output_len(self.axis);
let container_len = UiScalar::abs(painter.px_len(self.axis));
// Draw in the whole container only when its scrolling-axis length is
// not already known, then place it at the scrolled offset.
let known_len = painter.known_len(&self.inner, self.axis, UiRegion::FULL);
let measured = known_len.is_none();
let child = measured.then(|| painter.place(&self.inner, UiRegion::FULL).size());
let content_len = known_len
.unwrap_or_else(|| child.unwrap().axis(self.axis))
.apply_rest()
.within_len(container_len)
.to_abs(output_len);
@@ -31,8 +33,8 @@ impl Widget for Scroll {
let mut region = UiRegion::FULL.offset(Vec2::from_axis(self.axis, -self.amt, 0.0));
region.axis_mut(self.axis).end = region.axis(self.axis).start.offset(self.content_len);
painter.place(&self.inner, region);
child
let placed = painter.place(&self.inner, region).size();
child.unwrap_or(placed)
}
}
+7 -9
View File
@@ -15,16 +15,14 @@ impl Widget for Span {
let mut cursor = UiScalar::rel_min();
let mut lens = Vec::with_capacity(self.children.len());
for child in &self.children {
let len = match painter.size_hint(child, axis) {
let mut span = UiSpan::new(cursor, UiScalar::rel_max());
if self.dir.sign == Sign::Neg {
span.flip();
}
let region = UiRegion::from_axis(axis, span, UiSpan::FULL);
let len = match painter.known_len(child, axis, region) {
Some(len) => len,
None => {
let mut span = UiSpan::new(cursor, UiScalar::rel_max());
if self.dir.sign == Sign::Neg {
span.flip();
}
let region = UiRegion::from_axis(axis, span, UiSpan::FULL);
painter.place(child, region).len(axis)
}
None => painter.place(child, region).len(axis),
};
cursor.abs += len.abs + self.gap;
cursor.rel += len.rel;