diff options
| author | 2024-08-04 14:52:29 +0200 | |
|---|---|---|
| committer | 2024-08-04 14:52:29 +0200 | |
| commit | 145c3dc8fc4f92c400fbc3f8202ed22e1d498663 (patch) | |
| tree | fe48b8e7f0021100aa2a0c697437527212af3475 /core | |
| parent | 9cccaebb04944f2295cadff716d9708f4caa5642 (diff) | |
| parent | cc076903dda18f79dbd82238f7a8216bab8c679d (diff) | |
| download | iced-145c3dc8fc4f92c400fbc3f8202ed22e1d498663.tar.gz iced-145c3dc8fc4f92c400fbc3f8202ed22e1d498663.tar.bz2 iced-145c3dc8fc4f92c400fbc3f8202ed22e1d498663.zip | |
Merge pull request #2537 from iced-rs/feature/canvas-image-support
`image` and `svg` support for `canvas`
Diffstat (limited to '')
| -rw-r--r-- | core/src/image.rs | 85 | ||||
| -rw-r--r-- | core/src/lib.rs | 2 | ||||
| -rw-r--r-- | core/src/rectangle.rs | 56 | ||||
| -rw-r--r-- | core/src/renderer/null.rs | 27 | ||||
| -rw-r--r-- | core/src/svg.rs | 69 | 
5 files changed, 199 insertions, 40 deletions
| diff --git a/core/src/image.rs b/core/src/image.rs index 82ecdd0f..f985636a 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -7,6 +7,73 @@ use rustc_hash::FxHasher;  use std::hash::{Hash, Hasher};  use std::path::{Path, PathBuf}; +/// A raster image that can be drawn. +#[derive(Debug, Clone, PartialEq)] +pub struct Image<H = Handle> { +    /// The handle of the image. +    pub handle: H, + +    /// The filter method of the image. +    pub filter_method: FilterMethod, + +    /// The rotation to be applied to the image; on its center. +    pub rotation: Radians, + +    /// The opacity of the image. +    /// +    /// 0 means transparent. 1 means opaque. +    pub opacity: f32, + +    /// If set to `true`, the image will be snapped to the pixel grid. +    /// +    /// This can avoid graphical glitches, specially when using +    /// [`FilterMethod::Nearest`]. +    pub snap: bool, +} + +impl Image<Handle> { +    /// Creates a new [`Image`] with the given handle. +    pub fn new(handle: impl Into<Handle>) -> Self { +        Self { +            handle: handle.into(), +            filter_method: FilterMethod::default(), +            rotation: Radians(0.0), +            opacity: 1.0, +            snap: false, +        } +    } + +    /// Sets the filter method of the [`Image`]. +    pub fn filter_method(mut self, filter_method: FilterMethod) -> Self { +        self.filter_method = filter_method; +        self +    } + +    /// Sets the rotation of the [`Image`]. +    pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self { +        self.rotation = rotation.into(); +        self +    } + +    /// Sets the opacity of the [`Image`]. +    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self { +        self.opacity = opacity.into(); +        self +    } + +    /// Sets whether the [`Image`] should be snapped to the pixel grid. +    pub fn snap(mut self, snap: bool) -> Self { +        self.snap = snap; +        self +    } +} + +impl From<&Handle> for Image { +    fn from(handle: &Handle) -> Self { +        Image::new(handle.clone()) +    } +} +  /// A handle of some image data.  #[derive(Clone, PartialEq, Eq)]  pub enum Handle { @@ -101,6 +168,12 @@ where      }  } +impl From<&Handle> for Handle { +    fn from(value: &Handle) -> Self { +        value.clone() +    } +} +  impl std::fmt::Debug for Handle {      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {          match self { @@ -166,14 +239,6 @@ pub trait Renderer: crate::Renderer {      /// Returns the dimensions of an image for the given [`Handle`].      fn measure_image(&self, handle: &Self::Handle) -> Size<u32>; -    /// Draws an image with the given [`Handle`] and inside the provided -    /// `bounds`. -    fn draw_image( -        &mut self, -        handle: Self::Handle, -        filter_method: FilterMethod, -        bounds: Rectangle, -        rotation: Radians, -        opacity: f32, -    ); +    /// Draws an [`Image`] inside the provided `bounds`. +    fn draw_image(&mut self, image: Image<Self::Handle>, bounds: Rectangle);  } diff --git a/core/src/lib.rs b/core/src/lib.rs index 40a288e5..df599f45 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -57,6 +57,7 @@ pub use element::Element;  pub use event::Event;  pub use font::Font;  pub use gradient::Gradient; +pub use image::Image;  pub use layout::Layout;  pub use length::Length;  pub use overlay::Overlay; @@ -69,6 +70,7 @@ pub use rotation::Rotation;  pub use shadow::Shadow;  pub use shell::Shell;  pub use size::Size; +pub use svg::Svg;  pub use text::Text;  pub use theme::Theme;  pub use transformation::Transformation; diff --git a/core/src/rectangle.rs b/core/src/rectangle.rs index 1556e072..99c8d55d 100644 --- a/core/src/rectangle.rs +++ b/core/src/rectangle.rs @@ -47,6 +47,62 @@ impl Rectangle<f32> {          }      } +    /// Creates a new square [`Rectangle`] with the center at the origin and +    /// with the given radius. +    pub fn with_radius(radius: f32) -> Self { +        Self { +            x: -radius, +            y: -radius, +            width: radius * 2.0, +            height: radius * 2.0, +        } +    } + +    /// Creates a new axis-aligned [`Rectangle`] from the given vertices; returning the +    /// rotation in [`Radians`] that must be applied to the axis-aligned [`Rectangle`] +    /// to obtain the desired result. +    pub fn with_vertices( +        top_left: Point, +        top_right: Point, +        bottom_left: Point, +    ) -> (Rectangle, Radians) { +        let width = (top_right.x - top_left.x).hypot(top_right.y - top_left.y); + +        let height = +            (bottom_left.x - top_left.x).hypot(bottom_left.y - top_left.y); + +        let rotation = +            (top_right.y - top_left.y).atan2(top_right.x - top_left.x); + +        let rotation = if rotation < 0.0 { +            2.0 * std::f32::consts::PI + rotation +        } else { +            rotation +        }; + +        let position = { +            let center = Point::new( +                (top_right.x + bottom_left.x) / 2.0, +                (top_right.y + bottom_left.y) / 2.0, +            ); + +            let rotation = -rotation - std::f32::consts::PI * 2.0; + +            Point::new( +                center.x + (top_left.x - center.x) * rotation.cos() +                    - (top_left.y - center.y) * rotation.sin(), +                center.y +                    + (top_left.x - center.x) * rotation.sin() +                    + (top_left.y - center.y) * rotation.cos(), +            ) +        }; + +        ( +            Rectangle::new(position, Size::new(width, height)), +            Radians(rotation), +        ) +    } +      /// Returns the [`Point`] at the center of the [`Rectangle`].      pub fn center(&self) -> Point {          Point::new(self.center_x(), self.center_y()) diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index 5c7513c6..e3a07280 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -1,11 +1,10 @@  use crate::alignment; -use crate::image; +use crate::image::{self, Image};  use crate::renderer::{self, Renderer};  use crate::svg;  use crate::text::{self, Text};  use crate::{ -    Background, Color, Font, Pixels, Point, Radians, Rectangle, Size, -    Transformation, +    Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,  };  impl Renderer for () { @@ -178,21 +177,13 @@ impl text::Editor for () {  }  impl image::Renderer for () { -    type Handle = (); +    type Handle = image::Handle;      fn measure_image(&self, _handle: &Self::Handle) -> Size<u32> {          Size::default()      } -    fn draw_image( -        &mut self, -        _handle: Self::Handle, -        _filter_method: image::FilterMethod, -        _bounds: Rectangle, -        _rotation: Radians, -        _opacity: f32, -    ) { -    } +    fn draw_image(&mut self, _image: Image, _bounds: Rectangle) {}  }  impl svg::Renderer for () { @@ -200,13 +191,5 @@ impl svg::Renderer for () {          Size::default()      } -    fn draw_svg( -        &mut self, -        _handle: svg::Handle, -        _color: Option<Color>, -        _bounds: Rectangle, -        _rotation: Radians, -        _opacity: f32, -    ) { -    } +    fn draw_svg(&mut self, _svg: svg::Svg, _bounds: Rectangle) {}  } diff --git a/core/src/svg.rs b/core/src/svg.rs index 946b8156..ac19b223 100644 --- a/core/src/svg.rs +++ b/core/src/svg.rs @@ -7,6 +7,66 @@ use std::hash::{Hash, Hasher as _};  use std::path::PathBuf;  use std::sync::Arc; +/// A raster image that can be drawn. +#[derive(Debug, Clone, PartialEq)] +pub struct Svg<H = Handle> { +    /// The handle of the [`Svg`]. +    pub handle: H, + +    /// The [`Color`] filter to be applied to the [`Svg`]. +    /// +    /// If some [`Color`] is set, the whole [`Svg`] will be +    /// painted with it—ignoring any intrinsic colors. +    /// +    /// This can be useful for coloring icons programmatically +    /// (e.g. with a theme). +    pub color: Option<Color>, + +    /// The rotation to be applied to the image; on its center. +    pub rotation: Radians, + +    /// The opacity of the [`Svg`]. +    /// +    /// 0 means transparent. 1 means opaque. +    pub opacity: f32, +} + +impl Svg<Handle> { +    /// Creates a new [`Svg`] with the given handle. +    pub fn new(handle: impl Into<Handle>) -> Self { +        Self { +            handle: handle.into(), +            color: None, +            rotation: Radians(0.0), +            opacity: 1.0, +        } +    } + +    /// Sets the [`Color`] filter of the [`Svg`]. +    pub fn color(mut self, color: impl Into<Color>) -> Self { +        self.color = Some(color.into()); +        self +    } + +    /// Sets the rotation of the [`Svg`]. +    pub fn rotation(mut self, rotation: impl Into<Radians>) -> Self { +        self.rotation = rotation.into(); +        self +    } + +    /// Sets the opacity of the [`Svg`]. +    pub fn opacity(mut self, opacity: impl Into<f32>) -> Self { +        self.opacity = opacity.into(); +        self +    } +} + +impl From<&Handle> for Svg { +    fn from(handle: &Handle) -> Self { +        Svg::new(handle.clone()) +    } +} +  /// A handle of Svg data.  #[derive(Debug, Clone, PartialEq, Eq)]  pub struct Handle { @@ -95,12 +155,5 @@ pub trait Renderer: crate::Renderer {      fn measure_svg(&self, handle: &Handle) -> Size<u32>;      /// Draws an SVG with the given [`Handle`], an optional [`Color`] filter, and inside the provided `bounds`. -    fn draw_svg( -        &mut self, -        handle: Handle, -        color: Option<Color>, -        bounds: Rectangle, -        rotation: Radians, -        opacity: f32, -    ); +    fn draw_svg(&mut self, svg: Svg, bounds: Rectangle);  } | 
