diff options
| author | 2024-05-02 13:15:17 +0200 | |
|---|---|---|
| committer | 2024-05-02 17:27:45 +0200 | |
| commit | 09a6bcfffc24f5abdc8709403bab7ae1e01563f1 (patch) | |
| tree | 8a09792cd01cb56a3a5d11184a60009f8a22a85f /widget/src | |
| parent | aae8e4f5cfabfc3725ac938023fa29a6737a380c (diff) | |
| download | iced-09a6bcfffc24f5abdc8709403bab7ae1e01563f1.tar.gz iced-09a6bcfffc24f5abdc8709403bab7ae1e01563f1.tar.bz2 iced-09a6bcfffc24f5abdc8709403bab7ae1e01563f1.zip  | |
Add `Image` rotation support
Co-authored-by: DKolter <68352124+DKolter@users.noreply.github.com>
Diffstat (limited to '')
| -rw-r--r-- | widget/src/image.rs | 73 | ||||
| -rw-r--r-- | widget/src/image/viewer.rs | 2 | ||||
| -rw-r--r-- | widget/src/svg.rs | 65 | 
3 files changed, 107 insertions, 33 deletions
diff --git a/widget/src/image.rs b/widget/src/image.rs index 21d371b7..3a0a5e53 100644 --- a/widget/src/image.rs +++ b/widget/src/image.rs @@ -1,5 +1,6 @@  //! Display images in your user interface.  pub mod viewer; +use iced_renderer::core::{Point, RotationLayout};  pub use viewer::Viewer;  use crate::core::image; @@ -8,7 +9,7 @@ use crate::core::mouse;  use crate::core::renderer;  use crate::core::widget::Tree;  use crate::core::{ -    ContentFit, Element, Layout, Length, Rectangle, Size, Vector, Widget, +    ContentFit, Element, Layout, Length, Rectangle, Size, Widget,  };  pub use image::{FilterMethod, Handle}; @@ -36,6 +37,8 @@ pub struct Image<Handle> {      height: Length,      content_fit: ContentFit,      filter_method: FilterMethod, +    rotation: f32, +    rotation_layout: RotationLayout,  }  impl<Handle> Image<Handle> { @@ -47,6 +50,8 @@ impl<Handle> Image<Handle> {              height: Length::Shrink,              content_fit: ContentFit::Contain,              filter_method: FilterMethod::default(), +            rotation: 0.0, +            rotation_layout: RotationLayout::Change,          }      } @@ -75,6 +80,18 @@ impl<Handle> Image<Handle> {          self.filter_method = filter_method;          self      } + +    /// Rotates the [`Image`] by the given angle in radians. +    pub fn rotation(mut self, degrees: f32) -> Self { +        self.rotation = degrees; +        self +    } + +    /// Sets the [`RotationLayout`] of the [`Image`]. +    pub fn rotation_layout(mut self, rotation_layout: RotationLayout) -> Self { +        self.rotation_layout = rotation_layout; +        self +    }  }  /// Computes the layout of an [`Image`]. @@ -85,22 +102,25 @@ pub fn layout<Renderer, Handle>(      width: Length,      height: Length,      content_fit: ContentFit, +    rotation: f32, +    rotation_layout: RotationLayout,  ) -> layout::Node  where      Renderer: image::Renderer<Handle = Handle>,  {      // The raw w/h of the underlying image -    let image_size = { -        let Size { width, height } = renderer.measure_image(handle); +    let image_size = renderer.measure_image(handle); +    let image_size = +        Size::new(image_size.width as f32, image_size.height as f32); -        Size::new(width as f32, height as f32) -    }; +    // The rotated size of the image +    let rotated_size = rotation_layout.apply_to_size(image_size, rotation);      // The size to be available to the widget prior to `Shrink`ing -    let raw_size = limits.resolve(width, height, image_size); +    let raw_size = limits.resolve(width, height, rotated_size);      // The uncropped size of the image when fit to the bounds above -    let full_size = content_fit.fit(image_size, raw_size); +    let full_size = content_fit.fit(rotated_size, raw_size);      // Shrink the widget to fit the resized image, if requested      let final_size = Size { @@ -124,32 +144,45 @@ pub fn draw<Renderer, Handle>(      handle: &Handle,      content_fit: ContentFit,      filter_method: FilterMethod, +    rotation: f32, +    rotation_layout: RotationLayout,  ) where      Renderer: image::Renderer<Handle = Handle>,      Handle: Clone,  {      let Size { width, height } = renderer.measure_image(handle);      let image_size = Size::new(width as f32, height as f32); +    let rotated_size = rotation_layout.apply_to_size(image_size, rotation);      let bounds = layout.bounds(); -    let adjusted_fit = content_fit.fit(image_size, bounds.size()); +    let adjusted_fit = content_fit.fit(rotated_size, bounds.size()); +    let scale = Size::new( +        adjusted_fit.width / rotated_size.width, +        adjusted_fit.height / rotated_size.height, +    );      let render = |renderer: &mut Renderer| { -        let offset = Vector::new( -            (bounds.width - adjusted_fit.width).max(0.0) / 2.0, -            (bounds.height - adjusted_fit.height).max(0.0) / 2.0, -        ); - -        let drawing_bounds = Rectangle { -            width: adjusted_fit.width, -            height: adjusted_fit.height, -            ..bounds +        let position = match content_fit { +            ContentFit::None => Point::new( +                bounds.position().x +                    + (rotated_size.width - image_size.width) / 2.0, +                bounds.position().y +                    + (rotated_size.height - image_size.height) / 2.0, +            ), +            _ => Point::new( +                bounds.center_x() - image_size.width / 2.0, +                bounds.center_y() - image_size.height / 2.0, +            ),          }; +        let drawing_bounds = Rectangle::new(position, image_size); +          renderer.draw_image(              handle.clone(),              filter_method, -            drawing_bounds + offset, +            drawing_bounds, +            rotation, +            scale,          );      }; @@ -187,6 +220,8 @@ where              self.width,              self.height,              self.content_fit, +            self.rotation, +            self.rotation_layout,          )      } @@ -206,6 +241,8 @@ where              &self.handle,              self.content_fit,              self.filter_method, +            self.rotation, +            self.rotation_layout,          );      }  } diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs index 214cb996..ccdfdebb 100644 --- a/widget/src/image/viewer.rs +++ b/widget/src/image/viewer.rs @@ -341,6 +341,8 @@ where                          y: bounds.y,                          ..Rectangle::with_size(image_size)                      }, +                    0.0, +                    Size::UNIT,                  );              });          }); diff --git a/widget/src/svg.rs b/widget/src/svg.rs index eb142189..21946af8 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -5,8 +5,8 @@ use crate::core::renderer;  use crate::core::svg;  use crate::core::widget::Tree;  use crate::core::{ -    Color, ContentFit, Element, Layout, Length, Rectangle, Size, Theme, Vector, -    Widget, +    Color, ContentFit, Element, Layout, Length, Point, Rectangle, +    RotationLayout, Size, Theme, Widget,  };  use std::path::PathBuf; @@ -29,6 +29,8 @@ where      height: Length,      content_fit: ContentFit,      class: Theme::Class<'a>, +    rotation: f32, +    rotation_layout: RotationLayout,  }  impl<'a, Theme> Svg<'a, Theme> @@ -43,6 +45,8 @@ where              height: Length::Shrink,              content_fit: ContentFit::Contain,              class: Theme::default(), +            rotation: 0.0, +            rotation_layout: RotationLayout::Change,          }      } @@ -95,6 +99,18 @@ where          self.class = class.into();          self      } + +    /// Rotates the [`Svg`] by the given angle in radians. +    pub fn rotation(mut self, degrees: f32) -> Self { +        self.rotation = degrees; +        self +    } + +    /// Sets the [`RotationLayout`] of the [`Svg`]. +    pub fn rotation_layout(mut self, rotation_layout: RotationLayout) -> Self { +        self.rotation_layout = rotation_layout; +        self +    }  }  impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> @@ -120,11 +136,16 @@ where          let Size { width, height } = renderer.measure_svg(&self.handle);          let image_size = Size::new(width as f32, height as f32); +        // The rotated size of the svg +        let rotated_size = self +            .rotation_layout +            .apply_to_size(image_size, self.rotation); +          // The size to be available to the widget prior to `Shrink`ing -        let raw_size = limits.resolve(self.width, self.height, image_size); +        let raw_size = limits.resolve(self.width, self.height, rotated_size);          // The uncropped size of the image when fit to the bounds above -        let full_size = self.content_fit.fit(image_size, raw_size); +        let full_size = self.content_fit.fit(rotated_size, raw_size);          // Shrink the widget to fit the resized image, if requested          let final_size = Size { @@ -153,23 +174,35 @@ where      ) {          let Size { width, height } = renderer.measure_svg(&self.handle);          let image_size = Size::new(width as f32, height as f32); +        let rotated_size = self +            .rotation_layout +            .apply_to_size(image_size, self.rotation);          let bounds = layout.bounds(); -        let adjusted_fit = self.content_fit.fit(image_size, bounds.size()); +        let adjusted_fit = self.content_fit.fit(rotated_size, bounds.size()); +        let scale = Size::new( +            adjusted_fit.width / rotated_size.width, +            adjusted_fit.height / rotated_size.height, +        ); +          let is_mouse_over = cursor.is_over(bounds);          let render = |renderer: &mut Renderer| { -            let offset = Vector::new( -                (bounds.width - adjusted_fit.width).max(0.0) / 2.0, -                (bounds.height - adjusted_fit.height).max(0.0) / 2.0, -            ); - -            let drawing_bounds = Rectangle { -                width: adjusted_fit.width, -                height: adjusted_fit.height, -                ..bounds +            let position = match self.content_fit { +                ContentFit::None => Point::new( +                    bounds.position().x +                        + (rotated_size.width - image_size.width) / 2.0, +                    bounds.position().y +                        + (rotated_size.height - image_size.height) / 2.0, +                ), +                _ => Point::new( +                    bounds.center_x() - image_size.width / 2.0, +                    bounds.center_y() - image_size.height / 2.0, +                ),              }; +            let drawing_bounds = Rectangle::new(position, image_size); +              let status = if is_mouse_over {                  Status::Hovered              } else { @@ -181,7 +214,9 @@ where              renderer.draw_svg(                  self.handle.clone(),                  style.color, -                drawing_bounds + offset, +                drawing_bounds, +                self.rotation, +                scale,              );          };  | 
