diff options
-rw-r--r-- | core/src/angle.rs | 43 | ||||
-rw-r--r-- | core/src/content_fit.rs | 14 | ||||
-rw-r--r-- | core/src/rotation.rs | 7 | ||||
-rw-r--r-- | examples/ferris/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/ferris/src/main.rs | 161 |
5 files changed, 234 insertions, 1 deletions
diff --git a/core/src/angle.rs b/core/src/angle.rs index 69630717..8322273c 100644 --- a/core/src/angle.rs +++ b/core/src/angle.rs @@ -7,6 +7,11 @@ use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Sub, SubAssign}; #[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,44 @@ 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 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); diff --git a/core/src/content_fit.rs b/core/src/content_fit.rs index 56d2ffa6..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 @@ -118,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/rotation.rs b/core/src/rotation.rs index ebb85f3c..f36ef089 100644 --- a/core/src/rotation.rs +++ b/core/src/rotation.rs @@ -1,5 +1,5 @@ //! Control the rotation of some content (like an image) within a space. -use crate::{Radians, Size}; +use crate::{Degrees, Radians, Size}; /// The strategy used to rotate the content. /// @@ -31,6 +31,11 @@ impl Rotation { } } + /// Returns the angle of the [`Rotation`] in [`Degrees`]. + pub fn degrees(self) -> Degrees { + Degrees(self.radians().0.to_degrees()) + } + /// Rotates the given [`Size`]. pub fn apply(self, size: Size) -> Size { match self { diff --git a/examples/ferris/Cargo.toml b/examples/ferris/Cargo.toml new file mode 100644 index 00000000..c9fb8c13 --- /dev/null +++ b/examples/ferris/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ferris" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2021" +publish = false + +[dependencies] +iced.workspace = true +iced.features = ["image"] diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs new file mode 100644 index 00000000..d846f560 --- /dev/null +++ b/examples/ferris/src/main.rs @@ -0,0 +1,161 @@ +use iced::widget::{column, container, image, pick_list, row, slider, text}; +use iced::{ + Alignment, Color, ContentFit, Degrees, Element, Length, Rotation, Theme, +}; + +pub fn main() -> iced::Result { + iced::program("Ferris - Iced", Image::update, Image::view) + .theme(|_| Theme::TokyoNight) + .run() +} + +struct Image { + width: f32, + rotation: Rotation, + content_fit: ContentFit, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + WidthChanged(f32), + RotationStrategyChanged(RotationStrategy), + RotationChanged(Degrees), + ContentFitChanged(ContentFit), +} + +impl Image { + fn update(&mut self, message: Message) { + match message { + Message::WidthChanged(width) => { + self.width = width; + } + Message::RotationStrategyChanged(strategy) => { + self.rotation = match strategy { + RotationStrategy::Floating => { + Rotation::Floating(self.rotation.radians()) + } + RotationStrategy::Solid => { + Rotation::Solid(self.rotation.radians()) + } + }; + } + Message::RotationChanged(rotation) => { + self.rotation = match self.rotation { + Rotation::Floating(_) => { + Rotation::Floating(rotation.into()) + } + Rotation::Solid(_) => Rotation::Solid(rotation.into()), + }; + } + Message::ContentFitChanged(content_fit) => { + self.content_fit = content_fit; + } + } + } + + fn view(&self) -> Element<Message> { + let i_am_ferris = container( + column![ + "Hello!", + Element::from( + image(format!( + "{}/../tour/images/ferris.png", + env!("CARGO_MANIFEST_DIR") + )) + .width(self.width) + .content_fit(self.content_fit) + .rotation(self.rotation) + ) + .explain(Color::WHITE), + "I am Ferris!" + ] + .spacing(20) + .align_items(Alignment::Center), + ) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y(); + + let sizing = row![ + pick_list( + [ + ContentFit::Contain, + ContentFit::Cover, + ContentFit::Fill, + ContentFit::None, + ContentFit::ScaleDown + ], + Some(self.content_fit), + Message::ContentFitChanged + ) + .width(Length::Fill), + column![ + slider(100.0..=500.0, self.width, Message::WidthChanged), + text(format!("Width: {}px", self.width)) + .size(14) + .line_height(1.0) + ] + .spacing(5) + .align_items(Alignment::Center) + ] + .spacing(10); + + let rotation = row![ + pick_list( + [RotationStrategy::Floating, RotationStrategy::Solid], + Some(match self.rotation { + Rotation::Floating(_) => RotationStrategy::Floating, + Rotation::Solid(_) => RotationStrategy::Solid, + }), + Message::RotationStrategyChanged, + ) + .width(Length::Fill), + column![ + slider( + Degrees::RANGE, + self.rotation.degrees(), + Message::RotationChanged + ), + text(format!( + "Rotation: {:.0}°", + f32::from(self.rotation.degrees()) + )) + .size(14) + .line_height(1.0) + ] + .spacing(5) + .align_items(Alignment::Center) + ] + .spacing(10); + + container(column![i_am_ferris, sizing, rotation].spacing(10)) + .padding(10) + .into() + } +} + +impl Default for Image { + fn default() -> Self { + Self { + width: 300.0, + rotation: Rotation::default(), + content_fit: ContentFit::default(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RotationStrategy { + Floating, + Solid, +} + +impl std::fmt::Display for RotationStrategy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::Floating => "Floating", + Self::Solid => "Solid", + }) + } +} |