From 188db4da48954b95a3fe79bcd22689ffc3a661e0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 05:52:48 +0100 Subject: Draft support for dynamic custom renderer injection --- widget/src/image.rs | 10 +++++++--- widget/src/image/viewer.rs | 7 +++---- widget/src/svg.rs | 6 +++--- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'widget') diff --git a/widget/src/image.rs b/widget/src/image.rs index ccf1f175..f673c7b3 100644 --- a/widget/src/image.rs +++ b/widget/src/image.rs @@ -93,7 +93,7 @@ where { // The raw w/h of the underlying image let image_size = { - let Size { width, height } = renderer.dimensions(handle); + let Size { width, height } = renderer.measure_image(handle); Size::new(width as f32, height as f32) }; @@ -130,7 +130,7 @@ pub fn draw( Renderer: image::Renderer, Handle: Clone + Hash, { - let Size { width, height } = renderer.dimensions(handle); + let Size { width, height } = renderer.measure_image(handle); let image_size = Size::new(width as f32, height as f32); let bounds = layout.bounds(); @@ -148,7 +148,11 @@ pub fn draw( ..bounds }; - renderer.draw(handle.clone(), filter_method, drawing_bounds + offset); + renderer.draw_image( + handle.clone(), + filter_method, + drawing_bounds + offset, + ); }; if adjusted_fit.width > bounds.width || adjusted_fit.height > bounds.height diff --git a/widget/src/image/viewer.rs b/widget/src/image/viewer.rs index 2e3fd713..5f7bb345 100644 --- a/widget/src/image/viewer.rs +++ b/widget/src/image/viewer.rs @@ -117,7 +117,7 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { - let Size { width, height } = renderer.dimensions(&self.handle); + let Size { width, height } = renderer.measure_image(&self.handle); let mut size = limits.resolve( self.width, @@ -335,8 +335,7 @@ where renderer.with_layer(bounds, |renderer| { renderer.with_translation(translation, |renderer| { - image::Renderer::draw( - renderer, + renderer.draw_image( self.handle.clone(), self.filter_method, Rectangle { @@ -421,7 +420,7 @@ pub fn image_size( where Renderer: image::Renderer, { - let Size { width, height } = renderer.dimensions(handle); + let Size { width, height } = renderer.measure_image(handle); let (width, height) = { let dimensions = (width as f32, height as f32); diff --git a/widget/src/svg.rs b/widget/src/svg.rs index 1ac07ade..53c45bcb 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -108,7 +108,7 @@ where limits: &layout::Limits, ) -> layout::Node { // The raw w/h of the underlying image - let Size { width, height } = renderer.dimensions(&self.handle); + let Size { width, height } = renderer.measure_svg(&self.handle); let image_size = Size::new(width as f32, height as f32); // The size to be available to the widget prior to `Shrink`ing @@ -142,7 +142,7 @@ where cursor: mouse::Cursor, _viewport: &Rectangle, ) { - let Size { width, height } = renderer.dimensions(&self.handle); + let Size { width, height } = renderer.measure_svg(&self.handle); let image_size = Size::new(width as f32, height as f32); let bounds = layout.bounds(); @@ -169,7 +169,7 @@ where let appearance = (self.style)(theme, status); - renderer.draw( + renderer.draw_svg( self.handle.clone(), appearance.color, drawing_bounds + offset, -- cgit From 3645d34d6a1ba1247238e830e9eefd52d9e5b986 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 22:27:17 +0100 Subject: Implement composable, type-safe renderer fallback --- widget/src/canvas.rs | 19 +++++++++++-------- widget/src/canvas/program.rs | 19 ++++++------------- widget/src/qr_code.rs | 9 +++++---- 3 files changed, 22 insertions(+), 25 deletions(-) (limited to 'widget') diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index 0eda0191..fcd91d17 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -7,7 +7,6 @@ pub use event::Event; pub use program::Program; pub use crate::graphics::geometry::*; -pub use crate::renderer::geometry::*; use crate::core; use crate::core::layout::{self, Layout}; @@ -21,13 +20,19 @@ use crate::graphics::geometry; use std::marker::PhantomData; +/// A simple cache that stores generated [`Geometry`] to avoid recomputation. +/// +/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer +/// change or it is explicitly cleared. +pub type Cache = geometry::Cache; + /// A widget capable of drawing 2D graphics. /// /// ## Drawing a simple circle /// If you want to get a quick overview, here's how we can draw a simple circle: /// /// ```no_run -/// # use iced_widget::canvas::{self, Canvas, Fill, Frame, Geometry, Path, Program}; +/// # use iced_widget::canvas::{self, frame, Canvas, Fill, Frame, Path, Program}; /// # use iced_widget::core::{Color, Rectangle}; /// # use iced_widget::core::mouse; /// # use iced_widget::{Renderer, Theme}; @@ -42,9 +47,9 @@ use std::marker::PhantomData; /// impl Program<()> for Circle { /// type State = (); /// -/// fn draw(&self, _state: &(), renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) -> Vec{ +/// fn draw(&self, _state: &(), renderer: &mut Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) { /// // We prepare a new `Frame` -/// let mut frame = Frame::new(renderer, bounds.size()); +/// let mut frame = frame(renderer, bounds.size()); /// /// // We create a `Path` representing a simple circle /// let circle = Path::circle(frame.center(), self.radius); @@ -53,7 +58,7 @@ use std::marker::PhantomData; /// frame.fill(&circle, Color::BLACK); /// /// // Finally, we produce the geometry -/// vec![frame.into_geometry()] +/// renderer.draw_geometry([frame]); /// } /// } /// @@ -210,9 +215,7 @@ where renderer.with_transformation( Transformation::translate(bounds.x, bounds.y), |renderer| { - renderer.draw( - self.program.draw(state, renderer, theme, bounds, cursor), - ); + self.program.draw(state, renderer, theme, bounds, cursor); }, ); } diff --git a/widget/src/canvas/program.rs b/widget/src/canvas/program.rs index 0bff4bda..307686de 100644 --- a/widget/src/canvas/program.rs +++ b/widget/src/canvas/program.rs @@ -37,22 +37,15 @@ where (event::Status::Ignored, None) } - /// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. - /// - /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a - /// [`Cache`]. - /// - /// [`Geometry`]: crate::canvas::Geometry - /// [`Frame`]: crate::canvas::Frame - /// [`Cache`]: crate::canvas::Cache + /// Draws the state of the [`Program`] with the given [`Renderer`]. fn draw( &self, state: &Self::State, - renderer: &Renderer, + renderer: &mut Renderer, theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, - ) -> Vec; + ); /// Returns the current mouse interaction of the [`Program`]. /// @@ -90,12 +83,12 @@ where fn draw( &self, state: &Self::State, - renderer: &Renderer, + renderer: &mut Renderer, theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, - ) -> Vec { - T::draw(self, state, renderer, theme, bounds, cursor) + ) { + T::draw(self, state, renderer, theme, bounds, cursor); } fn mouse_interaction( diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 90c0c970..bc46aaaa 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -8,7 +8,6 @@ use crate::core::{ Color, Element, Layout, Length, Point, Rectangle, Size, Theme, Vector, Widget, }; -use crate::graphics::geometry::Renderer as _; use crate::Renderer; use std::cell::RefCell; @@ -92,6 +91,8 @@ impl<'a, Message, Theme> Widget _cursor: mouse::Cursor, _viewport: &Rectangle, ) { + use canvas::Frame; + let state = tree.state.downcast_ref::(); let bounds = layout.bounds(); @@ -142,7 +143,7 @@ impl<'a, Message, Theme> Widget renderer.with_translation( bounds.position() - Point::ORIGIN, |renderer| { - renderer.draw(vec![geometry]); + renderer.draw_geometry(vec![geometry]); }, ); } @@ -161,11 +162,11 @@ where /// The data of a [`QRCode`]. /// /// It stores the contents that will be displayed. -#[derive(Debug)] +#[allow(missing_debug_implementations)] pub struct Data { contents: Vec, width: usize, - cache: canvas::Cache, + cache: canvas::Cache, } impl Data { -- cgit From b972ebca8f8c23d2df1b45bb26038789766a5a65 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 23:30:36 +0100 Subject: Restore `canvas::Program` API --- widget/src/canvas.rs | 17 +++++++++++++---- widget/src/canvas/program.rs | 11 ++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'widget') diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index fcd91d17..81067491 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -26,13 +26,17 @@ use std::marker::PhantomData; /// change or it is explicitly cleared. pub type Cache = geometry::Cache; +/// The geometry supported by a renderer. +pub type Geometry = + ::Geometry; + /// A widget capable of drawing 2D graphics. /// /// ## Drawing a simple circle /// If you want to get a quick overview, here's how we can draw a simple circle: /// /// ```no_run -/// # use iced_widget::canvas::{self, frame, Canvas, Fill, Frame, Path, Program}; +/// # use iced_widget::canvas::{self, frame, Canvas, Fill, Frame, Geometry, Path, Program}; /// # use iced_widget::core::{Color, Rectangle}; /// # use iced_widget::core::mouse; /// # use iced_widget::{Renderer, Theme}; @@ -47,7 +51,7 @@ pub type Cache = geometry::Cache; /// impl Program<()> for Circle { /// type State = (); /// -/// fn draw(&self, _state: &(), renderer: &mut Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) { +/// fn draw(&self, _state: &(), renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) -> Vec { /// // We prepare a new `Frame` /// let mut frame = frame(renderer, bounds.size()); /// @@ -58,7 +62,7 @@ pub type Cache = geometry::Cache; /// frame.fill(&circle, Color::BLACK); /// /// // Finally, we produce the geometry -/// renderer.draw_geometry([frame]); +/// vec![frame.into()] /// } /// } /// @@ -215,7 +219,12 @@ where renderer.with_transformation( Transformation::translate(bounds.x, bounds.y), |renderer| { - self.program.draw(state, renderer, theme, bounds, cursor); + let layers = + self.program.draw(state, renderer, theme, bounds, cursor); + + for layer in layers { + renderer.draw_geometry(layer); + } }, ); } diff --git a/widget/src/canvas/program.rs b/widget/src/canvas/program.rs index 307686de..3ba31474 100644 --- a/widget/src/canvas/program.rs +++ b/widget/src/canvas/program.rs @@ -1,5 +1,6 @@ use crate::canvas::event::{self, Event}; use crate::canvas::mouse; +use crate::canvas::Geometry; use crate::core::Rectangle; use crate::graphics::geometry; @@ -41,11 +42,11 @@ where fn draw( &self, state: &Self::State, - renderer: &mut Renderer, + renderer: &Renderer, theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, - ); + ) -> Vec>; /// Returns the current mouse interaction of the [`Program`]. /// @@ -83,12 +84,12 @@ where fn draw( &self, state: &Self::State, - renderer: &mut Renderer, + renderer: &Renderer, theme: &Theme, bounds: Rectangle, cursor: mouse::Cursor, - ) { - T::draw(self, state, renderer, theme, bounds, cursor); + ) -> Vec> { + T::draw(self, state, renderer, theme, bounds, cursor) } fn mouse_interaction( -- cgit 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 --- widget/src/canvas.rs | 14 ++++++++++---- widget/src/qr_code.rs | 2 -- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'widget') diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index 81067491..7a21895a 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -6,7 +6,10 @@ mod program; pub use event::Event; pub use program::Program; -pub use crate::graphics::geometry::*; +pub use crate::graphics::geometry::{ + fill, gradient, path, stroke, Fill, Gradient, LineCap, LineDash, LineJoin, + Path, Stroke, Style, Text, +}; use crate::core; use crate::core::layout::{self, Layout}; @@ -30,13 +33,16 @@ pub type Cache = geometry::Cache; pub type Geometry = ::Geometry; +/// The frame supported by a renderer. +pub type Frame = geometry::Frame; + /// A widget capable of drawing 2D graphics. /// /// ## Drawing a simple circle /// If you want to get a quick overview, here's how we can draw a simple circle: /// /// ```no_run -/// # use iced_widget::canvas::{self, frame, Canvas, Fill, Frame, Geometry, Path, Program}; +/// # use iced_widget::canvas::{self, Canvas, Fill, Frame, Geometry, Path, Program}; /// # use iced_widget::core::{Color, Rectangle}; /// # use iced_widget::core::mouse; /// # use iced_widget::{Renderer, Theme}; @@ -53,7 +59,7 @@ pub type Geometry = /// /// fn draw(&self, _state: &(), renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) -> Vec { /// // We prepare a new `Frame` -/// let mut frame = frame(renderer, bounds.size()); +/// let mut frame = Frame::new(renderer, bounds.size()); /// /// // We create a `Path` representing a simple circle /// let circle = Path::circle(frame.center(), self.radius); @@ -62,7 +68,7 @@ pub type Geometry = /// frame.fill(&circle, Color::BLACK); /// /// // Finally, we produce the geometry -/// vec![frame.into()] +/// vec![frame.into_geometry()] /// } /// } /// diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index bc46aaaa..84898dc0 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -91,8 +91,6 @@ impl<'a, Message, Theme> Widget _cursor: mouse::Cursor, _viewport: &Rectangle, ) { - use canvas::Frame; - let state = tree.state.downcast_ref::(); let bounds = layout.bounds(); -- 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 --- widget/src/canvas/program.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'widget') diff --git a/widget/src/canvas/program.rs b/widget/src/canvas/program.rs index 3ba31474..a7ded0f4 100644 --- a/widget/src/canvas/program.rs +++ b/widget/src/canvas/program.rs @@ -38,7 +38,14 @@ where (event::Status::Ignored, None) } - /// Draws the state of the [`Program`] with the given [`Renderer`]. + /// Draws the state of the [`Program`], producing a bunch of [`Geometry`]. + /// + /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a + /// [`Cache`]. + /// + /// [`Geometry`]: crate::canvas::Geometry + /// [`Frame`]: crate::canvas::Frame + /// [`Cache`]: crate::canvas::Cache fn draw( &self, state: &Self::State, -- 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 --- widget/src/qr_code.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'widget') diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index 84898dc0..601e5808 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -141,7 +141,9 @@ impl<'a, Message, Theme> Widget renderer.with_translation( bounds.position() - Point::ORIGIN, |renderer| { - renderer.draw_geometry(vec![geometry]); + use crate::graphics::geometry::Renderer as _; + + renderer.draw_geometry(geometry); }, ); } -- cgit