Say rel base, and give containers back a box to hand over
`frame` named a length, not a rectangle, which was the one word in the layout vocabulary that lied about its own shape. It is `rel_base`: what a fraction a widget declares or reports is a fraction of. Three API changes with it, all for containers that do one simple thing: - `widget_within(id, region)` returns, taking a box in the widget's own coordinates and deriving the child's rel base from it. `Offset` and `Pad` are one call each again. `Offset` also stops reading `region_len`, which pinned its drawing to a box length it does not care about. - `place_at` takes the rel base, returns the answer, and asks the child where there is no answer to re-express. Which of the two happens is the painter's to work out, so `Span`'s second pass is one call and its `drawn_across` bookkeeping is gone. - `Part::All` is a `Part::WHOLE` constant rather than a variant, since it was exactly `Of(UiSpan::FULL)` and bought a separate arm in two matches. Measured at 0.07% of instructions retired against 0.04% run-to-run noise. Cold layout is byte-identical to `84dad21` over 400 depth-5 trees.
This commit is contained in:
1 parent
a904cf4f36
commit
aeb60e50f5
16 files changed
+246
-238
No files matched your search
+10
-22
@@ -10,7 +10,7 @@ pub struct Span {
|
||||
impl Widget for Span {
|
||||
fn draw(&mut self, painter: &mut Painter) -> Size {
|
||||
let axis = self.dir.axis;
|
||||
// The row: this span's own box, as a length of the frame its children
|
||||
// The row: this span's own box, as a length of the rel base its children
|
||||
// are laid out against. Its start is nothing's business -- a slot is
|
||||
// a length from it -- so what this reads is the length alone.
|
||||
let far = painter.region_len(axis);
|
||||
@@ -21,29 +21,23 @@ impl Widget for Span {
|
||||
// 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 = Place::Within(Part::All);
|
||||
let across = Place::Within(Part::WHOLE);
|
||||
// A length for every child before their final slots are chosen: from
|
||||
// a hint where one says, and from drawing otherwise. The frame passes
|
||||
// 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
|
||||
// given whatever else is in it and wherever this child sits among
|
||||
// them; what a drawn child is asked in is the room left from the
|
||||
// cursor, because a text has to wrap at the width actually there.
|
||||
let mut cursor = Len::rel_min();
|
||||
let mut lens = Vec::with_capacity(self.children.len());
|
||||
let mut drawn_across = Vec::with_capacity(self.children.len());
|
||||
for child in &self.children {
|
||||
let len = match painter.size_hint(child, axis) {
|
||||
Some(len) => {
|
||||
drawn_across.push(None);
|
||||
len
|
||||
}
|
||||
Some(len) => len,
|
||||
None => {
|
||||
let room = Place::Within(Part::From(along(cursor, far)));
|
||||
let size = painter
|
||||
painter
|
||||
.widget_at(child, [None; 2], axis.pair(room, across))
|
||||
.size();
|
||||
drawn_across.push(Some(size.axis(!axis)));
|
||||
size.axis(axis)
|
||||
.len(axis)
|
||||
}
|
||||
};
|
||||
cursor.px += len.px + self.gap;
|
||||
@@ -63,7 +57,7 @@ impl Widget for Span {
|
||||
);
|
||||
|
||||
// What is left for the shares to divide: the row less everything
|
||||
// fixed, as a length of the frame rather than a number of pixels.
|
||||
// fixed, as a length of the rel base rather than a number of pixels.
|
||||
let room = far - Len::from_parts(total.rel, total.px);
|
||||
// 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`
|
||||
@@ -100,7 +94,7 @@ impl Widget for Span {
|
||||
let mut taken = Weight::ZERO;
|
||||
let mut start = Len::rel_min();
|
||||
let mut ortho = LayoutLen::ZERO;
|
||||
for ((child, &len), &across_len) in self.children.iter().zip(&lens).zip(&drawn_across) {
|
||||
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.
|
||||
@@ -121,7 +115,7 @@ impl Widget for Span {
|
||||
// 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
|
||||
// else: its slot narrows its frame, and the child is asked in
|
||||
// else: its slot narrows its rel base, and the child is asked in
|
||||
// it, since a text wraps at the width it is actually given. A
|
||||
// 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.
|
||||
@@ -131,13 +125,7 @@ impl Widget for Span {
|
||||
if len.leftover > Weight::ZERO && shares {
|
||||
narrow[axis as usize] = Some(slot.len());
|
||||
}
|
||||
let used = match (across_len, narrow[axis as usize]) {
|
||||
(Some(across_len), None) => {
|
||||
painter.place_at(child, place);
|
||||
across_len
|
||||
}
|
||||
_ => painter.widget_at(child, narrow, place).len(!axis),
|
||||
};
|
||||
let used = painter.place_at(child, narrow, place).len(!axis);
|
||||
if shrinks {
|
||||
// Choosing between a fixed and a relative length from the
|
||||
// span's own eventual width admits multiple fixed points.
|
||||
|
||||
Reference in new issue
Block a user