diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/src/angle.rs | 75 | ||||
-rw-r--r-- | core/src/content_fit.rs | 17 | ||||
-rw-r--r-- | core/src/image.rs | 3 | ||||
-rw-r--r-- | core/src/lib.rs | 2 | ||||
-rw-r--r-- | core/src/rectangle.rs | 32 | ||||
-rw-r--r-- | core/src/renderer/null.rs | 5 | ||||
-rw-r--r-- | core/src/rotation.rs | 72 | ||||
-rw-r--r-- | core/src/size.rs | 29 | ||||
-rw-r--r-- | core/src/svg.rs | 3 | ||||
-rw-r--r-- | core/src/vector.rs | 3 |
10 files changed, 233 insertions, 8 deletions
diff --git a/core/src/angle.rs b/core/src/angle.rs index dc3c0e93..9c8a9b24 100644 --- a/core/src/angle.rs +++ b/core/src/angle.rs @@ -1,12 +1,17 @@ use crate::{Point, Rectangle, Vector}; use std::f32::consts::{FRAC_PI_2, PI}; -use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign}; /// Degrees #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub struct Degrees(pub f32); +impl Degrees { + /// The range of degrees of a circle. + pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(360.0); +} + impl PartialEq<f32> for Degrees { fn eq(&self, other: &f32) -> bool { self.0.eq(other) @@ -19,6 +24,52 @@ impl PartialOrd<f32> for Degrees { } } +impl From<f32> for Degrees { + fn from(degrees: f32) -> Self { + Self(degrees) + } +} + +impl From<u8> for Degrees { + fn from(degrees: u8) -> Self { + Self(f32::from(degrees)) + } +} + +impl From<Degrees> for f32 { + fn from(degrees: Degrees) -> Self { + degrees.0 + } +} + +impl From<Degrees> for f64 { + fn from(degrees: Degrees) -> Self { + Self::from(degrees.0) + } +} + +impl Mul<f32> for Degrees { + type Output = Degrees; + + fn mul(self, rhs: f32) -> Self::Output { + Self(self.0 * rhs) + } +} + +impl num_traits::FromPrimitive for Degrees { + fn from_i64(n: i64) -> Option<Self> { + Some(Self(n as f32)) + } + + fn from_u64(n: u64) -> Option<Self> { + Some(Self(n as f32)) + } + + fn from_f64(n: f64) -> Option<Self> { + Some(Self(n as f32)) + } +} + /// Radians #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub struct Radians(pub f32); @@ -65,6 +116,12 @@ impl From<u8> for Radians { } } +impl From<Radians> for f32 { + fn from(radians: Radians) -> Self { + radians.0 + } +} + impl From<Radians> for f64 { fn from(radians: Radians) -> Self { Self::from(radians.0) @@ -107,6 +164,14 @@ impl Add for Radians { } } +impl Add<Degrees> for Radians { + type Output = Self; + + fn add(self, rhs: Degrees) -> Self::Output { + Self(self.0 + rhs.0.to_radians()) + } +} + impl AddAssign for Radians { fn add_assign(&mut self, rhs: Radians) { self.0 = self.0 + rhs.0; @@ -153,6 +218,14 @@ impl Div for Radians { } } +impl Rem for Radians { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Self(self.0 % rhs.0) + } +} + impl PartialEq<f32> for Radians { fn eq(&self, other: &f32) -> bool { self.0.eq(other) diff --git a/core/src/content_fit.rs b/core/src/content_fit.rs index 6bbedc7a..19642716 100644 --- a/core/src/content_fit.rs +++ b/core/src/content_fit.rs @@ -1,6 +1,8 @@ //! Control the fit of some content (like an image) within a space. use crate::Size; +use std::fmt; + /// The strategy used to fit the contents of a widget to its bounding box. /// /// Each variant of this enum is a strategy that can be applied for resolving @@ -11,7 +13,7 @@ use crate::Size; /// in CSS, see [Mozilla's docs][1], or run the `tour` example /// /// [1]: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit -#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, Default)] pub enum ContentFit { /// Scale as big as it can be without needing to crop or hide parts. /// @@ -23,6 +25,7 @@ pub enum ContentFit { /// This is a great fit for when you need to display an image without losing /// any part of it, particularly when the image itself is the focus of the /// screen. + #[default] Contain, /// Scale the image to cover all of the bounding box, cropping if needed. @@ -117,3 +120,15 @@ impl ContentFit { } } } + +impl fmt::Display for ContentFit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + ContentFit::Contain => "Contain", + ContentFit::Cover => "Cover", + ContentFit::Fill => "Fill", + ContentFit::None => "None", + ContentFit::ScaleDown => "Scale Down", + }) + } +} diff --git a/core/src/image.rs b/core/src/image.rs index c38239bc..91a7fd36 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -1,7 +1,7 @@ //! Load and draw raster graphics. pub use bytes::Bytes; -use crate::{Rectangle, Size}; +use crate::{Radians, Rectangle, Size}; use rustc_hash::FxHasher; use std::hash::{Hash, Hasher}; @@ -173,5 +173,6 @@ pub trait Renderer: crate::Renderer { handle: Self::Handle, filter_method: FilterMethod, bounds: Rectangle, + rotation: Radians, ); } diff --git a/core/src/lib.rs b/core/src/lib.rs index feda4fb4..32156441 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -39,6 +39,7 @@ mod padding; mod pixels; mod point; mod rectangle; +mod rotation; mod shadow; mod shell; mod size; @@ -64,6 +65,7 @@ pub use pixels::Pixels; pub use point::Point; pub use rectangle::Rectangle; pub use renderer::Renderer; +pub use rotation::Rotation; pub use shadow::Shadow; pub use shell::Shell; pub use size::Size; diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index 2ab50137..1556e072 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -1,6 +1,6 @@ -use crate::{Point, Size, Vector}; +use crate::{Point, Radians, Size, Vector}; -/// A rectangle. +/// An axis-aligned rectangle. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Rectangle<T = f32> { /// X coordinate of the top-left corner. @@ -172,6 +172,18 @@ impl Rectangle<f32> { height: self.height + amount * 2.0, } } + + /// Rotates the [`Rectangle`] and returns the smallest [`Rectangle`] + /// containing it. + pub fn rotate(self, rotation: Radians) -> Self { + let size = self.size().rotate(rotation); + let position = Point::new( + self.center_x() - size.width / 2.0, + self.center_y() - size.height / 2.0, + ); + + Self::new(position, size) + } } impl std::ops::Mul<f32> for Rectangle<f32> { @@ -227,3 +239,19 @@ where } } } + +impl<T> std::ops::Mul<Vector<T>> for Rectangle<T> +where + T: std::ops::Mul<Output = T> + Copy, +{ + type Output = Rectangle<T>; + + fn mul(self, scale: Vector<T>) -> Self { + Rectangle { + x: self.x * scale.x, + y: self.y * scale.y, + width: self.width * scale.x, + height: self.height * scale.y, + } + } +} diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index fe38ec87..91519b40 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -4,7 +4,8 @@ use crate::renderer::{self, Renderer}; use crate::svg; use crate::text::{self, Text}; use crate::{ - Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation, + Background, Color, Font, Pixels, Point, Radians, Rectangle, Size, + Transformation, }; impl Renderer for () { @@ -171,6 +172,7 @@ impl image::Renderer for () { _handle: Self::Handle, _filter_method: image::FilterMethod, _bounds: Rectangle, + _rotation: Radians, ) { } } @@ -185,6 +187,7 @@ impl svg::Renderer for () { _handle: svg::Handle, _color: Option<Color>, _bounds: Rectangle, + _rotation: Radians, ) { } } diff --git a/core/src/rotation.rs b/core/src/rotation.rs new file mode 100644 index 00000000..afa8d79e --- /dev/null +++ b/core/src/rotation.rs @@ -0,0 +1,72 @@ +//! Control the rotation of some content (like an image) within a space. +use crate::{Degrees, Radians, Size}; + +/// The strategy used to rotate the content. +/// +/// This is used to control the behavior of the layout when the content is rotated +/// by a certain angle. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Rotation { + /// The element will float while rotating. The layout will be kept exactly as it was + /// before the rotation. + /// + /// This is especially useful when used for animations, as it will avoid the + /// layout being shifted or resized when smoothly i.e. an icon. + /// + /// This is the default. + Floating(Radians), + /// The element will be solid while rotating. The layout will be adjusted to fit + /// the rotated content. + /// + /// This allows you to rotate an image and have the layout adjust to fit the new + /// size of the image. + Solid(Radians), +} + +impl Rotation { + /// Returns the angle of the [`Rotation`] in [`Radians`]. + pub fn radians(self) -> Radians { + match self { + Rotation::Floating(radians) | Rotation::Solid(radians) => radians, + } + } + + /// Returns a mutable reference to the angle of the [`Rotation`] in [`Radians`]. + pub fn radians_mut(&mut self) -> &mut Radians { + match self { + Rotation::Floating(radians) | Rotation::Solid(radians) => radians, + } + } + + /// Returns the angle of the [`Rotation`] in [`Degrees`]. + pub fn degrees(self) -> Degrees { + Degrees(self.radians().0.to_degrees()) + } + + /// Applies the [`Rotation`] to the given [`Size`], returning + /// the minimum [`Size`] containing the rotated one. + pub fn apply(self, size: Size) -> Size { + match self { + Self::Floating(_) => size, + Self::Solid(rotation) => size.rotate(rotation), + } + } +} + +impl Default for Rotation { + fn default() -> Self { + Self::Floating(Radians(0.0)) + } +} + +impl From<Radians> for Rotation { + fn from(radians: Radians) -> Self { + Self::Floating(radians) + } +} + +impl From<f32> for Rotation { + fn from(radians: f32) -> Self { + Self::Floating(Radians(radians)) + } +} diff --git a/core/src/size.rs b/core/src/size.rs index c2b5671a..d7459355 100644 --- a/core/src/size.rs +++ b/core/src/size.rs @@ -1,4 +1,4 @@ -use crate::Vector; +use crate::{Radians, Vector}; /// An amount of space in 2 dimensions. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] @@ -51,6 +51,19 @@ impl Size { height: self.height + other.height, } } + + /// Rotates the given [`Size`] and returns the minimum [`Size`] + /// containing it. + pub fn rotate(self, rotation: Radians) -> Size { + let radians = f32::from(rotation); + + Size { + width: (self.width * radians.cos()).abs() + + (self.height * radians.sin()).abs(), + height: (self.width * radians.sin()).abs() + + (self.height * radians.cos()).abs(), + } + } } impl<T> From<[T; 2]> for Size<T> { @@ -113,3 +126,17 @@ where } } } + +impl<T> std::ops::Mul<Vector<T>> for Size<T> +where + T: std::ops::Mul<Output = T> + Copy, +{ + type Output = Size<T>; + + fn mul(self, scale: Vector<T>) -> Self::Output { + Size { + width: self.width * scale.x, + height: self.height * scale.y, + } + } +} diff --git a/core/src/svg.rs b/core/src/svg.rs index 0106e0c2..01f102e3 100644 --- a/core/src/svg.rs +++ b/core/src/svg.rs @@ -1,5 +1,5 @@ //! Load and draw vector graphics. -use crate::{Color, Rectangle, Size}; +use crate::{Color, Radians, Rectangle, Size}; use rustc_hash::FxHasher; use std::borrow::Cow; @@ -100,5 +100,6 @@ pub trait Renderer: crate::Renderer { handle: Handle, color: Option<Color>, bounds: Rectangle, + rotation: Radians, ); } diff --git a/core/src/vector.rs b/core/src/vector.rs index 1380c3b3..049e648f 100644 --- a/core/src/vector.rs +++ b/core/src/vector.rs @@ -18,6 +18,9 @@ impl<T> Vector<T> { impl Vector { /// The zero [`Vector`]. pub const ZERO: Self = Self::new(0.0, 0.0); + + /// The unit [`Vector`]. + pub const UNIT: Self = Self::new(0.0, 0.0); } impl<T> std::ops::Add for Vector<T> |