summaryrefslogtreecommitdiff
path: root/src/layout/constraints.rs
diff options
context:
space:
mode:
authorMartin <mhaug@live.de>2021-08-19 15:07:11 +0200
committerGitHub <noreply@github.com>2021-08-19 15:07:11 +0200
commitfdab7158c91c52a4ace211c804fdd8e9110f56de (patch)
tree7ec34f942bc89b2ade554618648825654a587ace /src/layout/constraints.rs
parentc44ecbfbd2706bf8e09728f2c85135aa2299d542 (diff)
Pattern properties (#42)
Included in this package are: * Code review I: The unnamed review. * Code Review II: How I met your review. * Code Review III: Code, the final frontier. These are the voyages of the USS Review ...
Diffstat (limited to 'src/layout/constraints.rs')
-rw-r--r--src/layout/constraints.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/layout/constraints.rs b/src/layout/constraints.rs
new file mode 100644
index 00000000..d13433ec
--- /dev/null
+++ b/src/layout/constraints.rs
@@ -0,0 +1,96 @@
+use std::ops::Deref;
+
+use crate::util::OptionExt;
+
+use super::*;
+
+/// Carries an item that is only valid in certain regions and the constraints
+/// that describe these regions.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct Constrained<T> {
+ /// The item that is only valid if the constraints are fullfilled.
+ pub item: T,
+ /// Constraints on regions in which the item is valid.
+ pub constraints: Constraints,
+}
+
+impl<T> Deref for Constrained<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.item
+ }
+}
+
+/// Describe regions that match them.
+#[derive(Debug, Copy, Clone, Eq, 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,
+ }
+ }
+
+ /// Check whether the constraints are fullfilled in a region with the given
+ /// properties.
+ pub fn check(&self, current: Size, base: Size, expand: Spec<bool>) -> bool {
+ let current = current.to_spec();
+ let base = base.to_spec();
+ self.expand == expand
+ && current.eq_by(&self.min, |x, y| y.map_or(true, |y| x.fits(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.approx_eq(y)))
+ && base.eq_by(&self.base, |x, y| y.map_or(true, |y| x.approx_eq(y)))
+ }
+
+ /// 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);
+ }
+ }
+
+ /// Changes all constraints by adding the `size` to them if they are `Some`.
+ pub fn inflate(&mut self, size: Size, regions: &Regions) {
+ for spec in [&mut self.min, &mut self.max] {
+ if let Some(horizontal) = spec.horizontal.as_mut() {
+ *horizontal += size.width;
+ }
+ if let Some(vertical) = spec.vertical.as_mut() {
+ *vertical += size.height;
+ }
+ }
+
+ self.exact.horizontal.and_set(Some(regions.current.width));
+ self.exact.vertical.and_set(Some(regions.current.height));
+ self.base.horizontal.and_set(Some(regions.base.width));
+ self.base.vertical.and_set(Some(regions.base.height));
+ }
+}