From 3c0496bb6104f0e2a60520e42137ecc29f26e9fa Mon Sep 17 00:00:00 2001 From: Laurenz Date: Thu, 12 Dec 2019 20:17:35 +0100 Subject: [PATCH] =?UTF-8?q?Refactor=20size=20module=20=E2=99=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/stack.rs | 15 +- src/size.rs | 708 ++++++++++++++++++-------------------------- 2 files changed, 302 insertions(+), 421 deletions(-) diff --git a/src/layout/stack.rs b/src/layout/stack.rs index 27ca433bd..cb1d867ee 100644 --- a/src/layout/stack.rs +++ b/src/layout/stack.rs @@ -1,5 +1,4 @@ use smallvec::smallvec; -use crate::size::max; use super::*; /// The stack layouter stack boxes onto each other along the secondary layouting @@ -183,10 +182,11 @@ impl StackLayouter { let mut size = self.space.size.generalized(axes); let mut extra = self.space.extra.generalized(axes); - size.x += max(dimensions.x - extra.x, Size::ZERO); - size.y += max(dimensions.y - extra.y, Size::ZERO); - extra.x = max(extra.x, dimensions.x); - extra.y = max(extra.y - dimensions.y, Size::ZERO); + size.x += (dimensions.x - extra.x).max(Size::ZERO); + size.y += (dimensions.y - extra.y).max(Size::ZERO); + + extra.x.max_eq(dimensions.x); + extra.y = (extra.y - dimensions.y).max(Size::ZERO); self.space.size = size.specialized(axes); self.space.extra = extra.specialized(axes); @@ -304,7 +304,7 @@ impl StackLayouter { // layout uses up space from the origin to the end. Thus, it reduces // the usable space for following layouts at it's origin by its // extent along the secondary axis. - *bound.secondary_origin_mut(*axes) + *bound.get_mut(*axes, GenericAxisKind::Secondary, Alignment::Origin) += axes.secondary.factor() * layout.dimensions.secondary(*axes); } @@ -334,7 +334,8 @@ impl StackLayouter { // We reduce the bounding box of this layout at it's end by the // accumulated secondary extent of all layouts we have seen so far, // which are the layouts after this one since we iterate reversed. - *bound.secondary_end_mut(*axes) -= axes.secondary.factor() * extent.y; + *bound.get_mut(*axes, GenericAxisKind::Secondary, Alignment::End) + -= axes.secondary.factor() * extent.y; // Then, we add this layout's secondary extent to the accumulator. let size = layout.dimensions.generalized(*axes); diff --git a/src/size.rs b/src/size.rs index b22f14bbf..7b0b76aec 100644 --- a/src/size.rs +++ b/src/size.rs @@ -6,15 +6,95 @@ use std::iter::Sum; use std::ops::*; use std::str::FromStr; -use crate::layout::{LayoutAxes, LayoutAlignment, Axis, Alignment}; +use crate::layout::{LayoutAxes, LayoutAlignment, Axis, GenericAxisKind, Alignment}; -/// A general space type. -#[derive(Copy, Clone, PartialEq)] + +/// A general spacing type. +#[derive(Copy, Clone, PartialEq, PartialOrd)] pub struct Size { /// The size in typographic points (1/72 inches). points: f32, } +impl Size { + /// The zeroed size. + pub const ZERO: Size = Size { points: 0.0 }; + + /// Create a size from an amount of points. + pub fn pt(points: f32) -> Size { Size { points } } + + /// Create a size from an amount of millimeters. + pub fn mm(mm: f32) -> Size { Size { points: 2.83465 * mm } } + + /// Create a size from an amount of centimeters. + pub fn cm(cm: f32) -> Size { Size { points: 28.3465 * cm } } + + /// Create a size from an amount of inches. + pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } } + + /// Convert this size into points. + pub fn to_pt(self) -> f32 { self.points } + + /// Convert this size into millimeters. + pub fn to_mm(self) -> f32 { self.points * 0.352778 } + + /// Convert this size into centimeters. + pub fn to_cm(self) -> f32 { self.points * 0.0352778 } + + /// Convert this size into inches. + pub fn to_inches(self) -> f32 { self.points * 0.0138889 } + + /// The maximum of this and the other size. + pub fn max(self, other: Size) -> Size { + if self > other { self } else { other } + } + + /// The minimum of this and the other size. + pub fn min(self, other: Size) -> Size { + if self <= other { self } else { other } + } + + /// Set this size to the maximum of itself and the other size. + pub fn max_eq(&mut self, other: Size) { *self = self.max(other); } + + /// Set this size to the minimum of itself and the other size. + pub fn min_eq(&mut self, other: Size) { *self = self.min(other); } + + /// The anchor position along the given axis for an item with the given + /// alignment in a container with this size. + pub fn anchor(self, alignment: Alignment, axis: Axis) -> Size { + use Alignment::*; + match (axis.is_positive(), alignment) { + (true, Origin) | (false, End) => Size::ZERO, + (_, Center) => self / 2, + (true, End) | (false, Origin) => self, + } + } +} + +impl Display for Size { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}cm", self.to_cm()) + } +} + +debug_display!(Size); + +impl Neg for Size { + type Output = Size; + + fn neg(self) -> Size { + Size { points: -self.points } + } +} + +impl Sum for Size { + fn sum(iter: I) -> Size + where I: Iterator { + iter.fold(Size::ZERO, Add::add) + } +} + /// A position or extent in 2-dimensional space. #[derive(Copy, Clone, PartialEq)] pub struct Size2D { @@ -24,6 +104,115 @@ pub struct Size2D { pub y: Size, } +impl Size2D { + /// The zeroed 2D-size. + pub const ZERO: Size2D = Size2D { x: Size::ZERO, y: Size::ZERO }; + + /// Create a new 2D-size from two sizes. + pub fn new(x: Size, y: Size) -> Size2D { Size2D { x, y } } + + /// Create a new 2D-size with `x` set to a value and `y` zero. + pub fn with_x(x: Size) -> Size2D { Size2D { x, y: Size::ZERO } } + + /// Create a new 2D-size with `y` set to a value and `x` zero. + pub fn with_y(y: Size) -> Size2D { Size2D { x: Size::ZERO, y } } + + /// Create a 2D-size with `x` and `y` set to the same value `s`. + pub fn with_all(s: Size) -> Size2D { Size2D { x: s, y: s } } + + /// Access the primary size of this specialized 2D-size. + pub fn primary(self, axes: LayoutAxes) -> Size { + if axes.primary.is_horizontal() { self.x } else { self.y } + } + + /// Access the primary size of this specialized 2D-size mutably. + pub fn primary_mut(&mut self, axes: LayoutAxes) -> &mut Size { + if axes.primary.is_horizontal() { &mut self.x } else { &mut self.y } + } + + /// Access the secondary size of this specialized 2D-size. + pub fn secondary(self, axes: LayoutAxes) -> Size { + if axes.primary.is_horizontal() { self.y } else { self.x } + } + + /// Access the secondary size of this specialized 2D-size mutably. + pub fn secondary_mut(&mut self, axes: LayoutAxes) -> &mut Size { + if axes.primary.is_horizontal() { &mut self.y } else { &mut self.x } + } + + /// Returns the generalized version of a `Size2D` dependent on the layouting + /// axes, 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, axes: LayoutAxes) -> Size2D { + match axes.primary.is_horizontal() { + true => self, + false => Size2D { x: self.y, y: self.x }, + } + } + + /// Returns the specialized version of this generalized Size2D (inverse to + /// `generalized`). + pub fn specialized(self, axes: LayoutAxes) -> Size2D { + // In fact, generalized is its own inverse. For reasons of clarity + // at the call site, we still have this second function. + self.generalized(axes) + } + + /// Whether the given 2D-size fits into this one, that is, both coordinate + /// values are smaller or equal. + pub fn fits(self, other: Size2D) -> bool { + self.x >= other.x && self.y >= other.y + } + + /// Return a 2D-size padded by the paddings of the given box. + pub fn padded(self, padding: SizeBox) -> Size2D { + Size2D { + x: self.x + padding.left + padding.right, + y: self.y + padding.top + padding.bottom, + } + } + + /// Return a 2D-size reduced by the paddings of the given box. + pub fn unpadded(self, padding: SizeBox) -> Size2D { + Size2D { + 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, alignment: LayoutAlignment, axes: LayoutAxes) -> Size2D { + Size2D { + x: self.x.anchor(alignment.primary, axes.primary), + y: self.y.anchor(alignment.secondary, axes.secondary), + } + } +} + +impl Display for Size2D { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "[{}, {}]", self.x, self.y) + } +} + +debug_display!(Size2D); + +impl Neg for Size2D { + type Output = Size2D; + + fn neg(self) -> Size2D { + Size2D { + x: -self.x, + y: -self.y, + } + } +} + /// A size in four directions. #[derive(Copy, Clone, PartialEq)] pub struct SizeBox { @@ -37,201 +226,6 @@ pub struct SizeBox { pub bottom: Size, } -/// Either an absolute size or a factor of some metric. -#[derive(Copy, Clone, PartialEq)] -pub enum ScaleSize { - Absolute(Size), - Scaled(f32), -} - -/// A scale size that is scaled by the font size. -pub type FSize = ScaleSize; - -/// A scale size that is scaled by the size of the padded parent container. -pub type PSize = ScaleSize; - -impl Size { - /// The zeroed size. - pub const ZERO: Size = Size { points: 0.0 }; - - /// Create a zeroed size. - pub fn zero() -> Size { Size::ZERO } - - /// Create a size from an amount of points. - pub fn pt(points: f32) -> Size { Size { points } } - - /// Create a size from an amount of millimeters. - pub fn mm(mm: f32) -> Size { Size { points: 2.83465 * mm } } - - /// Create a size from an amount of centimeters. - pub fn cm(cm: f32) -> Size { Size { points: 28.3465 * cm } } - - /// Create a size from an amount of inches. - pub fn inches(inches: f32) -> Size { Size { points: 72.0 * inches } } - - /// Convert this size into points. - pub fn to_pt(&self) -> f32 { self.points } - - /// Convert this size into millimeters. - pub fn to_mm(&self) -> f32 { self.points * 0.352778 } - - /// Convert this size into centimeters. - pub fn to_cm(&self) -> f32 { self.points * 0.0352778 } - - /// Convert this size into inches. - pub fn to_inches(&self) -> f32 { self.points * 0.0138889 } - - /// Set this size to the maximum of itself and the other size. - pub fn max_eq(&mut self, other: Size) { - *self = max(*self, other); - } - - /// Set this size to the minimum of itself and the other size. - pub fn min_eq(&mut self, other: Size) { - *self = min(*self, other); - } - - /// The anchor position along the given axis for an item with the given - /// alignment in a container with this size. - pub fn anchor(&self, alignment: Alignment, axis: Axis) -> Size { - use Alignment::*; - match (axis.is_positive(), alignment) { - (true, Origin) | (false, End) => Size::ZERO, - (_, Center) => *self / 2, - (true, End) | (false, Origin) => *self, - } - } -} - -impl Size2D { - /// The zeroed 2D-size. - pub const ZERO: Size2D = Size2D { x: Size::ZERO, y: Size::ZERO }; - - /// Create a new 2D-size from two sizes. - pub fn new(x: Size, y: Size) -> Size2D { - Size2D { x, y } - } - - /// Create a 2D-size with both sizes set to zero. - pub fn zero() -> Size2D { - Size2D::ZERO - } - - /// Create a 2D-size with `x` and `y` set to the same value `s`. - pub fn with_all(s: Size) -> Size2D { - Size2D { x: s, y: s } - } - - /// Create a new 2D-size with `x` set to a value and `y` zero. - pub fn with_x(x: Size) -> Size2D { - Size2D { x, y: Size::ZERO } - } - - /// Create a new 2D-size with `y` set to a value and `x` zero. - pub fn with_y(y: Size) -> Size2D { - Size2D { x: Size::ZERO, y } - } - - /// Access the primary size of this 2D-size. - pub fn primary(&self, axes: LayoutAxes) -> Size { - match axes.primary.is_horizontal() { - true => self.x, - false => self.y, - } - } - - /// Access the secondary size of this 2D-size. - pub fn secondary(&self, axes: LayoutAxes) -> Size { - match axes.primary.is_horizontal() { - true => self.y, - false => self.x, - } - } - - /// Access the primary size of this 2D-size. - pub fn primary_mut(&mut self, axes: LayoutAxes) -> &mut Size { - match axes.primary.is_horizontal() { - true => &mut self.x, - false => &mut self.y, - } - } - - /// Access the secondary size of this 2D-size. - pub fn secondary_mut(&mut self, axes: LayoutAxes) -> &mut Size { - match axes.primary.is_horizontal() { - true => &mut self.y, - false => &mut self.x, - } - } - - /// Returns the generalized version of a `Size2D` dependent on - /// the layouting axes, that is: - /// - The x coordinate describes the primary axis instead of the horizontal one. - /// - The y coordinate describes the secondary axis instead of the vertical one. - pub fn generalized(&self, axes: LayoutAxes) -> Size2D { - match axes.primary.is_horizontal() { - true => *self, - false => Size2D { x: self.y, y: self.x }, - } - } - - /// Returns the specialized version of this generalized Size2D. - /// (Inverse to `generalized`). - pub fn specialized(&self, axes: LayoutAxes) -> Size2D { - // In fact, generalized is its own inverse. For reasons of clarity - // at the call site, we still have this second function. - self.generalized(axes) - } - - /// Return a 2D-size padded by the paddings of the given box. - pub fn padded(&self, padding: SizeBox) -> Size2D { - Size2D { - x: self.x + padding.left + padding.right, - y: self.y + padding.top + padding.bottom, - } - } - - /// Return a 2D-size reduced by the paddings of the given box. - pub fn unpadded(&self, padding: SizeBox) -> Size2D { - Size2D { - x: self.x - padding.left - padding.right, - y: self.y - padding.top - padding.bottom, - } - } - - /// Whether the given 2D-size fits into this one, that is, - /// both coordinate values are smaller or equal. - pub fn fits(&self, other: Size2D) -> bool { - self.x >= other.x && self.y >= other.y - } - - /// Set this size to the maximum of itself and the other size - /// (for both dimensions). - pub fn max_eq(&mut self, other: Size2D) { - self.x.max_eq(other.x); - self.y.max_eq(other.y); - } - - /// Set this size to the minimum of itself and the other size - /// (for both dimensions). - pub fn min_eq(&mut self, other: Size2D) { - self.x.min_eq(other.x); - self.y.min_eq(other.y); - } - - /// 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, alignment: LayoutAlignment, axes: LayoutAxes) -> Size2D { - Size2D { - x: self.x.anchor(alignment.primary, axes.primary), - y: self.y.anchor(alignment.secondary, axes.secondary), - } - } -} - impl SizeBox { /// The zeroed size box. pub const ZERO: SizeBox = SizeBox { @@ -243,17 +237,7 @@ impl SizeBox { /// Create a new box from four sizes. pub fn new(left: Size, top: Size, right: Size, bottom: Size) -> SizeBox { - SizeBox { - left, - top, - right, - bottom, - } - } - - /// Create a box with all values set to zero. - pub fn zero() -> SizeBox { - SizeBox::ZERO + SizeBox { left, top, right, bottom } } /// Create a box with all four fields set to the same value `s`. @@ -261,9 +245,20 @@ impl SizeBox { SizeBox { left: value, top: value, right: value, bottom: value } } - /// Access the origin direction on the secondary axis of this box. - pub fn secondary_origin_mut(&mut self, axes: LayoutAxes) -> &mut Size { - match axes.secondary { + /// Get a mutable reference to the value for the specified axis and + /// alignment. Center alignment will be treated the same as origin + /// alignment. + pub fn get_mut(&mut self, + axes: LayoutAxes, + axis: GenericAxisKind, + alignment: Alignment, + ) -> &mut Size { + let mut normalized = axes.generic(axis); + if alignment == Alignment::End { + normalized = normalized.inv(); + } + + match normalized { Axis::LeftToRight => &mut self.left, Axis::RightToLeft => &mut self.right, Axis::TopToBottom => &mut self.top, @@ -271,16 +266,6 @@ impl SizeBox { } } - /// Access the end direction on the secondary axis of this box. - pub fn secondary_end_mut(&mut self, axes: LayoutAxes) -> &mut Size { - match axes.secondary { - Axis::LeftToRight => &mut self.right, - Axis::RightToLeft => &mut self.left, - Axis::TopToBottom => &mut self.bottom, - Axis::BottomToTop => &mut self.top, - } - } - /// Set the `left` and `right` values. pub fn set_all(&mut self, value: Size) { *self = SizeBox::with_all(value); @@ -299,6 +284,28 @@ impl SizeBox { } } +impl Display for SizeBox { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "[left: {}, top: {}, right: {}, bottom: {}]", + self.left, self.top, self.right, self.bottom) + } +} + +debug_display!(SizeBox); + +/// Either an absolute size or a factor of some metric. +#[derive(Copy, Clone, PartialEq)] +pub enum ScaleSize { + Absolute(Size), + Scaled(f32), +} + +/// A scale size that is scaled by the font size. +pub type FSize = ScaleSize; + +/// A scale size that is scaled by the size of the padded parent container. +pub type PSize = ScaleSize; + impl ScaleSize { /// Use the absolute value or scale the entity. pub fn concretize(&self, entity: Size) -> Size { @@ -309,25 +316,16 @@ impl ScaleSize { } } -/// The maximum of two sizes. -pub fn max(a: Size, b: Size) -> Size { - if a >= b { a } else { b } -} - -/// The minimum of two sizes. -pub fn min(a: Size, b: Size) -> Size { - if a <= b { a } else { b } -} - -//------------------------------------------------------------------------------------------------// - -impl Display for Size { +impl Display for ScaleSize { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}cm", self.to_cm()) + match self { + ScaleSize::Absolute(size) => write!(f, "{}", size), + ScaleSize::Scaled(scale) => write!(f, "x{}", scale), + } } } -debug_display!(Size); +debug_display!(ScaleSize); /// An error which can be returned when parsing a size. pub struct ParseSizeError; @@ -359,193 +357,75 @@ impl FromStr for Size { } } -impl PartialOrd for Size { - fn partial_cmp(&self, other: &Size) -> Option { - self.points.partial_cmp(&other.points) - } -} - -impl Neg for Size { - type Output = Size; - - fn neg(self) -> Size { - Size { points: -self.points } - } -} - -impl Sum for Size { - fn sum(iter: I) -> Size - where I: Iterator { - iter.fold(Size::ZERO, Add::add) - } -} - -macro_rules! impl_reflexive { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident) => ( - impl $trait for Size { - type Output = Size; - - fn $func(self, other: Size) -> Size { - Size { points: $trait::$func(self.points, other.points) } +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 $assign_trait for Size { - fn $assign_func(&mut self, other: Size) { - $assign_trait::$assign_func(&mut self.points, other.points); + impl $at for $ty { + fn $af(&mut $t, $o: $ty) { $($at::$af(&mut $t.$f, $o.$f);)* } + })* + + $(implement_traits!(@$w i32, $ty $t $o $($rest)*);)* + $(implement_traits!(@$w f32, $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 f32, $o.$f),)* } } } - ); -} + }; -macro_rules! impl_num_back { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => ( - impl $trait<$ty> for Size { - type Output = Size; - - fn $func(self, other: $ty) -> Size { - Size { points: $trait::$func(self.points, other as f32) } + (@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 f32),)* } } } - impl $assign_trait<$ty> for Size { - fn $assign_func(&mut self, other: $ty) { - $assign_trait::$assign_func(&mut self.points, other as f32); + impl $at<$num> for $ty { + fn $af(&mut $t, $o: $num) { $($at::$af(&mut $t.$f, $o as f32);)* } + } + }; +} + +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),*]) } } - ); + }; } -macro_rules! impl_num_both { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => ( - impl_num_back!($trait, $func, $assign_trait, $assign_func, $ty); - - impl $trait for $ty { - type Output = Size; - - fn $func(self, other: Size) -> Size { - Size { points: $trait::$func(self as f32, other.points) } - } - } - ); -} - -impl_reflexive!(Add, add, AddAssign, add_assign); -impl_reflexive!(Sub, sub, SubAssign, sub_assign); -impl_num_both!(Mul, mul, MulAssign, mul_assign, f32); -impl_num_both!(Mul, mul, MulAssign, mul_assign, i32); -impl_num_back!(Div, div, DivAssign, div_assign, f32); -impl_num_back!(Div, div, DivAssign, div_assign, i32); - -//------------------------------------------------------------------------------------------------// - -impl Display for Size2D { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "[{}, {}]", self.x, self.y) - } -} - -debug_display!(Size2D); - -impl Neg for Size2D { - type Output = Size2D; - - fn neg(self) -> Size2D { - Size2D { - x: -self.x, - y: -self.y, - } - } -} - -macro_rules! impl_reflexive2d { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident) => ( - impl $trait for Size2D { - type Output = Size2D; - - fn $func(self, other: Size2D) -> Size2D { - Size2D { - x: $trait::$func(self.x, other.x), - y: $trait::$func(self.y, other.y), - } - } - } - - impl $assign_trait for Size2D { - fn $assign_func(&mut self, other: Size2D) { - $assign_trait::$assign_func(&mut self.x, other.x); - $assign_trait::$assign_func(&mut self.y, other.y); - } - } - ); -} - -macro_rules! impl_num_back2d { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => ( - impl $trait<$ty> for Size2D { - type Output = Size2D; - - fn $func(self, other: $ty) -> Size2D { - Size2D { - x: $trait::$func(self.x, other as f32), - y: $trait::$func(self.y, other as f32), - } - } - } - - impl $assign_trait<$ty> for Size2D { - fn $assign_func(&mut self, other: $ty) { - $assign_trait::$assign_func(&mut self.x, other as f32); - $assign_trait::$assign_func(&mut self.y, other as f32); - } - } - ); -} - -macro_rules! impl_num_both2d { - ($trait:ident, $func:ident, $assign_trait:ident, $assign_func:ident, $ty:ty) => ( - impl_num_back2d!($trait, $func, $assign_trait, $assign_func, $ty); - - impl $trait for $ty { - type Output = Size2D; - - fn $func(self, other: Size2D) -> Size2D { - Size2D { - x: $trait::$func(self as f32, other.x), - y: $trait::$func(self as f32, other.y), - } - } - } - ); -} - -impl_reflexive2d!(Add, add, AddAssign, add_assign); -impl_reflexive2d!(Sub, sub, SubAssign, sub_assign); -impl_num_both2d!(Mul, mul, MulAssign, mul_assign, f32); -impl_num_both2d!(Mul, mul, MulAssign, mul_assign, i32); -impl_num_back2d!(Div, div, DivAssign, div_assign, f32); -impl_num_back2d!(Div, div, DivAssign, div_assign, i32); - -//------------------------------------------------------------------------------------------------// - -impl Display for SizeBox { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "[left: {}, top: {}, right: {}, bottom: {}]", - self.left, self.top, self.right, self.bottom) - } -} - -debug_display!(SizeBox); - -//------------------------------------------------------------------------------------------------// - -impl Display for ScaleSize { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - ScaleSize::Absolute(size) => write!(f, "{}", size), - ScaleSize::Scaled(scale) => write!(f, "x{}", scale), - } - } -} - -debug_display!(ScaleSize); +implement_size! { Size(self, other) [points] } +implement_size! { Size2D(self, other) [x, y] }