diff --git a/core/src/ui/mod.rs b/core/src/ui/mod.rs index e7dfe67..d6767da 100644 --- a/core/src/ui/mod.rs +++ b/core/src/ui/mod.rs @@ -20,7 +20,7 @@ pub use active::*; pub use holds::*; pub use layout_holds::*; pub use painter::{Painter, PrimitiveLike}; -pub use place::*; +pub use place::{PlaceDesc, PlaceDescAxis, RetainedPrimitive}; pub use render_state::*; #[derive(Default)] diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index 6cc23db..04c202d 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -8,7 +8,10 @@ use crate::{ GlyphPrimitive, Mask, MaskIdx, MoveIdx, Primitive, PrimitiveInst, PrimitiveKind, TexturePrimitive, }, - ui::render_state::{DrawInfo, Placing}, + ui::{ + place::{PlaceSpan, RelBase}, + render_state::{DrawInfo, Placing}, + }, }; /// makes your surfaces look pretty @@ -156,11 +159,15 @@ impl<'a> Painter<'a> { /// only moves its child does not pin its drawing to a rel base. fn resolve_rel_base(&mut self, mut place: PlaceDesc) -> PlaceDesc { for axis in Axis::BOTH { - if let Some(span) = place[axis].narrows_rel_base() { - let len = span.len(); - let stated = (len != Len::FULL).then(|| len.within_len(self.rel_base(axis))); - place[axis] = place[axis].with_rel_base(stated); - } + let at = &mut place[axis]; + let (RelBase::WithRegion, PlaceSpan::Within(span)) = (at.rel_base, at.span) else { + continue; + }; + let len = span.len(); + at.rel_base = match len == Len::FULL { + true => RelBase::Inherit, + false => RelBase::Len(len.within_len(self.rel_base(axis))), + }; } place } @@ -255,7 +262,7 @@ impl<'a> Painter<'a> { let place = self.resolve_rel_base(place.into()); let states_rel_base = Axis::BOTH .iter() - .any(|&axis| place[axis].stated_rel_base().is_some()); + .any(|&axis| matches!(place[axis].rel_base, RelBase::Len(_))); if states_rel_base || !self.children.contains(&id.id()) { return self.widget_at(id, place); } @@ -601,16 +608,20 @@ impl Painter<'_> { for axis in Axis::BOTH { let declared = declared[axis]; let holds = holds[axis]; + let at = place[axis]; let result = &mut result[axis]; // Every read became pixels against the window, so a range on // it is already in this widget's terms. result.window = holds.window; - let at = place[axis]; - let reaches = at.stated_rel_base().is_none() - && !at.is_sized() + // A length this widget named -- a resolved share, a box a sibling + // decided, a box it sized outright, which is its own base -- is + // not a length of this widget's rel base, so a pin on it stops + // here. So does a declaration in pixels: no length of either base + // is in it to see. + let reaches = !matches!(at.rel_base, RelBase::Len(_)) && declared.is_none_or(|len| len.rel != Rel::ZERO); result.rel_base = holds.rel_base.and(reaches.then(|| self.rel_base[axis])); - match (at.within_span(), declared.is_some()) { + match (at.span, declared) { // Its box is a part of this widget's own box, in that box's // own lengths, so what it holds for maps back through that // part into a range on this widget's box. A length it pinned @@ -618,7 +629,7 @@ impl Painter<'_> { // part is the whole of the box less pixels, which is the one // shape that inverts exactly; any other part pins this // widget's own length. - (Some(span), false) => { + (PlaceSpan::Within(span), None) => { let part_len = span.len(); result.region = holds.region.through(part_len); result.region_len = holds.region_len.map(|pinned| match part_len.rel { @@ -641,7 +652,7 @@ impl Painter<'_> { impl Widgets { /// What a widget's box is where a rule or its own hint says so outright. - pub(crate) fn declared_lens(&self, id: WidgetId) -> Declared { + pub(super) fn declared_lens(&self, id: WidgetId) -> Declared { let rules = self.size_rules(id); let widget = self.get_dyn(id); Declared::from_axes(|axis| { @@ -668,7 +679,7 @@ impl LayoutLen { /// the rule already gave the region its length, and the rule's length is /// what the widget reports there. And an axis the parent decided from /// the answer is the answer already. - pub(crate) fn fills(self, declared: Option, decided: bool) -> bool { + pub(super) fn fills(self, declared: Option, decided: bool) -> bool { self.leftover != Weight::ZERO || declared.is_some() || decided } } @@ -683,7 +694,7 @@ impl PlaceDesc { /// part. That is what makes a fraction the same fraction wherever the part /// it is placed in sits and however long it is -- the fraction is resolved /// once, here, against the rel base it was reported of. - pub(crate) fn placement( + pub(super) fn placement( self, region: UiRegion, size: Size, @@ -693,7 +704,7 @@ impl PlaceDesc { let mut placed = region; for axis in Axis::BOTH { let reported = size[axis]; - if reported.fills(declared[axis], self[axis].does_fill()) { + if reported.fills(declared[axis], self[axis].fills) { continue; } placed[axis] = placed[axis].place(reported.without_leftover(), align[axis]); @@ -711,7 +722,7 @@ impl PlaceDesc { /// name. The child's declaration is a fraction of whichever reached it, and /// is the only one that also places the box: a box the caller decided is /// what `place` names. - pub(crate) fn rel_base_and_region( + pub(super) fn rel_base_and_region( self, own: UiRegion, parent_rel_base: UiVec2, @@ -722,9 +733,10 @@ impl PlaceDesc { let mut rel_base = parent_rel_base; let mut region = given; for axis in Axis::BOTH { - let base = self[axis] - .stated_rel_base() - .unwrap_or_else(|| parent_rel_base[axis]); + let base = match self[axis].rel_base { + RelBase::Len(len) => len, + RelBase::Inherit | RelBase::WithRegion => parent_rel_base[axis], + }; let len = declared[axis] .map(|len| len.within_len(base)) .unwrap_or(base); diff --git a/core/src/ui/place.rs b/core/src/ui/place.rs index fe51d64..b844e87 100644 --- a/core/src/ui/place.rs +++ b/core/src/ui/place.rs @@ -11,21 +11,23 @@ use crate::{Axis, AxisAlign, Len, PrimitiveHandle, RegionAlign, UiRegion, UiSpan /// it differently, so it is said here. #[derive(Clone, Copy, Debug, PartialEq)] pub struct PlaceDescAxis { - span: PlaceSpan, - fills: bool, - rel_base: RelBase, + pub span: PlaceSpan, + pub fills: bool, + pub rel_base: RelBase, } #[derive(Clone, Copy, Debug, PartialEq)] -enum PlaceSpan { +pub enum PlaceSpan { Within(UiSpan), Shifted(UiSpan), Sized(Len), } -/// What a child's fractions are of, where the caller has not named a length. +/// What a child's fractions are of. [`PlaceSpan::Sized`] is a length the +/// caller named, which is always its own base, so nothing here constructs one +/// beside anything but [`Self::Len`]. #[derive(Clone, Copy, Debug, PartialEq)] -enum RelBase { +pub enum RelBase { /// The caller's own, unchanged. Inherit, /// The caller's own, narrowed the way the region is. @@ -61,14 +63,8 @@ impl PlaceDescAxis { self } - /// Whether the region is the placement outright, rather than a box the - /// answer is placed inside. - pub(crate) const fn does_fill(self) -> bool { - self.fills - } - /// Where it lands in the coordinates `own` is in. - pub(crate) fn of(self, own: UiSpan, align: AxisAlign) -> UiSpan { + pub fn of(self, own: UiSpan, align: AxisAlign) -> UiSpan { match self.span { PlaceSpan::Within(span) => span.within(&own), PlaceSpan::Shifted(mut span) => { @@ -78,50 +74,6 @@ impl PlaceDescAxis { PlaceSpan::Sized(len) => own.place(len, align), } } - - /// The child's rel base, where this says one outright. `None` forwards - /// the caller's own, and [`RelBase::WithRegion`] is resolved by whoever - /// can read that rel base, so it does not reach here. - pub(crate) const fn stated_rel_base(self) -> Option { - match self.rel_base { - RelBase::Len(len) => Some(len), - _ => None, - } - } - - /// The length this narrows the caller's rel base by, where it does. - /// `None` leaves that rel base alone, and reading it is then a - /// dependency the caller does not take. - pub(crate) const fn narrows_rel_base(self) -> Option { - match (self.rel_base, self.span) { - (RelBase::WithRegion, PlaceSpan::Within(span)) => Some(span), - _ => None, - } - } - - /// The span it composes into the caller's box, where that is what it - /// does: the one case whose validity maps back through the part. - pub(crate) const fn within_span(self) -> Option { - match self.span { - PlaceSpan::Within(span) => Some(span), - _ => None, - } - } - - /// Whether the caller decided this length rather than a place along its - /// own box, which is what stops its length reaching the child at all. - pub(crate) const fn is_sized(self) -> bool { - matches!(self.span, PlaceSpan::Sized(_)) - } - - /// The same, with its rel base stated outright. - pub(crate) const fn with_rel_base(mut self, len: Option) -> Self { - self.rel_base = match len { - Some(len) => RelBase::Len(len), - None => RelBase::Inherit, - }; - self - } } /// Where a child is asked, on both axes. A [`UiRegion`] converts into the @@ -172,7 +124,7 @@ impl PlaceDesc { } /// The box each axis names, in the coordinates `own` is in. - pub(crate) fn of(self, own: UiRegion, align: RegionAlign) -> UiRegion { + pub fn of(self, own: UiRegion, align: RegionAlign) -> UiRegion { UiRegion::new(self.x.of(own.x, align.x), self.y.of(own.y, align.y)) } }