use crate::util::impl_axis_index; use crate::{Axis, Holds, Len, Px, PxVec2, UiRegion, UiVec2}; /// What one evaluation of a widget depends on along one axis: the window /// lengths its reads hold for, the pixel lengths of its own box, and the /// symbolic lengths of that box and of its rel base where either one is what /// it was expressed in. /// /// The symbolic lengths are pins rather than ranges: a container places its /// children as lengths of its rel base measured from where its own box starts, /// so what it draws turns on that box's length and on nothing about where it /// is. A box pin reaches the parent only where the box it pinned is the /// parent's own; anywhere else the parent chose that length itself, and a /// widget pinned this way is checked when it is re-placed. /// /// A rel base pin says the answer or the drawing is a fraction of the rel base, /// which is a different length wherever the rel base is a different one -- at /// the same window size, so no range of window pixels can say it. A length /// of the rel base that is only pixels is not one: it is that many pixels /// whatever the rel base turns out to be. #[derive(Clone, Copy, Debug, PartialEq)] pub struct AxisHolds { pub window: Holds, pub rel_base: Option, pub region: Holds, pub region_len: Option, } impl AxisHolds { pub const ANY: Self = Self { window: Holds::ANY, rel_base: None, region: Holds::ANY, region_len: None, }; pub fn and(self, other: Self) -> Self { // Two pins of the same length disagreeing would mean one drawing was // a fraction of two different lengths at once. debug_assert!( self.region_len.is_none() || other.region_len.is_none() || self.region_len == other.region_len ); debug_assert!( self.rel_base.is_none() || other.rel_base.is_none() || self.rel_base == other.rel_base ); Self { window: self.window.and(other.window), rel_base: self.rel_base.or(other.rel_base), region: self.region.and(other.region), region_len: self.region_len.or(other.region_len), } } pub fn covers(self, other: Self) -> bool { self.window.covers(other.window) && self.region.covers(other.region) && self .region_len .is_none_or(|len| other.region_len == Some(len)) && self.rel_base.is_none_or(|len| other.rel_base == Some(len)) } /// Whether a widget in a box `len` long, with that rel base, in that /// window, is one this drawing holds for. pub fn contains(self, window: Px, rel_base: Len, len: Len) -> bool { self.window.contains(window) && self.rel_base.is_none_or(|pinned| pinned == rel_base) && self.region.contains(len.to_px(window)) && self.region_len.is_none_or(|pinned| pinned == len) } } /// [`AxisHolds`] on both axes. Every question asked of it is asked of one /// axis at a time, since a widget that read one length holds for any length /// of the other. #[derive(Clone, Copy, Debug, PartialEq)] pub struct LayoutHolds { pub x: AxisHolds, pub y: AxisHolds, } impl LayoutHolds { pub const ANY: Self = Self { x: AxisHolds::ANY, y: AxisHolds::ANY, }; pub fn and(self, other: Self) -> Self { Self { x: self.x.and(other.x), y: self.y.and(other.y), } } pub fn covers(self, other: Self) -> bool { self.x.covers(other.x) && self.y.covers(other.y) } pub fn contains(self, window: PxVec2, rel_base: UiVec2, region: UiRegion) -> bool { Axis::BOTH .into_iter() .all(|axis| self[axis].contains(window[axis], rel_base[axis], region[axis].len())) } } impl_axis_index!(LayoutHolds => AxisHolds);