summaryrefslogtreecommitdiff
path: root/src/geom.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/geom.rs')
-rw-r--r--src/geom.rs333
1 files changed, 96 insertions, 237 deletions
diff --git a/src/geom.rs b/src/geom.rs
index f897c08f..6aa875f1 100644
--- a/src/geom.rs
+++ b/src/geom.rs
@@ -1,209 +1,161 @@
//! Geometrical types.
-use std::fmt::{self, Debug, Formatter};
-use std::ops::*;
+#[doc(no_inline)]
+pub use kurbo::*;
-use crate::layout::primitive::*;
+use crate::layout::primitive::{Dir, GenAlign, LayoutAlign, LayoutSystem, SpecAxis};
-/// A value in two dimensions.
-#[derive(Default, Copy, Clone, Eq, PartialEq)]
-pub struct Value2<T> {
- /// The horizontal component.
- pub x: T,
- /// The vertical component.
- pub y: T,
-}
+/// Additional methods for [sizes].
+///
+/// [sizes]: ../../kurbo/struct.Size.html
+pub trait SizeExt {
+ /// Return the primary component of this specialized size.
+ fn primary(self, sys: LayoutSystem) -> f64;
-impl<T: Clone> Value2<T> {
- /// Create a new 2D-value from two values.
- pub fn new(x: T, y: T) -> Self {
- Self { x, y }
- }
+ /// Borrow the primary component of this specialized size mutably.
+ fn primary_mut(&mut self, sys: LayoutSystem) -> &mut f64;
- /// Create a new 2D-value with `x` set to a value and `y` to default.
- pub fn with_x(x: T) -> Self
- where
- T: Default,
- {
- Self { x, y: T::default() }
- }
+ /// Return the secondary component of this specialized size.
+ fn secondary(self, sys: LayoutSystem) -> f64;
- /// Create a new 2D-value with `y` set to a value and `x` to default.
- pub fn with_y(y: T) -> Self
- where
- T: Default,
- {
- Self { x: T::default(), y }
- }
+ /// Borrow the secondary component of this specialized size mutably.
+ fn secondary_mut(&mut self, sys: LayoutSystem) -> &mut f64;
- /// Create a 2D-value with `x` and `y` set to the same value `s`.
- pub fn with_all(s: T) -> Self {
- Self { x: s.clone(), y: s }
- }
+ /// Returns the generalized version of a `Size` based on the layouting
+ /// system, that is:
+ /// - `x` describes the primary axis instead of the horizontal one.
+ /// - `y` describes the secondary axis instead of the vertical one.
+ fn generalized(self, sys: LayoutSystem) -> Self;
- /// Get the specificed component.
- pub fn get(self, axis: SpecAxis) -> T {
- match axis {
- SpecAxis::Horizontal => self.x,
- SpecAxis::Vertical => self.y,
- }
- }
+ /// Returns the specialized version of this generalized Size2D (inverse to
+ /// `generalized`).
+ fn specialized(self, sys: LayoutSystem) -> Self;
- /// Borrow the specificed component mutably.
- pub fn get_mut(&mut self, axis: SpecAxis) -> &mut T {
- match axis {
- SpecAxis::Horizontal => &mut self.x,
- SpecAxis::Vertical => &mut self.y,
- }
- }
+ /// Whether the given size fits into this one, that is, both coordinate
+ /// values are smaller or equal.
+ fn fits(self, other: Self) -> bool;
+
+ /// The anchor position along the given axis for an item with the given
+ /// alignment in a container with this size.
+ ///
+ /// This assumes the size to be generalized such that `x` corresponds to the
+ /// primary axis.
+ fn anchor(self, align: LayoutAlign, sys: LayoutSystem) -> Point;
+}
- /// Return the primary value of this specialized 2D-value.
- pub fn primary(self, sys: LayoutSystem) -> T {
+impl SizeExt for Size {
+ fn primary(self, sys: LayoutSystem) -> f64 {
if sys.primary.axis() == SpecAxis::Horizontal {
- self.x
+ self.width
} else {
- self.y
+ self.height
}
}
- /// Borrow the primary value of this specialized 2D-value mutably.
- pub fn primary_mut(&mut self, sys: LayoutSystem) -> &mut T {
+ fn primary_mut(&mut self, sys: LayoutSystem) -> &mut f64 {
if sys.primary.axis() == SpecAxis::Horizontal {
- &mut self.x
+ &mut self.width
} else {
- &mut self.y
+ &mut self.height
}
}
- /// Return the secondary value of this specialized 2D-value.
- pub fn secondary(self, sys: LayoutSystem) -> T {
+ fn secondary(self, sys: LayoutSystem) -> f64 {
if sys.primary.axis() == SpecAxis::Horizontal {
- self.y
+ self.height
} else {
- self.x
+ self.width
}
}
- /// Borrow the secondary value of this specialized 2D-value mutably.
- pub fn secondary_mut(&mut self, sys: LayoutSystem) -> &mut T {
+ fn secondary_mut(&mut self, sys: LayoutSystem) -> &mut f64 {
if sys.primary.axis() == SpecAxis::Horizontal {
- &mut self.y
+ &mut self.height
} else {
- &mut self.x
+ &mut self.width
}
}
- /// Returns the generalized version of a `Size2D` dependent on the layouting
- /// system, that is:
- /// - `x` describes the primary axis instead of the horizontal one.
- /// - `y` describes the secondary axis instead of the vertical one.
- pub fn generalized(self, sys: LayoutSystem) -> Self {
+ fn generalized(self, sys: LayoutSystem) -> Self {
match sys.primary.axis() {
SpecAxis::Horizontal => self,
- SpecAxis::Vertical => Self { x: self.y, y: self.x },
+ SpecAxis::Vertical => Self::new(self.height, self.width),
}
}
- /// Returns the specialized version of this generalized Size2D (inverse to
- /// `generalized`).
- pub fn specialized(self, sys: LayoutSystem) -> Self {
+ fn specialized(self, sys: LayoutSystem) -> Self {
// In fact, generalized is its own inverse. For reasons of clarity
// at the call site, we still have this second function.
self.generalized(sys)
}
- /// Swap the `x` and `y` values.
- pub fn swap(&mut self) {
- std::mem::swap(&mut self.x, &mut self.y);
+ fn fits(self, other: Self) -> bool {
+ self.width >= other.width && self.height >= other.height
}
-}
-impl<T: Debug> Debug for Value2<T> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.debug_list().entry(&self.x).entry(&self.y).finish()
- }
-}
-
-/// A position or extent in 2-dimensional space.
-pub type Size = Value2<f64>;
-
-impl Size {
- /// The zeroed size.
- pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
-
- /// Whether the given size fits into this one, that is, both coordinate
- /// values are smaller or equal.
- pub fn fits(self, other: Self) -> bool {
- self.x >= other.x && self.y >= other.y
- }
-
- /// Return a size padded by the paddings of the given box.
- pub fn padded(self, padding: Margins) -> Self {
- Size {
- x: self.x + padding.left + padding.right,
- y: self.y + padding.top + padding.bottom,
+ fn anchor(self, align: LayoutAlign, sys: LayoutSystem) -> Point {
+ fn length_anchor(length: f64, align: GenAlign, dir: Dir) -> f64 {
+ match (dir.is_positive(), align) {
+ (true, GenAlign::Start) | (false, GenAlign::End) => 0.0,
+ (_, GenAlign::Center) => length / 2.0,
+ (true, GenAlign::End) | (false, GenAlign::Start) => length,
+ }
}
- }
- /// Return a size reduced by the paddings of the given box.
- pub fn unpadded(self, padding: Margins) -> Self {
- Size {
- x: self.x - padding.left - padding.right,
- y: self.y - padding.top - padding.bottom,
- }
- }
-
- /// The anchor position along the given axis for an item with the given
- /// alignment in a container with this size.
- ///
- /// This assumes the size to be generalized such that `x` corresponds to the
- /// primary axis.
- pub fn anchor(self, align: LayoutAlign, sys: LayoutSystem) -> Self {
- Size {
- x: anchor(self.x, align.primary, sys.primary),
- y: anchor(self.y, align.secondary, sys.secondary),
- }
+ Point::new(
+ length_anchor(self.width, align.primary, sys.primary),
+ length_anchor(self.height, align.secondary, sys.secondary),
+ )
}
}
-fn anchor(length: f64, align: GenAlign, dir: Dir) -> f64 {
- match (dir.is_positive(), align) {
- (true, GenAlign::Start) | (false, GenAlign::End) => 0.0,
- (_, GenAlign::Center) => length / 2.0,
- (true, GenAlign::End) | (false, GenAlign::Start) => length,
- }
+/// Additional methods for [rectangles].
+///
+/// [rectangles]: ../../kurbo/struct.Rect.html
+pub trait RectExt {
+ /// Get a mutable reference to the value for the specified direction at the
+ /// alignment.
+ ///
+ /// Center alignment is treated the same as origin alignment.
+ fn get_mut(&mut self, dir: Dir, align: GenAlign) -> &mut f64;
}
-impl Neg for Size {
- type Output = Size;
-
- fn neg(self) -> Size {
- Size { x: -self.x, y: -self.y }
+impl RectExt for Rect {
+ fn get_mut(&mut self, dir: Dir, align: GenAlign) -> &mut f64 {
+ match if align == GenAlign::End { dir.inv() } else { dir } {
+ Dir::LTR => &mut self.x0,
+ Dir::TTB => &mut self.y0,
+ Dir::RTL => &mut self.x1,
+ Dir::BTT => &mut self.y1,
+ }
}
}
-/// A value in four dimensions.
+/// A generic container for `[left, top, right, bottom]` values.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
-pub struct Value4<T> {
- /// The left extent.
+pub struct Sides<T> {
+ /// The value for the left side.
pub left: T,
- /// The top extent.
+ /// The value for the top side.
pub top: T,
- /// The right extent.
+ /// The value for the right side.
pub right: T,
- /// The bottom extent.
+ /// The value for the bottom side.
pub bottom: T,
}
-impl<T: Clone> Value4<T> {
+impl<T> Sides<T> {
/// Create a new box from four sizes.
pub fn new(left: T, top: T, right: T, bottom: T) -> Self {
- Value4 { left, top, right, bottom }
+ Self { left, top, right, bottom }
}
- /// Create a box with all four fields set to the same value `s`.
- pub fn with_all(value: T) -> Self {
- Value4 {
+ /// Create an instance with all four components set to the same `value`.
+ pub fn uniform(value: T) -> Self
+ where
+ T: Clone,
+ {
+ Self {
left: value.clone(),
top: value.clone(),
right: value.clone(),
@@ -215,105 +167,12 @@ impl<T: Clone> Value4<T> {
/// alignment.
///
/// Center alignment is treated the same as origin alignment.
- pub fn get_mut(&mut self, mut dir: Dir, align: GenAlign) -> &mut T {
- if align == GenAlign::End {
- dir = dir.inv();
- }
-
- match dir {
+ pub fn get_mut(&mut self, dir: Dir, align: GenAlign) -> &mut T {
+ match if align == GenAlign::End { dir.inv() } else { dir } {
Dir::LTR => &mut self.left,
Dir::RTL => &mut self.right,
Dir::TTB => &mut self.top,
Dir::BTT => &mut self.bottom,
}
}
-
- /// Set all values to the given value.
- pub fn set_all(&mut self, value: T) {
- *self = Value4::with_all(value);
- }
-}
-
-/// A length in four dimensions.
-pub type Margins = Value4<f64>;
-
-impl Margins {
- /// The zero margins.
- pub const ZERO: Margins = Margins {
- left: 0.0,
- top: 0.0,
- right: 0.0,
- bottom: 0.0,
- };
}
-
-macro_rules! implement_traits {
- ($ty:ident, $t:ident, $o:ident
- reflexive {$(
- ($tr:ident($tf:ident), $at:ident($af:ident), [$($f:ident),*])
- )*}
- numbers { $(($w:ident: $($rest:tt)*))* }
- ) => {
- $(impl $tr for $ty {
- type Output = $ty;
- fn $tf($t, $o: $ty) -> $ty {
- $ty { $($f: $tr::$tf($t.$f, $o.$f),)* }
- }
- }
-
- impl $at for $ty {
- fn $af(&mut $t, $o: $ty) { $($at::$af(&mut $t.$f, $o.$f);)* }
- })*
-
- $(implement_traits!(@$w f64, $ty $t $o $($rest)*);)*
- };
-
- (@front $num:ty, $ty:ident $t:ident $o:ident
- $tr:ident($tf:ident),
- [$($f:ident),*]
- ) => {
- impl $tr<$ty> for $num {
- type Output = $ty;
- fn $tf($t, $o: $ty) -> $ty {
- $ty { $($f: $tr::$tf($t as f64, $o.$f),)* }
- }
- }
- };
-
- (@back $num:ty, $ty:ident $t:ident $o:ident
- $tr:ident($tf:ident), $at:ident($af:ident),
- [$($f:ident),*]
- ) => {
- impl $tr<$num> for $ty {
- type Output = $ty;
- fn $tf($t, $o: $num) -> $ty {
- $ty { $($f: $tr::$tf($t.$f, $o as f64),)* }
- }
- }
-
- impl $at<$num> for $ty {
- fn $af(&mut $t, $o: $num) { $($at::$af(&mut $t.$f, $o as f64);)* }
- }
- };
-}
-
-macro_rules! implement_size {
- ($ty:ident($t:ident, $o:ident) [$($f:ident),*]) => {
- implement_traits! {
- $ty, $t, $o
-
- reflexive {
- (Add(add), AddAssign(add_assign), [$($f),*])
- (Sub(sub), SubAssign(sub_assign), [$($f),*])
- }
-
- numbers {
- (front: Mul(mul), [$($f),*])
- (back: Mul(mul), MulAssign(mul_assign), [$($f),*])
- (back: Div(div), DivAssign(div_assign), [$($f),*])
- }
- }
- };
-}
-
-implement_size! { Size(self, other) [x, y] }