From efc55b655bfce98fc32e698cf3c2007e27be941a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 2 May 2024 17:14:20 +0200 Subject: Create `ferris` example to showcase `ContentFit` and `Rotation` --- examples/ferris/src/main.rs | 161 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 examples/ferris/src/main.rs (limited to 'examples/ferris/src/main.rs') 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 { + 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", + }) + } +} -- cgit From 4010e3983d40e24a5d7b590d8fec9801651199ce Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 May 2024 07:23:55 +0200 Subject: Add `spin` mode to `ferris` example :crab: --- examples/ferris/src/main.rs | 68 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 14 deletions(-) (limited to 'examples/ferris/src/main.rs') diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs index d846f560..b7536740 100644 --- a/examples/ferris/src/main.rs +++ b/examples/ferris/src/main.rs @@ -1,10 +1,16 @@ -use iced::widget::{column, container, image, pick_list, row, slider, text}; +use iced::time::Instant; +use iced::widget::{ + checkbox, column, container, image, pick_list, row, slider, text, +}; +use iced::window; use iced::{ - Alignment, Color, ContentFit, Degrees, Element, Length, Rotation, Theme, + Alignment, Color, ContentFit, Degrees, Element, Length, Radians, Rotation, + Subscription, Theme, }; pub fn main() -> iced::Result { iced::program("Ferris - Iced", Image::update, Image::view) + .subscription(Image::subscription) .theme(|_| Theme::TokyoNight) .run() } @@ -13,6 +19,8 @@ struct Image { width: f32, rotation: Rotation, content_fit: ContentFit, + spin: bool, + last_tick: Instant, } #[derive(Debug, Clone, Copy)] @@ -21,6 +29,8 @@ enum Message { RotationStrategyChanged(RotationStrategy), RotationChanged(Degrees), ContentFitChanged(ContentFit), + SpinToggled(bool), + RedrawRequested(Instant), } impl Image { @@ -50,6 +60,29 @@ impl Image { Message::ContentFitChanged(content_fit) => { self.content_fit = content_fit; } + Message::SpinToggled(spin) => { + self.spin = spin; + self.last_tick = Instant::now(); + } + Message::RedrawRequested(now) => { + const ROTATION_SPEED: Degrees = Degrees(360.0); + + let delta = (now - self.last_tick).as_millis() as f32 / 1_000.0; + + *self.rotation.radians_mut() = (self.rotation.radians() + + ROTATION_SPEED * delta) + % (2.0 * Radians::PI); + + self.last_tick = now; + } + } + } + + fn subscription(&self) -> Subscription { + if self.spin { + window::frames().map(Message::RedrawRequested) + } else { + Subscription::none() } } @@ -111,18 +144,23 @@ impl Image { 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) + row![ + 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), + checkbox("Spin!", self.spin).on_toggle(Message::SpinToggled) ] .spacing(5) .align_items(Alignment::Center) @@ -141,6 +179,8 @@ impl Default for Image { width: 300.0, rotation: Rotation::default(), content_fit: ContentFit::default(), + spin: false, + last_tick: Instant::now(), } } } -- cgit From 15057a05c118dafcb8cf90d4119e66caaa6026c5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 May 2024 09:11:46 +0200 Subject: Introduce `center` widget helper ... and also make `center_x` and `center_y` set `width` and `height` to `Length::Fill`, respectively. This targets the most common use case when centering things and removes a bunch of boilerplate as a result. --- examples/ferris/src/main.rs | 77 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 39 deletions(-) (limited to 'examples/ferris/src/main.rs') diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs index b7536740..13d746dd 100644 --- a/examples/ferris/src/main.rs +++ b/examples/ferris/src/main.rs @@ -1,6 +1,6 @@ use iced::time::Instant; use iced::widget::{ - checkbox, column, container, image, pick_list, row, slider, text, + center, checkbox, column, container, image, pick_list, row, slider, text, }; use iced::window; use iced::{ @@ -87,28 +87,22 @@ impl Image { } fn view(&self) -> Element { - 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 i_am_ferris = 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); let sizing = row![ pick_list( @@ -126,13 +120,14 @@ impl Image { column![ slider(100.0..=500.0, self.width, Message::WidthChanged), text(format!("Width: {}px", self.width)) - .size(14) + .size(12) .line_height(1.0) ] - .spacing(5) + .spacing(2) .align_items(Alignment::Center) ] - .spacing(10); + .spacing(10) + .align_items(Alignment::End); let rotation = row![ pick_list( @@ -144,30 +139,34 @@ impl Image { Message::RotationStrategyChanged, ) .width(Length::Fill), - row![ - column![ + column![ + row![ slider( Degrees::RANGE, self.rotation.degrees(), Message::RotationChanged ), - text(format!( - "Rotation: {:.0}°", - f32::from(self.rotation.degrees()) - )) - .size(14) - .line_height(1.0) + checkbox("Spin!", self.spin) + .text_size(12) + .on_toggle(Message::SpinToggled) + .size(12) ] - .spacing(5) + .spacing(10) .align_items(Alignment::Center), - checkbox("Spin!", self.spin).on_toggle(Message::SpinToggled) + text(format!( + "Rotation: {:.0}°", + f32::from(self.rotation.degrees()) + )) + .size(12) + .line_height(1.0) ] - .spacing(5) + .spacing(2) .align_items(Alignment::Center) ] - .spacing(10); + .spacing(10) + .align_items(Alignment::End); - container(column![i_am_ferris, sizing, rotation].spacing(10)) + container(column![center(i_am_ferris), sizing, rotation].spacing(10)) .padding(10) .into() } -- cgit From fa9e1d96ea1924b51749b775ea0e67e69bc8a305 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 May 2024 13:25:58 +0200 Subject: Introduce dynamic `opacity` support for `Image` and `Svg` --- examples/ferris/src/main.rs | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'examples/ferris/src/main.rs') diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs index 13d746dd..1d0e9181 100644 --- a/examples/ferris/src/main.rs +++ b/examples/ferris/src/main.rs @@ -17,6 +17,7 @@ pub fn main() -> iced::Result { struct Image { width: f32, + opacity: f32, rotation: Rotation, content_fit: ContentFit, spin: bool, @@ -26,6 +27,7 @@ struct Image { #[derive(Debug, Clone, Copy)] enum Message { WidthChanged(f32), + OpacityChanged(f32), RotationStrategyChanged(RotationStrategy), RotationChanged(Degrees), ContentFitChanged(ContentFit), @@ -39,6 +41,9 @@ impl Image { Message::WidthChanged(width) => { self.width = width; } + Message::OpacityChanged(opacity) => { + self.opacity = opacity; + } Message::RotationStrategyChanged(strategy) => { self.rotation = match strategy { RotationStrategy::Floating => { @@ -97,6 +102,7 @@ impl Image { .width(self.width) .content_fit(self.content_fit) .rotation(self.rotation) + .opacity(self.opacity) ) .explain(Color::WHITE), "I am Ferris!" @@ -117,14 +123,15 @@ impl Image { Message::ContentFitChanged ) .width(Length::Fill), - column![ + with_value( slider(100.0..=500.0, self.width, Message::WidthChanged), - text(format!("Width: {}px", self.width)) - .size(12) - .line_height(1.0) - ] - .spacing(2) - .align_items(Alignment::Center) + format!("Width: {}px", self.width) + ), + with_value( + slider(0.0..=1.0, self.opacity, Message::OpacityChanged) + .step(0.01), + format!("Opacity: {:.2}", self.opacity) + ) ] .spacing(10) .align_items(Alignment::End); @@ -139,7 +146,7 @@ impl Image { Message::RotationStrategyChanged, ) .width(Length::Fill), - column![ + with_value( row![ slider( Degrees::RANGE, @@ -153,15 +160,8 @@ impl Image { ] .spacing(10) .align_items(Alignment::Center), - text(format!( - "Rotation: {:.0}°", - f32::from(self.rotation.degrees()) - )) - .size(12) - .line_height(1.0) - ] - .spacing(2) - .align_items(Alignment::Center) + format!("Rotation: {:.0}°", f32::from(self.rotation.degrees())) + ) ] .spacing(10) .align_items(Alignment::End); @@ -176,6 +176,7 @@ impl Default for Image { fn default() -> Self { Self { width: 300.0, + opacity: 1.0, rotation: Rotation::default(), content_fit: ContentFit::default(), spin: false, @@ -198,3 +199,13 @@ impl std::fmt::Display for RotationStrategy { }) } } + +fn with_value<'a>( + control: impl Into>, + value: String, +) -> Element<'a, Message> { + column![control.into(), text(value).size(12).line_height(1.0)] + .spacing(2) + .align_items(Alignment::Center) + .into() +} -- cgit From afb4cb99b92a196bf4dd15a09a8f9bd191293fdd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 May 2024 13:32:51 +0200 Subject: Improve layout of `ferris` example :crab: --- examples/ferris/src/main.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'examples/ferris/src/main.rs') diff --git a/examples/ferris/src/main.rs b/examples/ferris/src/main.rs index 1d0e9181..0400c376 100644 --- a/examples/ferris/src/main.rs +++ b/examples/ferris/src/main.rs @@ -110,7 +110,7 @@ impl Image { .spacing(20) .align_items(Alignment::Center); - let sizing = row![ + let fit = row![ pick_list( [ ContentFit::Contain, @@ -123,20 +123,6 @@ impl Image { Message::ContentFitChanged ) .width(Length::Fill), - with_value( - slider(100.0..=500.0, self.width, Message::WidthChanged), - format!("Width: {}px", self.width) - ), - with_value( - slider(0.0..=1.0, self.opacity, Message::OpacityChanged) - .step(0.01), - format!("Opacity: {:.2}", self.opacity) - ) - ] - .spacing(10) - .align_items(Alignment::End); - - let rotation = row![ pick_list( [RotationStrategy::Floating, RotationStrategy::Solid], Some(match self.rotation { @@ -146,6 +132,20 @@ impl Image { Message::RotationStrategyChanged, ) .width(Length::Fill), + ] + .spacing(10) + .align_items(Alignment::End); + + let properties = row![ + with_value( + slider(100.0..=500.0, self.width, Message::WidthChanged), + format!("Width: {}px", self.width) + ), + with_value( + slider(0.0..=1.0, self.opacity, Message::OpacityChanged) + .step(0.01), + format!("Opacity: {:.2}", self.opacity) + ), with_value( row![ slider( @@ -166,7 +166,7 @@ impl Image { .spacing(10) .align_items(Alignment::End); - container(column![center(i_am_ferris), sizing, rotation].spacing(10)) + container(column![fit, center(i_am_ferris), properties].spacing(10)) .padding(10) .into() } -- cgit