Say layout's operations by name, and index a pair by its axis
Four rounds over the same idea: an expression that needed a comment to say
what it computed wanted to be a named operation.
The placement description is built by chaining off the value that says it.
`UiSpan::within_desc`/`shifted_desc` and `Len::as_desc` replace the
`PlaceDescAxis::` constructors, `PlaceDescAxis::axis` lifts one axis into a
pair with the whole box across it, and `PlaceDesc::per_axis` covers the case
where the two axes differ. `beside` is dropped: `from_axis` already said it.
Seven module-level functions become methods on the value each took first --
`Widgets::declared_lens`, `LayoutLen::fills`, `PlaceDesc::placement` and
`::rel_base_and_region`, `Size::within_box`, `UiRegion::at_origin` and
`::as_translation`.
`UiSpan::place` is the aligned-placement rule, which was written out three
times; `LayoutLen::without_leftover` is the sibling `apply_leftover` never
had, at six sites; `is_px` and `is_only_leftover` name field comparisons the
surrounding comments had to translate; `Holds::covers` was interval
containment spelled out by hand. A span's `shared` loses the two arguments
that did not vary across its loop.
`LayoutHolds` was four two-element arrays where every other pair here is a
struct of two per-axis values, so nothing it did could be written once.
It becomes `AxisHolds` on `x` and `y`, and `and`, `covers` and `contains`
lose their loops.
Every pair gets `Index<Axis>`/`IndexMut<Axis>` through one macro, and the
eighteen `axis`/`axis_mut` methods go. `const_index` keeps the accessors
usable in const context.
Cold layout is unchanged: `layout_dump` over 400 depth-5 trees is identical
to 58ce74d byte for byte, across all 34,492 boxes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
58ce74dd7d
commit
55df32a33c
21 files changed
+465
-490
No files matched your search
+17
-29
@@ -18,10 +18,6 @@ impl Widget for Span {
|
||||
Sign::Pos => UiSpan::new(from, to),
|
||||
Sign::Neg => UiSpan::new(far - to, far - from),
|
||||
};
|
||||
// Across itself the child sits where its own alignment says, in the
|
||||
// whole of the row: a span is what contains its children there, and
|
||||
// nothing divides that axis.
|
||||
let across = PlaceDescAxis::WHOLE;
|
||||
// A length for every child before their final slots are chosen: from
|
||||
// a hint where one says, and from drawing otherwise. The rel base passes
|
||||
// through unchanged, so `rel(0.5)` is half the area this span was
|
||||
@@ -34,10 +30,11 @@ impl Widget for Span {
|
||||
let len = match painter.size_hint(child, axis) {
|
||||
Some(len) => len,
|
||||
None => {
|
||||
let room = PlaceDescAxis::shifted(along(cursor, far));
|
||||
painter
|
||||
.widget_at(child, PlaceDesc::from_axis(axis, room, across))
|
||||
.len(axis)
|
||||
// Across itself the child sits where its own alignment
|
||||
// says, in the whole of the row: a span is what contains
|
||||
// its children there, and nothing divides that axis.
|
||||
let room = along(cursor, far).shifted_desc().axis(axis);
|
||||
painter.widget_at(child, room).len(axis)
|
||||
}
|
||||
};
|
||||
cursor.px += len.px + self.gap;
|
||||
@@ -58,7 +55,7 @@ impl Widget for Span {
|
||||
|
||||
// What is left for the shares to divide: the row less everything
|
||||
// fixed, as a length of the rel base rather than a number of pixels.
|
||||
let room = far - Len::from_parts(total.rel, total.px);
|
||||
let room = far - total.without_leftover();
|
||||
// Whether anything is left over is a question in pixels: `rel(0.5)`
|
||||
// beside 300 px is full at 600 and overfull at 400. Asked of `room`
|
||||
// itself, and answered back through the same expression, so the
|
||||
@@ -94,24 +91,26 @@ impl Widget for Span {
|
||||
let mut taken = Weight::ZERO;
|
||||
let mut start = Len::rel_min();
|
||||
let mut ortho = LayoutLen::ZERO;
|
||||
let shared = |fixed: Len, taken: Weight| match taken == Weight::ZERO {
|
||||
true => fixed,
|
||||
false => fixed + room.scale(Rel::ratio(taken, total.leftover)),
|
||||
};
|
||||
for (child, &len) in self.children.iter().zip(&lens) {
|
||||
// A child asking for nothing but a part of what is left over,
|
||||
// when nothing is, is not drawn at all. One that also asked for
|
||||
// pixels or a fraction keeps those and overflows.
|
||||
if len.leftover > Weight::ZERO && len.px == Px::ZERO && len.rel == Rel::ZERO && !shares
|
||||
{
|
||||
if len.is_only_leftover() && !shares {
|
||||
painter.undraw(child);
|
||||
fixed.px += self.gap;
|
||||
start = shared(fixed, taken, total.leftover, room);
|
||||
start = shared(fixed, taken);
|
||||
continue;
|
||||
}
|
||||
let from = start;
|
||||
if len.leftover > Weight::ZERO && shares {
|
||||
taken += len.leftover;
|
||||
}
|
||||
fixed.px += len.px;
|
||||
fixed.rel += len.rel;
|
||||
start = shared(fixed, taken, total.leftover, room);
|
||||
fixed += len.without_leftover();
|
||||
start = shared(fixed, taken);
|
||||
// Along the row the span says where the child goes, and that slot
|
||||
// is the child's box outright rather than something to place an
|
||||
// answer inside again. A share is decided here and nowhere
|
||||
@@ -120,8 +119,7 @@ impl Widget for Span {
|
||||
// fixed child's slot is its own answer, so a drawing made in the
|
||||
// room is put there as it is, and one not made yet is made here.
|
||||
let slot = along(from, start);
|
||||
let slot_place = PlaceDescAxis::shifted(slot).fills();
|
||||
let mut place = PlaceDesc::from_axis(axis, slot_place, across);
|
||||
let mut place = slot.shifted_desc().fills().axis(axis);
|
||||
if len.leftover > Weight::ZERO && shares {
|
||||
place = place.rel_base(axis, slot.len());
|
||||
}
|
||||
@@ -131,14 +129,14 @@ impl Widget for Span {
|
||||
// span's own eventual width admits multiple fixed points.
|
||||
// A scalable child therefore makes Children scalable too;
|
||||
// only fixed children are compared with one another.
|
||||
if used.rel != Rel::ZERO || used.leftover != Weight::ZERO {
|
||||
if !used.is_px() {
|
||||
ortho = LayoutLen::LEFTOVER;
|
||||
} else if ortho.leftover == Weight::ZERO {
|
||||
ortho.px = ortho.px.max(used.px);
|
||||
}
|
||||
}
|
||||
fixed.px += self.gap;
|
||||
start = shared(fixed, taken, total.leftover, room);
|
||||
start = shared(fixed, taken);
|
||||
}
|
||||
|
||||
// Carried whole rather than collapsed to one share: a span that sizes
|
||||
@@ -157,16 +155,6 @@ impl Widget for Span {
|
||||
}
|
||||
}
|
||||
|
||||
/// Where a row has reached: everything fixed before this point, which is a
|
||||
/// sum and exact, plus the share of the room the weights so far are worth,
|
||||
/// which is one rounding wherever it is asked for.
|
||||
fn shared(fixed: Len, taken: Weight, weight: Weight, room: Len) -> Len {
|
||||
if taken == Weight::ZERO {
|
||||
return fixed;
|
||||
}
|
||||
fixed + room.scale(Rel::ratio(taken, weight))
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub fn empty(dir: Dir) -> Self {
|
||||
Self {
|
||||
|
||||
Reference in new issue
Block a user