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 extent: [Holds; 2], pub extent_len: [Option; 2], } impl LayoutHolds { pub const ANY: Self = Self { window: [Holds::ANY; 2], frame_len: [None; 2], extent: [Holds::ANY; 2], extent_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.extent[n] = self.extent[n].and(other.extent[n]); debug_assert!( self.extent_len[n].is_none() || other.extent_len[n].is_none() || self.extent_len[n] == other.extent_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.extent_len[n] = self.extent_len[n].or(other.extent_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.extent[n].lo <= other.extent[n].lo && self.extent[n].hi >= other.extent[n].hi && self.extent_len[n].is_none_or(|len| other.extent_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, extent: UiRegion) -> bool { AXES.into_iter().all(|axis| { let n = axis as usize; let len = extent.axis(axis).len(); self.window[n].contains(window.axis(axis)) && self.frame_len[n].is_none_or(|pinned| pinned == frame.axis(axis)) && self.extent[n].contains(len.to_px(window.axis(axis))) && self.extent_len[n].is_none_or(|pinned| pinned == len) }) } }