diff options
| author | Martin <mhaug@live.de> | 2021-06-17 14:18:43 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-06-17 14:18:43 +0200 |
| commit | e14e8047890afad5896c9f38ccdd8551f869be64 (patch) | |
| tree | e65a448e88c0de84ae0790a92a00fd903ba197da /src/layout/incremental.rs | |
| parent | e2cdda67dc0e16b9a482aa3a4bfd5991db06d143 (diff) | |
Constraints (#31)
Diffstat (limited to 'src/layout/incremental.rs')
| -rw-r--r-- | src/layout/incremental.rs | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/layout/incremental.rs b/src/layout/incremental.rs new file mode 100644 index 00000000..427df079 --- /dev/null +++ b/src/layout/incremental.rs @@ -0,0 +1,147 @@ +use std::{collections::HashMap, ops::Deref}; + +use super::*; + +/// Caches layouting artifacts. +#[derive(Default, Debug, Clone)] +pub struct LayoutCache { + /// Maps from node hashes to the resulting frames and regions in which the + /// frames are valid. + pub frames: HashMap<u64, FramesEntry>, +} + +impl LayoutCache { + /// Create a new, empty layout cache. + pub fn new() -> Self { + Self { frames: HashMap::new() } + } + + /// Clear the cache. + pub fn clear(&mut self) { + self.frames.clear(); + } +} + +#[derive(Debug, Clone)] +/// Cached frames from past layouting. +pub struct FramesEntry { + /// The cached frames for a node. + pub frames: Vec<Constrained<Frame>>, +} + +impl FramesEntry { + /// Checks if the cached [`Frame`] is valid for the given regions. + pub fn check(&self, mut regions: Regions) -> Option<Vec<Constrained<Frame>>> { + for (i, frame) in self.frames.iter().enumerate() { + if (i != 0 && !regions.next()) || !frame.constraints.check(®ions) { + return None; + } + } + + Some(self.frames.clone()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Constraints { + /// The minimum available length in the region. + pub min: Spec<Option<Length>>, + /// The maximum available length in the region. + pub max: Spec<Option<Length>>, + /// The available length in the region. + pub exact: Spec<Option<Length>>, + /// The base length of the region used for relative length resolution. + pub base: Spec<Option<Length>>, + /// The expand settings of the region. + pub expand: Spec<bool>, +} + +impl Constraints { + /// Create a new region constraint. + pub fn new(expand: Spec<bool>) -> Self { + Self { + min: Spec::default(), + max: Spec::default(), + exact: Spec::default(), + base: Spec::default(), + expand, + } + } + + /// Set the appropriate base constraints for (relative) width and height + /// metrics, respectively. + pub fn set_base_using_linears( + &mut self, + size: Spec<Option<Linear>>, + regions: &Regions, + ) { + // The full sizes need to be equal if there is a relative component in the sizes. + if size.horizontal.map_or(false, |l| l.is_relative()) { + self.base.horizontal = Some(regions.base.width); + } + if size.vertical.map_or(false, |l| l.is_relative()) { + self.base.vertical = Some(regions.base.height); + } + } + + fn check(&self, regions: &Regions) -> bool { + if self.expand != regions.expand { + return false; + } + + let base = regions.base.to_spec(); + let current = regions.current.to_spec(); + + current.eq_by(&self.min, |x, y| y.map_or(true, |y| x >= &y)) + && current.eq_by(&self.max, |x, y| y.map_or(true, |y| x < &y)) + && current.eq_by(&self.exact, |x, y| y.map_or(true, |y| x == &y)) + && base.eq_by(&self.base, |x, y| y.map_or(true, |y| x == &y)) + } + + /// Changes all constraints by adding the argument to them if they are set. + pub fn mutate(&mut self, size: Size) { + for x in &mut [self.min, self.max, self.exact, self.base] { + if let Some(horizontal) = x.horizontal.as_mut() { + *horizontal += size.width; + } + if let Some(vertical) = x.vertical.as_mut() { + *vertical += size.height; + } + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Constrained<T> { + pub item: T, + pub constraints: Constraints, +} + +impl<T> Deref for Constrained<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.item + } +} + +pub trait OptionExt { + fn set_min(&mut self, other: Length); + fn set_max(&mut self, other: Length); +} + +impl OptionExt for Option<Length> { + fn set_min(&mut self, other: Length) { + match self { + Some(x) => x.set_min(other), + None => *self = Some(other), + } + } + + fn set_max(&mut self, other: Length) { + match self { + Some(x) => x.set_max(other), + None => *self = Some(other), + } + } +} |
