summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector@hecrj.dev>2024-08-04 14:52:29 +0200
committerLibravatar GitHub <noreply@github.com>2024-08-04 14:52:29 +0200
commit145c3dc8fc4f92c400fbc3f8202ed22e1d498663 (patch)
treefe48b8e7f0021100aa2a0c697437527212af3475 /core
parent9cccaebb04944f2295cadff716d9708f4caa5642 (diff)
parentcc076903dda18f79dbd82238f7a8216bab8c679d (diff)
downloadiced-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.rs85
-rw-r--r--core/src/lib.rs2
-rw-r--r--core/src/rectangle.rs56
-rw-r--r--core/src/renderer/null.rs27
-rw-r--r--core/src/svg.rs69
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);
}