Constrain offered boxes with independent widget size bounds
This commit is contained in:
1 parent
4cb6f6882a
commit
2ac0843cb2
18 files changed
+554
-379
No files matched your search
+24
-28
@@ -254,7 +254,6 @@ impl UiRenderState {
|
||||
);
|
||||
}
|
||||
let align = rsc.widgets().alignment(id);
|
||||
let declared = info.declared;
|
||||
// Nothing this widget measured can be dirty while it draws: layout is
|
||||
// one bottom-up walk, so anything deeper has settled or deferred to
|
||||
// its own parent, and a deferred one leaves that parent marked.
|
||||
@@ -268,7 +267,7 @@ impl UiRenderState {
|
||||
.then(|| self.retained_answer(id, region, info))
|
||||
.flatten()
|
||||
.and_then(|answer| {
|
||||
let placed = info.placed.placement(region, answer.size, declared, align);
|
||||
let placed = info.placed.placement(region, answer.size, align);
|
||||
self.try_reuse(id, region, placed, info, rsc)
|
||||
.then_some(answer)
|
||||
});
|
||||
@@ -280,7 +279,7 @@ impl UiRenderState {
|
||||
// Where the drawing goes: the part its parent gave it, with the
|
||||
// answer placed inside that part on any axis the parent left
|
||||
// open.
|
||||
let placed = info.placed.placement(region, answer.size, declared, align);
|
||||
let placed = info.placed.placement(region, answer.size, align);
|
||||
if placed != region {
|
||||
self.relocate(id, placed, info, rsc);
|
||||
}
|
||||
@@ -379,10 +378,7 @@ impl UiRenderState {
|
||||
size_deps,
|
||||
request_deps,
|
||||
scratch,
|
||||
// What the ask holds for is part of what the drawing holds for:
|
||||
// a box the widget's own rule took past the offer was decided in
|
||||
// this window, and at the root nobody else keeps that range.
|
||||
own: info.ask_holds,
|
||||
own: LayoutHolds::ANY,
|
||||
under,
|
||||
answer_under: LayoutHolds::ANY,
|
||||
depth: info.depth,
|
||||
@@ -437,9 +433,9 @@ impl UiRenderState {
|
||||
// rel base is the answer wherever the ask declared a length: it was
|
||||
// resolved into the rel base when the widget was asked, and resolving
|
||||
// it again here would take the fraction of a fraction.
|
||||
let rules = rsc.widgets().size_rules(id).clone();
|
||||
let rules = rsc.widgets().size_rules(id);
|
||||
let ruled = |axis: Axis, reported: LayoutLen| {
|
||||
if matches!(rules[axis], crate::SizeRule::Request(_)) {
|
||||
if rules[axis].deferred().is_some() {
|
||||
return info.rel_base[axis].into();
|
||||
}
|
||||
match rules[axis].exact() {
|
||||
@@ -470,18 +466,30 @@ impl UiRenderState {
|
||||
// it is a length only to whoever divides one, and the box that
|
||||
// divider gives is a box this widget is asked in, where the bound is
|
||||
// applied to it.
|
||||
let mut bounded = LayoutHolds::ANY;
|
||||
// Widgets may widen their own read ranges, but not the ask's constraints.
|
||||
let mut own_holds = own.and(info.ask_holds);
|
||||
for axis in Axis::BOTH {
|
||||
let answer = size[axis];
|
||||
if answer.leftover != Weight::ZERO {
|
||||
continue;
|
||||
}
|
||||
let (held, kept) = info.bounds[axis].outside(answer.without_leftover(), window[axis]);
|
||||
bounded[axis].window = kept;
|
||||
own_holds[axis].window = own_holds[axis].window.and(kept);
|
||||
if let Some(held) = held {
|
||||
size[axis] = held.into();
|
||||
}
|
||||
}
|
||||
// A rule that is a fraction of the rel base is answered with the
|
||||
// rel base's own length, so the answer is that rel base's and not just
|
||||
// that many pixels of this window -- the same pin a widget that read
|
||||
// its rel base took for its drawing. A bound counts: which side of it
|
||||
// the box fell was decided against this rel base, and the same box of
|
||||
// a different one can fall on the other.
|
||||
for axis in Axis::BOTH {
|
||||
if rules[axis].has_fraction() {
|
||||
own_holds[axis].rel_base = Some(info.rel_base[axis]);
|
||||
}
|
||||
}
|
||||
// A widget that clipped its contents to its box drew nothing outside
|
||||
// it, so reporting more than the box asks to be placed at a length it
|
||||
// does not occupy -- and its parent would place the part it cut off.
|
||||
@@ -509,18 +517,6 @@ impl UiRenderState {
|
||||
if let Some(idx) = retired_move {
|
||||
self.moves.remove(idx);
|
||||
}
|
||||
// A rule that is a fraction of the rel base is answered with the
|
||||
// rel base's own length, so the answer is that rel base's and not just
|
||||
// that many pixels of this window -- the same pin a widget that read
|
||||
// its rel base took for its drawing. A bound counts: which side of it
|
||||
// the box fell was decided against this rel base, and the same box of
|
||||
// a different one can fall on the other.
|
||||
let mut own_holds = own.and(bounded);
|
||||
for axis in Axis::BOTH {
|
||||
if rules[axis].has_fraction() {
|
||||
own_holds[axis].rel_base = Some(info.rel_base[axis]);
|
||||
}
|
||||
}
|
||||
let answer_holds = own_holds.and(answer_under);
|
||||
let holds = under
|
||||
.iter()
|
||||
@@ -798,7 +794,6 @@ impl UiRenderState {
|
||||
let placed = place.placement(
|
||||
region,
|
||||
active.measured().unwrap_or(active.size),
|
||||
active.declared,
|
||||
active.own_align,
|
||||
);
|
||||
let info = DrawInfo {
|
||||
@@ -823,8 +818,8 @@ impl UiRenderState {
|
||||
|
||||
/// The rel base and the box a widget already drawn is given at `place` of
|
||||
/// the box its parent is being taken as. What narrowed its rel base and what
|
||||
/// it declared are its own record's, so both are resolved against that
|
||||
/// parent's rel base again exactly as the first ask resolved them.
|
||||
/// it declared are its own record's. Declared lengths stay as the ask
|
||||
/// resolved them; the destination only decides where they sit.
|
||||
fn ask_again(active: &ActiveData, at: &Placing, place: PlaceDesc) -> (UiVec2, UiRegion) {
|
||||
place.rel_base_and_region(at.region, at.rel_base, active.declared, active.own_align)
|
||||
}
|
||||
@@ -1195,10 +1190,11 @@ impl UiRenderState {
|
||||
active.asked,
|
||||
);
|
||||
let active = &self.active[&id];
|
||||
let declared_changed = ask.declared != active.declared;
|
||||
// Even an inactive bound changes what the parent must track about its offer.
|
||||
let constraints_changed = ask.declared != active.declared || ask.bounds != active.bounds;
|
||||
let alignment_changed = rsc.widgets().alignment(id) != active.own_align;
|
||||
if let Some(parent) = active.parent
|
||||
&& (declared_changed
|
||||
&& (constraints_changed
|
||||
|| alignment_changed
|
||||
|| active.re_asked
|
||||
|| !active.drawn
|
||||
|
||||
Reference in new issue
Block a user