diff --git a/core/src/orientation/len.rs b/core/src/orientation/len.rs index c272467..f1bcc60 100644 --- a/core/src/orientation/len.rs +++ b/core/src/orientation/len.rs @@ -158,6 +158,13 @@ impl LayoutLen { self.leftover > Weight::ZERO && self.without_leftover() == Len::ZERO } + /// This as a length of a box, where it is one. `leftover` is not: a + /// share of what is left over is a length only to whoever divides one, + /// so it passes up in the reported size instead and is resolved there. + pub fn declared(self) -> Option { + (self.leftover == Weight::ZERO).then(|| self.without_leftover()) + } + /// What this takes whatever is left over: the reading of a length for /// anyone not dividing a box between siblings, where a share is a claim /// on someone else's room rather than a length of its own. diff --git a/core/src/ui/active.rs b/core/src/ui/active.rs index 0f943bf..ab0a493 100644 --- a/core/src/ui/active.rs +++ b/core/src/ui/active.rs @@ -1,5 +1,5 @@ use crate::{ - LayerId, LayoutHolds, LayoutLen, MaskIdx, MoveIdx, PlaceDesc, RegionAlign, RetainedPrimitive, + Declared, LayerId, LayoutHolds, MaskIdx, MoveIdx, PlaceDesc, RegionAlign, RetainedPrimitive, Size, TextureHandle, UiRegion, UiVec2, WidgetId, }; @@ -59,7 +59,7 @@ pub struct ActiveData { /// The declared lengths whoever drew this widget resolved into its rel base. /// A change to one moves a box this widget cannot fix by drawing again, /// and comparing them is what says so. - pub declared: [Option; 2], + pub declared: Declared, /// Its alignment when it was last drawn, which a change to the property /// is found against. pub own_align: RegionAlign, diff --git a/core/src/ui/painter.rs b/core/src/ui/painter.rs index ba174e3..ec3993e 100644 --- a/core/src/ui/painter.rs +++ b/core/src/ui/painter.rs @@ -1,7 +1,7 @@ #[cfg(feature = "layout-diagnostics")] use crate::layout_diagnostics::{self as diag, Counter}; use crate::{ - Axis, Holds, LayoutHolds, LayoutLen, Len, PlaceDesc, Px, PxVec2, RegionAlign, Rel, + Axis, Declared, Holds, LayoutHolds, LayoutLen, Len, PlaceDesc, Px, PxVec2, RegionAlign, Rel, RenderedText, RetainedPrimitive, Size, StrongWidget, TextAttrs, TextBuffer, TextData, TextureHandle, UiRegion, UiRenderState, UiRsc, UiVec2, Weight, WidgetId, Widgets, render::{ @@ -292,7 +292,7 @@ impl<'a> Painter<'a> { /// it resolves into its rel base. Reading them depends on nothing -- the box /// that comes of them is kept on the child, and `redraw` compares it /// there. - fn declared_lens(&self, id: &StrongWidget) -> [Option; 2] { + fn declared_lens(&self, id: &StrongWidget) -> Declared { self.rsc.widgets().declared_lens(id.id()) } @@ -599,11 +599,11 @@ impl Painter<'_> { holds: LayoutHolds, region: UiRegion, place: PlaceDesc, - declared: [Option; 2], + declared: Declared, ) -> LayoutHolds { let mut result = LayoutHolds::ANY; for axis in AXES { - let declared = declared[axis as usize]; + let declared = declared[axis]; let holds = holds[axis]; let result = &mut result[axis]; // Every read became pixels against the window, so a range on @@ -644,13 +644,11 @@ impl Painter<'_> { } impl Widgets { - /// What a widget declares a length of its box to be. `leftover` is not - /// one: a share of what is left over is only a length to the widget - /// dividing one, so it passes up in the size instead. - pub(crate) fn declared_lens(&self, id: WidgetId) -> [Option; 2] { + /// 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 { let rules = self.size_rules(id); let widget = self.get_dyn(id); - AXES.map(|axis| { + Declared::per_axis(|axis| { rules[axis].declared().or_else(|| { // A hint still narrows the box where no rule does, which is // how a widget with a natural pixel size -- an image, a gap @@ -660,7 +658,7 @@ impl Widgets { // the box it was offered. widget .and_then(|widget| widget.size_hint(axis)) - .filter(|len| len.leftover == Weight::ZERO) + .and_then(LayoutLen::declared) }) }) } @@ -674,7 +672,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(crate) fn fills(self, declared: Option, decided: bool) -> bool { self.leftover != Weight::ZERO || declared.is_some() || decided } } @@ -693,14 +691,13 @@ impl PlaceDesc { self, region: UiRegion, size: Size, - declared: [Option; 2], + declared: Declared, align: RegionAlign, ) -> UiRegion { let mut placed = region; for axis in AXES { - let n = axis as usize; let reported = size[axis]; - if reported.fills(declared[n], self[axis].does_fill()) { + if reported.fills(declared[axis], self[axis].does_fill()) { continue; } placed[axis] = placed[axis].place(reported.without_leftover(), align[axis]); @@ -722,22 +719,21 @@ impl PlaceDesc { self, own: UiRegion, parent_rel_base: UiVec2, - declared: [Option; 2], + declared: Declared, align: RegionAlign, ) -> (UiVec2, UiRegion) { let given = self.of(own, align); let mut rel_base = parent_rel_base; let mut region = given; for axis in AXES { - let n = axis as usize; let base = self[axis] .stated_rel_base() .unwrap_or_else(|| parent_rel_base[axis]); - let len = declared[n] - .map(|len| len.without_leftover().within_len(base)) + let len = declared[axis] + .map(|len| len.within_len(base)) .unwrap_or(base); rel_base[axis] = len; - if declared[n].is_some() { + if declared[axis].is_some() { region[axis] = given[axis].place(len, align[axis]); } } diff --git a/core/src/ui/render_state.rs b/core/src/ui/render_state.rs index 031431d..fdcc65f 100644 --- a/core/src/ui/render_state.rs +++ b/core/src/ui/render_state.rs @@ -1,9 +1,9 @@ #[cfg(feature = "layout-diagnostics")] use crate::layout_diagnostics::{self as diag, Counter, ReuseOutcome, TimerKind}; use crate::{ - ActiveData, Axis, DrawLayers, IdLike, LayoutHolds, LayoutLen, Len, MaskIdx, MoveIdx, Moves, - Painter, PixelRegion, PlaceDesc, PxVec2, Rel, Size, StrongWidget, UiRegion, UiRsc, UiSpan, - UiVec2, Weight, WidgetId, Widgets, + ActiveData, Axis, Declared, DrawLayers, IdLike, LayoutHolds, LayoutLen, Len, MaskIdx, MoveIdx, + Moves, Painter, PixelRegion, PlaceDesc, PxVec2, Rel, Size, StrongWidget, UiRegion, UiRsc, + UiSpan, UiVec2, Weight, WidgetId, Widgets, util::{HashMap, Vec2}, }; @@ -868,7 +868,7 @@ impl UiRenderState { children: Vec::new(), size_deps: Vec::new(), move_idx: info.parent_move, - declared: [None; 2], + declared: Declared::NONE, own_align: rsc.widgets().alignment(id), parent_move: info.parent_move, mask: info.mask, diff --git a/core/src/widget/size_rule.rs b/core/src/widget/size_rule.rs index d3a0f5e..728a107 100644 --- a/core/src/widget/size_rule.rs +++ b/core/src/widget/size_rule.rs @@ -1,5 +1,5 @@ use crate::util::impl_axis_index; -use crate::{LayoutLen, Weight}; +use crate::{Axis, LayoutLen, Len}; /// What a widget's length on one axis is, as a rule its parent applies where /// it draws it rather than an answer the widget gives about itself. @@ -20,14 +20,9 @@ pub enum SizeRule { impl SizeRule { /// The length this rule gives without the widget being drawn, if it can - /// give one. `leftover` is never among them: a share is a length only to - /// whoever divides one, so it passes up in the reported size instead and - /// is resolved there. - pub fn declared(&self) -> Option { - match self { - Self::Exact(len) if len.leftover == Weight::ZERO => Some(*len), - _ => None, - } + /// give one. + pub fn declared(&self) -> Option { + self.exact().and_then(LayoutLen::declared) } /// The length this rule gives outright, whatever the widget reports -- @@ -72,3 +67,28 @@ pub struct SizeRules { } impl_axis_index!(SizeRules => SizeRule); + +/// What a widget's box is on each axis where something says so outright, +/// before it is drawn: a rule beside it, or a hint it gives about itself. +/// Whoever draws the widget resolves these against its rel base. +/// +/// A [`Len`] rather than a [`LayoutLen`], because a share can never be one +/// -- see [`LayoutLen::declared`]. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Declared { + pub x: Option, + pub y: Option, +} + +impl Declared { + pub const NONE: Self = Self { x: None, y: None }; + + pub fn per_axis(f: impl Fn(Axis) -> Option) -> Self { + Self { + x: f(Axis::X), + y: f(Axis::Y), + } + } +} + +impl_axis_index!(Declared => Option);