From 53a183fe0d6aed460fbb8155ac9541757277aab3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:35:14 +0100 Subject: Restore `canvas::Frame` API --- graphics/src/geometry/frame.rs | 208 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 graphics/src/geometry/frame.rs (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs new file mode 100644 index 00000000..e88c43b0 --- /dev/null +++ b/graphics/src/geometry/frame.rs @@ -0,0 +1,208 @@ +use crate::core::{Point, Radians, Rectangle, Size, Vector}; +use crate::geometry::{self, Geometry}; +use crate::geometry::{Fill, Path, Stroke, Text}; + +pub struct Frame +where + Renderer: geometry::Renderer, +{ + raw: Renderer::Frame, +} + +impl Frame +where + Renderer: geometry::Renderer, +{ + pub fn new(renderer: &Renderer, size: Size) -> Self { + Self { + raw: renderer.new_frame(size), + } + } + + /// Returns the width of the [`Frame`]. + pub fn width(&self) -> f32 { + self.raw.width() + } + + /// Returns the height of the [`Frame`]. + pub fn height(&self) -> f32 { + self.raw.height() + } + + /// Returns the dimensions of the [`Frame`]. + pub fn size(&self) -> Size { + self.raw.size() + } + + /// Returns the coordinate of the center of the [`Frame`]. + pub fn center(&self) -> Point { + self.raw.center() + } + + /// Draws the given [`Path`] on the [`Frame`] by filling it with the + /// provided style. + pub fn fill(&mut self, path: &Path, fill: impl Into) { + self.raw.fill(path, fill); + } + + /// Draws an axis-aligned rectangle given its top-left corner coordinate and + /// its `Size` on the [`Frame`] by filling it with the provided style. + pub fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ) { + self.raw.fill_rectangle(top_left, size, fill); + } + + /// Draws the stroke of the given [`Path`] on the [`Frame`] with the + /// provided style. + pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { + self.raw.stroke(path, stroke); + } + + /// Draws the characters of the given [`Text`] on the [`Frame`], filling + /// them with the given color. + /// + /// __Warning:__ Text currently does not work well with rotations and scale + /// transforms! The position will be correctly transformed, but the + /// resulting glyphs will not be rotated or scaled properly. + /// + /// Additionally, all text will be rendered on top of all the layers of + /// a `Canvas`. Therefore, it is currently only meant to be used for + /// overlays, which is the most common use case. + /// + /// Support for vectorial text is planned, and should address all these + /// limitations. + pub fn fill_text(&mut self, text: impl Into) { + self.raw.fill_text(text); + } + + /// Stores the current transform of the [`Frame`] and executes the given + /// drawing operations, restoring the transform afterwards. + /// + /// This method is useful to compose transforms and perform drawing + /// operations in different coordinate systems. + #[inline] + pub fn with_save(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { + self.push_transform(); + + let result = f(self); + + self.pop_transform(); + + result + } + + /// Pushes the current transform in the transform stack. + pub fn push_transform(&mut self) { + self.raw.push_transform(); + } + + /// Pops a transform from the transform stack and sets it as the current transform. + pub fn pop_transform(&mut self) { + self.raw.pop_transform(); + } + + /// Executes the given drawing operations within a [`Rectangle`] region, + /// clipping any geometry that overflows its bounds. Any transformations + /// performed are local to the provided closure. + /// + /// This method is useful to perform drawing operations that need to be + /// clipped. + #[inline] + pub fn with_clip( + &mut self, + region: Rectangle, + f: impl FnOnce(&mut Self) -> R, + ) -> R { + let mut frame = self.draft(region.size()); + + let result = f(&mut frame); + + let origin = Point::new(region.x, region.y); + + self.paste(frame, origin); + + result + } + + /// Creates a new [`Frame`] with the given [`Size`]. + /// + /// Draw its contents back to this [`Frame`] with [`paste`]. + /// + /// [`paste`]: Self::paste + pub fn draft(&mut self, size: Size) -> Self { + Self { + raw: self.raw.draft(size), + } + } + + /// Draws the contents of the given [`Frame`] with origin at the given [`Point`]. + pub fn paste(&mut self, frame: Self, at: Point) { + self.raw.paste(frame.raw, at); + } + + /// Applies a translation to the current transform of the [`Frame`]. + pub fn translate(&mut self, translation: Vector) { + self.raw.translate(translation); + } + + /// Applies a rotation in radians to the current transform of the [`Frame`]. + pub fn rotate(&mut self, angle: impl Into) { + self.raw.rotate(angle); + } + + /// Applies a uniform scaling to the current transform of the [`Frame`]. + pub fn scale(&mut self, scale: impl Into) { + self.raw.scale(scale); + } + + /// Applies a non-uniform scaling to the current transform of the [`Frame`]. + pub fn scale_nonuniform(&mut self, scale: impl Into) { + self.raw.scale_nonuniform(scale); + } + + pub fn into_geometry(self) -> Renderer::Geometry { + self.raw.into_geometry() + } +} + +/// The internal implementation of a [`Frame`]. +/// +/// Analogous to [`Frame`]. See [`Frame`] for the documentation +/// of each method. +#[allow(missing_docs)] +pub trait Backend: Sized { + type Geometry: Geometry; + + fn width(&self) -> f32; + fn height(&self) -> f32; + fn size(&self) -> Size; + fn center(&self) -> Point; + + fn push_transform(&mut self); + fn pop_transform(&mut self); + + fn translate(&mut self, translation: Vector); + fn rotate(&mut self, angle: impl Into); + fn scale(&mut self, scale: impl Into); + fn scale_nonuniform(&mut self, scale: impl Into); + + fn draft(&mut self, size: Size) -> Self; + fn paste(&mut self, frame: Self, at: Point); + + fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>); + + fn fill(&mut self, path: &Path, fill: impl Into); + fn fill_text(&mut self, text: impl Into); + fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ); + + fn into_geometry(self) -> Self::Geometry; +} -- cgit From 85800c99ab285efd244c0addfdcf3c732a98de1d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:53:48 +0100 Subject: Fix broken links in documentation --- graphics/src/geometry/frame.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index e88c43b0..37e0df38 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -1,7 +1,10 @@ +//! Draw and generate geometry. use crate::core::{Point, Radians, Rectangle, Size, Vector}; -use crate::geometry::{self, Geometry}; -use crate::geometry::{Fill, Path, Stroke, Text}; +use crate::geometry::{self, Fill, Path, Stroke, Text}; +use crate::Cached; +/// The region of a surface that can be used to draw geometry. +#[allow(missing_debug_implementations)] pub struct Frame where Renderer: geometry::Renderer, @@ -13,6 +16,7 @@ impl Frame where Renderer: geometry::Renderer, { + /// Creates a new [`Frame`] with the given dimensions. pub fn new(renderer: &Renderer, size: Size) -> Self { Self { raw: renderer.new_frame(size), @@ -164,6 +168,7 @@ where self.raw.scale_nonuniform(scale); } + /// Turns the [`Frame`] into its underlying geometry. pub fn into_geometry(self) -> Renderer::Geometry { self.raw.into_geometry() } @@ -175,7 +180,7 @@ where /// of each method. #[allow(missing_docs)] pub trait Backend: Sized { - type Geometry: Geometry; + type Geometry: Cached; fn width(&self) -> f32; fn height(&self) -> f32; -- cgit From bbafeed13d20f2cbd6fc18b949b34596aa0c6c2e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:55:28 +0100 Subject: Fix outdated warning in docs of `Frame::fill_text` --- graphics/src/geometry/frame.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index 37e0df38..b54fca5d 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -69,16 +69,9 @@ where /// Draws the characters of the given [`Text`] on the [`Frame`], filling /// them with the given color. /// - /// __Warning:__ Text currently does not work well with rotations and scale - /// transforms! The position will be correctly transformed, but the - /// resulting glyphs will not be rotated or scaled properly. - /// - /// Additionally, all text will be rendered on top of all the layers of + /// __Warning:__ All text will be rendered on top of all the layers of /// a `Canvas`. Therefore, it is currently only meant to be used for /// overlays, which is the most common use case. - /// - /// Support for vectorial text is planned, and should address all these - /// limitations. pub fn fill_text(&mut self, text: impl Into) { self.raw.fill_text(text); } -- cgit From 1f13a91361258a1607c71f4840a26a6437f88612 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 05:27:31 +0100 Subject: Make `iced_tiny_skia` optional with a `tiny-skia` feature --- graphics/src/geometry/frame.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index b54fca5d..635012d0 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -1,7 +1,6 @@ //! Draw and generate geometry. use crate::core::{Point, Radians, Rectangle, Size, Vector}; use crate::geometry::{self, Fill, Path, Stroke, Text}; -use crate::Cached; /// The region of a surface that can be used to draw geometry. #[allow(missing_debug_implementations)] @@ -173,7 +172,7 @@ where /// of each method. #[allow(missing_docs)] pub trait Backend: Sized { - type Geometry: Cached; + type Geometry; fn width(&self) -> f32; fn height(&self) -> f32; -- cgit From 4f2f40c68b4647f281d34034beb159a41422aa06 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 05:41:15 +0100 Subject: Fix standalone compilation of `iced_widget` crate --- graphics/src/geometry/frame.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index 635012d0..ad35e8ec 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -203,3 +203,49 @@ pub trait Backend: Sized { fn into_geometry(self) -> Self::Geometry; } + +#[cfg(debug_assertions)] +impl Backend for () { + type Geometry = (); + + fn width(&self) -> f32 { + 0.0 + } + + fn height(&self) -> f32 { + 0.0 + } + + fn size(&self) -> Size { + Size::ZERO + } + + fn center(&self) -> Point { + Point::ORIGIN + } + + fn push_transform(&mut self) {} + fn pop_transform(&mut self) {} + + fn translate(&mut self, _translation: Vector) {} + fn rotate(&mut self, _angle: impl Into) {} + fn scale(&mut self, _scale: impl Into) {} + fn scale_nonuniform(&mut self, _scale: impl Into) {} + + fn draft(&mut self, _size: Size) -> Self {} + fn paste(&mut self, _frame: Self, _at: Point) {} + + fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into>) {} + + fn fill(&mut self, _path: &Path, _fill: impl Into) {} + fn fill_text(&mut self, _text: impl Into) {} + fn fill_rectangle( + &mut self, + _top_left: Point, + _size: Size, + _fill: impl Into, + ) { + } + + fn into_geometry(self) -> Self::Geometry {} +} -- cgit From 6d3e1d835e1688fbc58622a03a784ed25ed3f0e1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 23:59:21 +0200 Subject: Decouple caching from layering and simplify everything --- graphics/src/geometry/frame.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'graphics/src/geometry/frame.rs') diff --git a/graphics/src/geometry/frame.rs b/graphics/src/geometry/frame.rs index ad35e8ec..377589d7 100644 --- a/graphics/src/geometry/frame.rs +++ b/graphics/src/geometry/frame.rs @@ -113,13 +113,11 @@ where region: Rectangle, f: impl FnOnce(&mut Self) -> R, ) -> R { - let mut frame = self.draft(region.size()); + let mut frame = self.draft(region); let result = f(&mut frame); - let origin = Point::new(region.x, region.y); - - self.paste(frame, origin); + self.paste(frame, Point::new(region.x, region.y)); result } @@ -129,14 +127,14 @@ where /// Draw its contents back to this [`Frame`] with [`paste`]. /// /// [`paste`]: Self::paste - pub fn draft(&mut self, size: Size) -> Self { + fn draft(&mut self, clip_bounds: Rectangle) -> Self { Self { - raw: self.raw.draft(size), + raw: self.raw.draft(clip_bounds), } } /// Draws the contents of the given [`Frame`] with origin at the given [`Point`]. - pub fn paste(&mut self, frame: Self, at: Point) { + fn paste(&mut self, frame: Self, at: Point) { self.raw.paste(frame.raw, at); } @@ -187,7 +185,7 @@ pub trait Backend: Sized { fn scale(&mut self, scale: impl Into); fn scale_nonuniform(&mut self, scale: impl Into); - fn draft(&mut self, size: Size) -> Self; + fn draft(&mut self, clip_bounds: Rectangle) -> Self; fn paste(&mut self, frame: Self, at: Point); fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>); @@ -232,7 +230,7 @@ impl Backend for () { fn scale(&mut self, _scale: impl Into) {} fn scale_nonuniform(&mut self, _scale: impl Into) {} - fn draft(&mut self, _size: Size) -> Self {} + fn draft(&mut self, _clip_bounds: Rectangle) -> Self {} fn paste(&mut self, _frame: Self, _at: Point) {} fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into>) {} -- cgit