use crate::{Axis, Holds, Len, PxVec2, UiRegion, UiVec2}; const AXES: [Axis; 2] = [Axis::X, Axis::Y]; /// What one evaluation of a widget depends on: the window lengths its reads /// hold for, the pixel lengths of its own box, and the symbolic lengths of /// that box and of its frame 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 frame 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 frame pin says the answer or the drawing is a fraction of the frame, /// which is a different length wherever the frame is a different one -- at /// the same window size, so no range of window pixels can say it. A length /// of the frame that is only pixels is not one: it is that many pixels /// whatever the frame turns out to be. #[derive(Clone, Copy, Debug, PartialEq)] pub struct LayoutHolds { pub window: [Holds; 2], pub frame_len: [Option; 2], pub region: [Holds; 2], pub region_len: [Option; 2], } impl LayoutHolds { pub const ANY: Self = Self { window: [Holds::ANY; 2], frame_len: [None; 2], region: [Holds::ANY; 2], region_len: [None; 2], }; pub fn and(self, other: Self) -> Self { let mut result = Self::ANY; for n in 0..2 { result.window[n] = self.window[n].and(other.window[n]); result.region[n] = self.region[n].and(other.region[n]); debug_assert!( self.region_len[n].is_none() || other.region_len[n].is_none() || self.region_len[n] == other.region_len[n] ); debug_assert!( self.frame_len[n].is_none() || other.frame_len[n].is_none() || self.frame_len[n] == other.frame_len[n] ); result.region_len[n] = self.region_len[n].or(other.region_len[n]); result.frame_len[n] = self.frame_len[n].or(other.frame_len[n]); } result } pub fn covers(self, other: Self) -> bool { (0..2).all(|n| { self.window[n].lo <= other.window[n].lo && self.window[n].hi >= other.window[n].hi && self.region[n].lo <= other.region[n].lo && self.region[n].hi >= other.region[n].hi && self.region_len[n].is_none_or(|len| other.region_len[n] == Some(len)) && self.frame_len[n].is_none_or(|len| other.frame_len[n] == Some(len)) }) } pub fn contains(self, window: PxVec2, frame: UiVec2, region: UiRegion) -> bool { AXES.into_iter().all(|axis| { let n = axis as usize; let len = region.axis(axis).len(); self.window[n].contains(window.axis(axis)) && self.frame_len[n].is_none_or(|pinned| pinned == frame.axis(axis)) && self.region[n].contains(len.to_px(window.axis(axis))) && self.region_len[n].is_none_or(|pinned| pinned == len) }) } }