From e84070acef84f883ca42d965c577e54ce60c3f2a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 3 Aug 2024 16:20:12 +0200 Subject: Implement `From<&Handle>` for `image::Handle` --- core/src/image.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'core') diff --git a/core/src/image.rs b/core/src/image.rs index 82ecdd0f..77ff7500 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -101,6 +101,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 { -- cgit From 0ceee1cf3ae49f5bd0e3f2b346a4b34076e4523a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 03:28:43 +0200 Subject: Implement image support for `canvas` widget --- core/src/rectangle.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'core') 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 { } } + /// 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()) -- cgit From 92bd3ecd6b4a6618f0fc725dea3694c3b40e5314 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 04:30:12 +0200 Subject: Introduce `Image` struct in `core::image` --- core/src/image.rs | 79 +++++++++++++++++++++++++++++++++++++++++------ core/src/lib.rs | 1 + core/src/renderer/null.rs | 14 +++------ 3 files changed, 74 insertions(+), 20 deletions(-) (limited to 'core') diff --git a/core/src/image.rs b/core/src/image.rs index 77ff7500..99d7f3ef 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 { + /// 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, from 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 a + /// [`FilterMethod::Nearest`]. + pub snap: bool, +} + +impl Image { + /// Creates a new [`Image`] with the given handle. + pub fn new(handle: impl Into) -> 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) -> Self { + self.rotation = rotation.into(); + self + } + + /// Sets the opacity of the [`Image`]. + pub fn opacity(mut self, opacity: impl Into) -> 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 { @@ -172,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; - /// 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, bounds: Rectangle); } diff --git a/core/src/lib.rs b/core/src/lib.rs index 40a288e5..0e17d430 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; diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index 5c7513c6..e71117da 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -1,5 +1,5 @@ use crate::alignment; -use crate::image; +use crate::image::{self, Image}; use crate::renderer::{self, Renderer}; use crate::svg; use crate::text::{self, Text}; @@ -178,20 +178,14 @@ impl text::Editor for () { } impl image::Renderer for () { - type Handle = (); + type Handle = image::Handle; fn measure_image(&self, _handle: &Self::Handle) -> Size { 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) { + todo!() } } -- cgit From 3904f0b83af2fd3cd0d841d34d0d9c6193eeb845 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 04:30:59 +0200 Subject: Remove `todo!` in `core::renderer::null` --- core/src/renderer/null.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'core') diff --git a/core/src/renderer/null.rs b/core/src/renderer/null.rs index e71117da..3c6f8be0 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -184,9 +184,7 @@ impl image::Renderer for () { Size::default() } - fn draw_image(&mut self, _image: Image, _bounds: Rectangle) { - todo!() - } + fn draw_image(&mut self, _image: Image, _bounds: Rectangle) {} } impl svg::Renderer for () { -- cgit From d4b08462e5a25929ec4df32f242898986902af56 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 4 Aug 2024 04:52:55 +0200 Subject: Introduce `Svg` struct in `core::svg` --- core/src/image.rs | 4 +-- core/src/lib.rs | 1 + core/src/renderer/null.rs | 13 ++------- core/src/svg.rs | 69 +++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 66 insertions(+), 21 deletions(-) (limited to 'core') diff --git a/core/src/image.rs b/core/src/image.rs index 99d7f3ef..f985636a 100644 --- a/core/src/image.rs +++ b/core/src/image.rs @@ -16,7 +16,7 @@ pub struct Image { /// The filter method of the image. pub filter_method: FilterMethod, - /// The rotation to be applied to the image, from its center. + /// The rotation to be applied to the image; on its center. pub rotation: Radians, /// The opacity of the image. @@ -26,7 +26,7 @@ pub struct Image { /// If set to `true`, the image will be snapped to the pixel grid. /// - /// This can avoid graphical glitches, specially when using a + /// This can avoid graphical glitches, specially when using /// [`FilterMethod::Nearest`]. pub snap: bool, } diff --git a/core/src/lib.rs b/core/src/lib.rs index 0e17d430..df599f45 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -70,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/renderer/null.rs b/core/src/renderer/null.rs index 3c6f8be0..e3a07280 100644 --- a/core/src/renderer/null.rs +++ b/core/src/renderer/null.rs @@ -4,8 +4,7 @@ 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 () { @@ -192,13 +191,5 @@ impl svg::Renderer for () { Size::default() } - fn draw_svg( - &mut self, - _handle: svg::Handle, - _color: Option, - _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 { + /// 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, + + /// 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 { + /// Creates a new [`Svg`] with the given handle. + pub fn new(handle: impl Into) -> 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) -> Self { + self.color = Some(color.into()); + self + } + + /// Sets the rotation of the [`Svg`]. + pub fn rotation(mut self, rotation: impl Into) -> Self { + self.rotation = rotation.into(); + self + } + + /// Sets the opacity of the [`Svg`]. + pub fn opacity(mut self, opacity: impl Into) -> 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; /// 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, - bounds: Rectangle, - rotation: Radians, - opacity: f32, - ); + fn draw_svg(&mut self, svg: Svg, bounds: Rectangle); } -- cgit