From 0b5028b1ab47707a469176e9bf20cacdd3a19861 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 14:39:30 +0200 Subject: Draft `Program` interactivity for `Canvas` --- wgpu/src/lib.rs | 2 +- wgpu/src/widget/canvas.rs | 82 +++++++++++++++++++++++------------ wgpu/src/widget/canvas/drawable.rs | 6 +++ wgpu/src/widget/canvas/event.rs | 6 +++ wgpu/src/widget/canvas/layer/cache.rs | 16 ++++++- wgpu/src/widget/canvas/program.rs | 16 +++++++ 6 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 wgpu/src/widget/canvas/event.rs create mode 100644 wgpu/src/widget/canvas/program.rs (limited to 'wgpu/src') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 799c1f34..30b5bb4a 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -20,7 +20,7 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -#![deny(missing_docs)] +//#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 325f90ce..de4f0203 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -9,7 +9,8 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ - layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size, Widget, + input::mouse, layout, Clipboard, Element, Hasher, Layout, Length, + MouseCursor, Point, Size, Widget, }; use std::hash::Hash; @@ -17,16 +18,20 @@ pub mod layer; pub mod path; mod drawable; +mod event; mod fill; mod frame; +mod program; mod stroke; mod text; pub use drawable::Drawable; +pub use event::Event; pub use fill::Fill; pub use frame::Frame; pub use layer::Layer; pub use path::Path; +pub use program::Program; pub use stroke::{LineCap, LineJoin, Stroke}; pub use text::Text; @@ -81,31 +86,31 @@ pub use text::Text; /// } /// /// // We can use a `Cache` to avoid unnecessary re-tessellation -/// let cache: layer::Cache = layer::Cache::new(); +/// let mut cache: layer::Cache = layer::Cache::new(); /// -/// // Finally, we simply provide the data to our `Cache` and push the resulting -/// // layer into a `Canvas` -/// let canvas = Canvas::new() -/// .push(cache.with(&Circle { radius: 50.0 })); +/// // Finally, we simply use our `Cache` to create the `Canvas`! +/// let canvas = Canvas::new(&mut cache, &Circle { radius: 50.0 }); /// ``` #[derive(Debug)] -pub struct Canvas<'a> { +pub struct Canvas<'a, P: Program> { width: Length, height: Length, - layers: Vec>, + program: &'a mut P, + input: &'a P::Input, } -impl<'a> Canvas<'a> { +impl<'a, P: Program> Canvas<'a, P> { const DEFAULT_SIZE: u16 = 100; /// Creates a new [`Canvas`] with no layers. /// /// [`Canvas`]: struct.Canvas.html - pub fn new() -> Self { + pub fn new(program: &'a mut P, input: &'a P::Input) -> Self { Canvas { width: Length::Units(Self::DEFAULT_SIZE), height: Length::Units(Self::DEFAULT_SIZE), - layers: Vec::new(), + program, + input, } } @@ -124,20 +129,9 @@ impl<'a> Canvas<'a> { self.height = height; self } - - /// Adds a [`Layer`] to the [`Canvas`]. - /// - /// It will be drawn on top of previous layers. - /// - /// [`Layer`]: layer/trait.Layer.html - /// [`Canvas`]: struct.Canvas.html - pub fn push(mut self, layer: impl Layer + 'a) -> Self { - self.layers.push(Box::new(layer)); - self - } } -impl<'a, Message> Widget for Canvas<'a> { +impl<'a, Message, P: Program> Widget for Canvas<'a, P> { fn width(&self) -> Length { self.width } @@ -157,6 +151,37 @@ impl<'a, Message> Widget for Canvas<'a> { layout::Node::new(size) } + fn on_event( + &mut self, + event: iced_native::Event, + layout: Layout<'_>, + cursor_position: Point, + _messages: &mut Vec, + _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, + ) { + let bounds = layout.bounds(); + + let canvas_event = match event { + iced_native::Event::Mouse(mouse_event) => { + Some(Event::Mouse(match mouse_event { + mouse::Event::CursorMoved { .. } => { + mouse::Event::CursorMoved { + x: cursor_position.x - bounds.x, + y: cursor_position.y - bounds.y, + } + } + _ => mouse_event, + })) + } + _ => None, + }; + + if let Some(canvas_event) = canvas_event { + self.program.update(canvas_event, bounds.size(), self.input) + } + } + fn draw( &self, _renderer: &mut Renderer, @@ -171,7 +196,8 @@ impl<'a, Message> Widget for Canvas<'a> { ( Primitive::Group { primitives: self - .layers + .program + .layers(self.input) .iter() .map(|layer| Primitive::Cached { origin, @@ -184,18 +210,20 @@ impl<'a, Message> Widget for Canvas<'a> { } fn hash_layout(&self, state: &mut Hasher) { - std::any::TypeId::of::>().hash(state); + struct Marker; + std::any::TypeId::of::().hash(state); self.width.hash(state); self.height.hash(state); } } -impl<'a, Message> From> for Element<'a, Message, Renderer> +impl<'a, Message, P: Program> From> + for Element<'a, Message, Renderer> where Message: 'static, { - fn from(canvas: Canvas<'a>) -> Element<'a, Message, Renderer> { + fn from(canvas: Canvas<'a, P>) -> Element<'a, Message, Renderer> { Element::new(canvas) } } diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs index 6c74071c..48ba6b4c 100644 --- a/wgpu/src/widget/canvas/drawable.rs +++ b/wgpu/src/widget/canvas/drawable.rs @@ -10,3 +10,9 @@ pub trait Drawable { /// [`Frame`]: struct.Frame.html fn draw(&self, frame: &mut Frame); } + +impl<'a> Drawable for dyn Fn(&mut Frame) + 'a { + fn draw(&self, frame: &mut Frame) { + self(frame) + } +} diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs new file mode 100644 index 00000000..7a8b0829 --- /dev/null +++ b/wgpu/src/widget/canvas/event.rs @@ -0,0 +1,6 @@ +use iced_native::input::mouse; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Event { + Mouse(mouse::Event), +} diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs index 4f8c2bec..2e87297c 100644 --- a/wgpu/src/widget/canvas/layer/cache.rs +++ b/wgpu/src/widget/canvas/layer/cache.rs @@ -1,5 +1,5 @@ use crate::{ - canvas::{Drawable, Frame, Layer}, + canvas::{Drawable, Frame, Layer, Program}, Primitive, }; @@ -79,6 +79,20 @@ where } } +impl Program for Cache +where + T: Drawable + std::fmt::Debug, +{ + type Input = T; + + fn layers<'a>( + &'a self, + input: &'a Self::Input, + ) -> Vec> { + vec![Box::new(self.with(input))] + } +} + #[derive(Debug)] struct Bind<'a, T: Drawable> { cache: &'a Cache, diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs new file mode 100644 index 00000000..c65a078b --- /dev/null +++ b/wgpu/src/widget/canvas/program.rs @@ -0,0 +1,16 @@ +use crate::canvas::{Event, Layer, Size}; + +pub trait Program { + type Input; + + fn layers<'a>(&'a self, input: &'a Self::Input) + -> Vec>; + + fn update<'a>( + &'a mut self, + _event: Event, + _bounds: Size, + _input: &'a Self::Input, + ) { + } +} -- cgit From 8ade09a0f6fd6bfdcefebb92ccbbff25d741062a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 14:41:25 +0200 Subject: Simplify `Canvas` example in documentation --- wgpu/src/widget/canvas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index de4f0203..326bc7d5 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -78,7 +78,7 @@ pub use text::Text; /// impl Drawable for Circle { /// fn draw(&self, frame: &mut Frame) { /// // We create a `Path` representing a simple circle -/// let circle = Path::new(|p| p.circle(frame.center(), self.radius)); +/// let circle = Path::circle(frame.center(), self.radius); /// /// // And fill it with some color /// frame.fill(&circle, Fill::Color(Color::BLACK)); -- cgit From a97acd8fa854a470f26e7c39a62b90f2e2c2c664 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 17:59:32 +0200 Subject: Use `Borrow` when binding in `layer::Cache` --- wgpu/src/widget/canvas/layer/cache.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs index 2e87297c..e8d62b63 100644 --- a/wgpu/src/widget/canvas/layer/cache.rs +++ b/wgpu/src/widget/canvas/layer/cache.rs @@ -4,7 +4,7 @@ use crate::{ }; use iced_native::Size; -use std::{cell::RefCell, marker::PhantomData, sync::Arc}; +use std::{borrow::Borrow, cell::RefCell, marker::PhantomData, sync::Arc}; enum State { Empty, @@ -71,7 +71,10 @@ where /// [`Cache`]: struct.Cache.html /// [`Layer`]: ../trait.Layer.html /// [`Canvas`]: ../../struct.Canvas.html - pub fn with<'a>(&'a self, input: &'a T) -> impl Layer + 'a { + pub fn with<'a>( + &'a self, + input: impl Borrow + std::fmt::Debug + 'a, + ) -> impl Layer + 'a { Bind { cache: self, input: input, @@ -94,14 +97,15 @@ where } #[derive(Debug)] -struct Bind<'a, T: Drawable> { +struct Bind<'a, T: Drawable, I: Borrow + 'a> { cache: &'a Cache, - input: &'a T, + input: I, } -impl<'a, T> Layer for Bind<'a, T> +impl<'a, T, I> Layer for Bind<'a, T, I> where T: Drawable + std::fmt::Debug, + I: Borrow + std::fmt::Debug + 'a, { fn draw(&self, current_bounds: Size) -> Arc { use std::ops::Deref; @@ -115,7 +119,7 @@ where } let mut frame = Frame::new(current_bounds.width, current_bounds.height); - self.input.draw(&mut frame); + self.input.borrow().draw(&mut frame); let primitive = Arc::new(frame.into_primitive()); -- cgit From bb424e54c5083402225a0fdda6130de575592dca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 18:48:30 +0200 Subject: Add interactivity to `solar_system` example --- wgpu/src/widget/canvas/layer/cache.rs | 50 +++++++++-------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs index e8d62b63..4ecebb48 100644 --- a/wgpu/src/widget/canvas/layer/cache.rs +++ b/wgpu/src/widget/canvas/layer/cache.rs @@ -1,5 +1,5 @@ use crate::{ - canvas::{Drawable, Frame, Layer, Program}, + canvas::{Drawable, Frame, Layer}, Primitive, }; @@ -26,34 +26,17 @@ impl Default for State { /// /// [`Layer`]: ../trait.Layer.html /// [`Cache`]: struct.Cache.html -#[derive(Debug)] -pub struct Cache { - input: PhantomData, +#[derive(Debug, Default)] +pub struct Cache { state: RefCell, } -impl Default for Cache -where - T: Drawable, -{ - fn default() -> Self { - Self { - input: PhantomData, - state: Default::default(), - } - } -} - -impl Cache -where - T: Drawable + std::fmt::Debug, -{ +impl Cache { /// Creates a new empty [`Cache`]. /// /// [`Cache`]: struct.Cache.html pub fn new() -> Self { Cache { - input: PhantomData, state: Default::default(), } } @@ -71,35 +54,26 @@ where /// [`Cache`]: struct.Cache.html /// [`Layer`]: ../trait.Layer.html /// [`Canvas`]: ../../struct.Canvas.html - pub fn with<'a>( + pub fn with<'a, T>( &'a self, input: impl Borrow + std::fmt::Debug + 'a, - ) -> impl Layer + 'a { + ) -> impl Layer + 'a + where + T: Drawable + std::fmt::Debug + 'a, + { Bind { cache: self, input: input, + drawable: PhantomData, } } } -impl Program for Cache -where - T: Drawable + std::fmt::Debug, -{ - type Input = T; - - fn layers<'a>( - &'a self, - input: &'a Self::Input, - ) -> Vec> { - vec![Box::new(self.with(input))] - } -} - #[derive(Debug)] struct Bind<'a, T: Drawable, I: Borrow + 'a> { - cache: &'a Cache, + cache: &'a Cache, input: I, + drawable: PhantomData, } impl<'a, T, I> Layer for Bind<'a, T, I> -- cgit From 592cc685067c36cbba87e4db14f4ebc71d65b951 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 21:55:23 +0200 Subject: Remove `Layer` trait and simplify `Canvas` --- wgpu/src/widget/canvas.rs | 46 ++++++------- wgpu/src/widget/canvas/cache.rs | 110 +++++++++++++++++++++++++++++++ wgpu/src/widget/canvas/drawable.rs | 9 +++ wgpu/src/widget/canvas/geometry.rs | 15 +++++ wgpu/src/widget/canvas/layer.rs | 25 ------- wgpu/src/widget/canvas/layer/cache.rs | 120 ---------------------------------- wgpu/src/widget/canvas/program.rs | 16 ----- wgpu/src/widget/canvas/state.rs | 20 ++++++ 8 files changed, 177 insertions(+), 184 deletions(-) create mode 100644 wgpu/src/widget/canvas/cache.rs create mode 100644 wgpu/src/widget/canvas/geometry.rs delete mode 100644 wgpu/src/widget/canvas/layer.rs delete mode 100644 wgpu/src/widget/canvas/layer/cache.rs delete mode 100644 wgpu/src/widget/canvas/program.rs create mode 100644 wgpu/src/widget/canvas/state.rs (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 326bc7d5..2b485e18 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -14,24 +14,26 @@ use iced_native::{ }; use std::hash::Hash; -pub mod layer; pub mod path; +mod cache; mod drawable; mod event; mod fill; mod frame; -mod program; +mod geometry; +mod state; mod stroke; mod text; +pub use cache::Cache; pub use drawable::Drawable; pub use event::Event; pub use fill::Fill; pub use frame::Frame; -pub use layer::Layer; +pub use geometry::Geometry; pub use path::Path; -pub use program::Program; +pub use state::State; pub use stroke::{LineCap, LineJoin, Stroke}; pub use text::Text; @@ -65,7 +67,7 @@ pub use text::Text; /// # pub use iced_wgpu::canvas; /// # pub use iced_native::Color; /// # } -/// use iced::canvas::{self, layer, Canvas, Drawable, Fill, Frame, Path}; +/// use iced::canvas::{self, Cache, Canvas, Drawable, Fill, Frame, Path}; /// use iced::Color; /// /// // First, we define the data we need for drawing @@ -86,31 +88,29 @@ pub use text::Text; /// } /// /// // We can use a `Cache` to avoid unnecessary re-tessellation -/// let mut cache: layer::Cache = layer::Cache::new(); +/// let cache = Cache::new(); /// /// // Finally, we simply use our `Cache` to create the `Canvas`! -/// let canvas = Canvas::new(&mut cache, &Circle { radius: 50.0 }); +/// let canvas = Canvas::new(cache.with(Circle { radius: 50.0 })); /// ``` #[derive(Debug)] -pub struct Canvas<'a, P: Program> { +pub struct Canvas { width: Length, height: Length, - program: &'a mut P, - input: &'a P::Input, + state: S, } -impl<'a, P: Program> Canvas<'a, P> { +impl Canvas { const DEFAULT_SIZE: u16 = 100; /// Creates a new [`Canvas`] with no layers. /// /// [`Canvas`]: struct.Canvas.html - pub fn new(program: &'a mut P, input: &'a P::Input) -> Self { + pub fn new(state: S) -> Self { Canvas { width: Length::Units(Self::DEFAULT_SIZE), height: Length::Units(Self::DEFAULT_SIZE), - program, - input, + state, } } @@ -131,7 +131,7 @@ impl<'a, P: Program> Canvas<'a, P> { } } -impl<'a, Message, P: Program> Widget for Canvas<'a, P> { +impl Widget for Canvas { fn width(&self) -> Length { self.width } @@ -178,7 +178,7 @@ impl<'a, Message, P: Program> Widget for Canvas<'a, P> { }; if let Some(canvas_event) = canvas_event { - self.program.update(canvas_event, bounds.size(), self.input) + self.state.update(canvas_event, bounds.size()) } } @@ -196,12 +196,12 @@ impl<'a, Message, P: Program> Widget for Canvas<'a, P> { ( Primitive::Group { primitives: self - .program - .layers(self.input) - .iter() - .map(|layer| Primitive::Cached { + .state + .draw(size) + .into_iter() + .map(|geometry| Primitive::Cached { origin, - cache: layer.draw(size), + cache: geometry.into_primitive(), }) .collect(), }, @@ -218,12 +218,12 @@ impl<'a, Message, P: Program> Widget for Canvas<'a, P> { } } -impl<'a, Message, P: Program> From> +impl<'a, Message, S: State + 'a> From> for Element<'a, Message, Renderer> where Message: 'static, { - fn from(canvas: Canvas<'a, P>) -> Element<'a, Message, Renderer> { + fn from(canvas: Canvas) -> Element<'a, Message, Renderer> { Element::new(canvas) } } diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs new file mode 100644 index 00000000..c88239af --- /dev/null +++ b/wgpu/src/widget/canvas/cache.rs @@ -0,0 +1,110 @@ +use crate::{ + canvas::{Drawable, Frame, Geometry}, + Primitive, +}; + +use iced_native::Size; +use std::{cell::RefCell, sync::Arc}; + +enum State { + Empty, + Filled { + bounds: Size, + primitive: Arc, + }, +} + +impl Default for State { + fn default() -> Self { + State::Empty + } +} +/// 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. +/// +/// [`Layer`]: ../trait.Layer.html +/// [`Cache`]: struct.Cache.html +#[derive(Debug, Default)] +pub struct Cache { + state: RefCell, +} + +impl Cache { + /// Creates a new empty [`Cache`]. + /// + /// [`Cache`]: struct.Cache.html + pub fn new() -> Self { + Cache { + state: Default::default(), + } + } + + /// Clears the cache, forcing a redraw the next time it is used. + /// + /// [`Cached`]: struct.Cached.html + pub fn clear(&mut self) { + *self.state.borrow_mut() = State::Empty; + } + + pub fn draw(&self, new_bounds: Size, input: T) -> Geometry + where + T: Drawable + std::fmt::Debug, + { + use std::ops::Deref; + + if let State::Filled { bounds, primitive } = self.state.borrow().deref() + { + if *bounds == new_bounds { + return Geometry::from_primitive(primitive.clone()); + } + } + + let mut frame = Frame::new(new_bounds.width, new_bounds.height); + input.draw(&mut frame); + + let primitive = Arc::new(frame.into_primitive()); + + *self.state.borrow_mut() = State::Filled { + bounds: new_bounds, + primitive: primitive.clone(), + }; + + Geometry::from_primitive(primitive) + } + + pub fn with<'a, T>(&'a self, input: T) -> impl crate::canvas::State + 'a + where + T: Drawable + std::fmt::Debug + 'a, + { + Bind { cache: self, input } + } +} + +struct Bind<'a, T> { + cache: &'a Cache, + input: T, +} + +impl<'a, T> crate::canvas::State for Bind<'a, T> +where + T: Drawable + std::fmt::Debug + 'a, +{ + fn draw(&self, bounds: Size) -> Vec { + vec![self.cache.draw(bounds, &self.input)] + } +} + +impl std::fmt::Debug for State { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + State::Empty => write!(f, "Empty"), + State::Filled { primitive, bounds } => f + .debug_struct("Filled") + .field("primitive", primitive) + .field("bounds", bounds) + .finish(), + } + } +} diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs index 48ba6b4c..32258b71 100644 --- a/wgpu/src/widget/canvas/drawable.rs +++ b/wgpu/src/widget/canvas/drawable.rs @@ -16,3 +16,12 @@ impl<'a> Drawable for dyn Fn(&mut Frame) + 'a { self(frame) } } + +impl Drawable for &T +where + T: Drawable, +{ + fn draw(&self, frame: &mut Frame) { + T::draw(self, frame) + } +} diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs new file mode 100644 index 00000000..db7b4054 --- /dev/null +++ b/wgpu/src/widget/canvas/geometry.rs @@ -0,0 +1,15 @@ +use crate::Primitive; +use std::sync::Arc; + +#[derive(Debug)] +pub struct Geometry(Arc); + +impl Geometry { + pub(crate) fn from_primitive(primitive: Arc) -> Self { + Self(primitive) + } + + pub(crate) fn into_primitive(self) -> Arc { + self.0 + } +} diff --git a/wgpu/src/widget/canvas/layer.rs b/wgpu/src/widget/canvas/layer.rs deleted file mode 100644 index a46b7fb1..00000000 --- a/wgpu/src/widget/canvas/layer.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Produce, store, and reuse geometry. -mod cache; - -pub use cache::Cache; - -use crate::Primitive; -use iced_native::Size; - -use std::sync::Arc; - -/// A layer that can be presented at a [`Canvas`]. -/// -/// [`Canvas`]: ../struct.Canvas.html -pub trait Layer: std::fmt::Debug { - /// Draws the [`Layer`] in the given bounds and produces a [`Primitive`] as - /// a result. - /// - /// The [`Layer`] may choose to store the produced [`Primitive`] locally and - /// only recompute it when the bounds change, its contents change, or is - /// otherwise explicitly cleared by other means. - /// - /// [`Layer`]: trait.Layer.html - /// [`Primitive`]: ../../../enum.Primitive.html - fn draw(&self, bounds: Size) -> Arc; -} diff --git a/wgpu/src/widget/canvas/layer/cache.rs b/wgpu/src/widget/canvas/layer/cache.rs deleted file mode 100644 index 4ecebb48..00000000 --- a/wgpu/src/widget/canvas/layer/cache.rs +++ /dev/null @@ -1,120 +0,0 @@ -use crate::{ - canvas::{Drawable, Frame, Layer}, - Primitive, -}; - -use iced_native::Size; -use std::{borrow::Borrow, cell::RefCell, marker::PhantomData, sync::Arc}; - -enum State { - Empty, - Filled { - bounds: Size, - primitive: Arc, - }, -} - -impl Default for State { - fn default() -> Self { - State::Empty - } -} -/// 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. -/// -/// [`Layer`]: ../trait.Layer.html -/// [`Cache`]: struct.Cache.html -#[derive(Debug, Default)] -pub struct Cache { - state: RefCell, -} - -impl Cache { - /// Creates a new empty [`Cache`]. - /// - /// [`Cache`]: struct.Cache.html - pub fn new() -> Self { - Cache { - state: Default::default(), - } - } - - /// Clears the cache, forcing a redraw the next time it is used. - /// - /// [`Cached`]: struct.Cached.html - pub fn clear(&mut self) { - *self.state.borrow_mut() = State::Empty; - } - - /// Binds the [`Cache`] with some data, producing a [`Layer`] that can be - /// added to a [`Canvas`]. - /// - /// [`Cache`]: struct.Cache.html - /// [`Layer`]: ../trait.Layer.html - /// [`Canvas`]: ../../struct.Canvas.html - pub fn with<'a, T>( - &'a self, - input: impl Borrow + std::fmt::Debug + 'a, - ) -> impl Layer + 'a - where - T: Drawable + std::fmt::Debug + 'a, - { - Bind { - cache: self, - input: input, - drawable: PhantomData, - } - } -} - -#[derive(Debug)] -struct Bind<'a, T: Drawable, I: Borrow + 'a> { - cache: &'a Cache, - input: I, - drawable: PhantomData, -} - -impl<'a, T, I> Layer for Bind<'a, T, I> -where - T: Drawable + std::fmt::Debug, - I: Borrow + std::fmt::Debug + 'a, -{ - fn draw(&self, current_bounds: Size) -> Arc { - use std::ops::Deref; - - if let State::Filled { bounds, primitive } = - self.cache.state.borrow().deref() - { - if *bounds == current_bounds { - return primitive.clone(); - } - } - - let mut frame = Frame::new(current_bounds.width, current_bounds.height); - self.input.borrow().draw(&mut frame); - - let primitive = Arc::new(frame.into_primitive()); - - *self.cache.state.borrow_mut() = State::Filled { - bounds: current_bounds, - primitive: primitive.clone(), - }; - - primitive - } -} - -impl std::fmt::Debug for State { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - State::Empty => write!(f, "Empty"), - State::Filled { primitive, bounds } => f - .debug_struct("Filled") - .field("primitive", primitive) - .field("bounds", bounds) - .finish(), - } - } -} diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs deleted file mode 100644 index c65a078b..00000000 --- a/wgpu/src/widget/canvas/program.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::canvas::{Event, Layer, Size}; - -pub trait Program { - type Input; - - fn layers<'a>(&'a self, input: &'a Self::Input) - -> Vec>; - - fn update<'a>( - &'a mut self, - _event: Event, - _bounds: Size, - _input: &'a Self::Input, - ) { - } -} diff --git a/wgpu/src/widget/canvas/state.rs b/wgpu/src/widget/canvas/state.rs new file mode 100644 index 00000000..8388f94d --- /dev/null +++ b/wgpu/src/widget/canvas/state.rs @@ -0,0 +1,20 @@ +use crate::canvas::{Event, Geometry, Size}; + +pub trait State { + fn update(&mut self, _event: Event, _bounds: Size) {} + + fn draw(&self, bounds: Size) -> Vec; +} + +impl State for &mut T +where + T: State, +{ + fn update(&mut self, event: Event, bounds: Size) { + T::update(self, event, bounds); + } + + fn draw(&self, bounds: Size) -> Vec { + T::draw(self, bounds) + } +} -- cgit From f59832e88e9e6c72cd65d51de6fbf91bddf4a9d3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 19 Apr 2020 21:55:33 +0200 Subject: Fix alignment in triangle pipeline of `iced_wgpu` --- wgpu/src/triangle.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 86c74fcd..99365a4b 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -231,11 +231,9 @@ impl Pipeline { // We upload everything upfront for (origin, mesh) in meshes { - let transform = Uniforms { - transform: (transformation - * Transformation::translate(origin.x, origin.y)) - .into(), - }; + let transform = (transformation + * Transformation::translate(origin.x, origin.y)) + .into(); let vertex_buffer = device.create_buffer_with_data( mesh.vertices.as_bytes(), @@ -361,12 +359,28 @@ impl Pipeline { #[derive(Debug, Clone, Copy, AsBytes)] struct Uniforms { transform: [f32; 16], + // We need to align this to 256 bytes to please `wgpu`... + // TODO: Be smarter and stop wasting memory! + _padding_a: [f32; 32], + _padding_b: [f32; 16], } impl Default for Uniforms { fn default() -> Self { Self { transform: *Transformation::identity().as_ref(), + _padding_a: [0.0; 32], + _padding_b: [0.0; 16], + } + } +} + +impl From for Uniforms { + fn from(transformation: Transformation) -> Uniforms { + Self { + transform: transformation.into(), + _padding_a: [0.0; 32], + _padding_b: [0.0; 16], } } } -- cgit From b0825ce38bb9d496193f40e5d2cc7a4654455396 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 03:14:05 +0200 Subject: Add convenient builder methods to `canvas::Stroke` --- wgpu/src/widget/canvas/stroke.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/stroke.rs b/wgpu/src/widget/canvas/stroke.rs index 46d669c4..e20379cd 100644 --- a/wgpu/src/widget/canvas/stroke.rs +++ b/wgpu/src/widget/canvas/stroke.rs @@ -14,6 +14,24 @@ pub struct Stroke { pub line_join: LineJoin, } +impl Stroke { + pub fn with_color(self, color: Color) -> Stroke { + Stroke { color, ..self } + } + + pub fn with_width(self, width: f32) -> Stroke { + Stroke { width, ..self } + } + + pub fn with_line_cap(self, line_cap: LineCap) -> Stroke { + Stroke { line_cap, ..self } + } + + pub fn with_line_join(self, line_join: LineJoin) -> Stroke { + Stroke { line_join, ..self } + } +} + impl Default for Stroke { fn default() -> Stroke { Stroke { -- cgit From 2381a9310c56f60698653f5fd13f5a0d80fa4f67 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 03:16:18 +0200 Subject: Ask for a `Size` in `Frame::new` --- wgpu/src/widget/canvas/cache.rs | 2 +- wgpu/src/widget/canvas/frame.rs | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs index c88239af..310bc1d3 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/wgpu/src/widget/canvas/cache.rs @@ -61,7 +61,7 @@ impl Cache { } } - let mut frame = Frame::new(new_bounds.width, new_bounds.height); + let mut frame = Frame::new(new_bounds); input.draw(&mut frame); let primitive = Arc::new(frame.into_primitive()); diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index de4717f1..a951a029 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -10,8 +10,7 @@ use crate::{ /// [`Canvas`]: struct.Canvas.html #[derive(Debug)] pub struct Frame { - width: f32, - height: f32, + size: Size, buffers: lyon::tessellation::VertexBuffers, primitives: Vec, transforms: Transforms, @@ -36,10 +35,9 @@ impl Frame { /// top-left corner of its bounds. /// /// [`Frame`]: struct.Frame.html - pub fn new(width: f32, height: f32) -> Frame { + pub fn new(size: Size) -> Frame { Frame { - width, - height, + size, buffers: lyon::tessellation::VertexBuffers::new(), primitives: Vec::new(), transforms: Transforms { @@ -57,7 +55,7 @@ impl Frame { /// [`Frame`]: struct.Frame.html #[inline] pub fn width(&self) -> f32 { - self.width + self.size.width } /// Returns the width of the [`Frame`]. @@ -65,7 +63,7 @@ impl Frame { /// [`Frame`]: struct.Frame.html #[inline] pub fn height(&self) -> f32 { - self.height + self.size.height } /// Returns the dimensions of the [`Frame`]. @@ -73,7 +71,7 @@ impl Frame { /// [`Frame`]: struct.Frame.html #[inline] pub fn size(&self) -> Size { - Size::new(self.width, self.height) + self.size } /// Returns the coordinate of the center of the [`Frame`]. @@ -81,7 +79,7 @@ impl Frame { /// [`Frame`]: struct.Frame.html #[inline] pub fn center(&self) -> Point { - Point::new(self.width / 2.0, self.height / 2.0) + Point::new(self.size.width / 2.0, self.size.height / 2.0) } /// Draws the given [`Path`] on the [`Frame`] by filling it with the -- cgit From 59b1e90661ee9e479f404bae71029db824cc7b46 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 03:18:31 +0200 Subject: Introduce `Translate` primitive in `iced_wgpu` --- wgpu/src/primitive.rs | 16 +++++++++------- wgpu/src/renderer.rs | 20 +++++++++++++------- wgpu/src/renderer/widget/pane_grid.rs | 6 +++--- wgpu/src/triangle.rs | 4 ++-- wgpu/src/widget/canvas.rs | 24 ++++++++++++------------ wgpu/src/widget/canvas/cache.rs | 12 +++++++++--- wgpu/src/widget/canvas/frame.rs | 12 ++++++------ wgpu/src/widget/canvas/geometry.rs | 15 ++++++++++----- 8 files changed, 64 insertions(+), 45 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index 46d9e624..e9c0bf46 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,5 +1,5 @@ use iced_native::{ - image, svg, Background, Color, Font, HorizontalAlignment, Point, Rectangle, + image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Vector, VerticalAlignment, }; @@ -70,13 +70,18 @@ pub enum Primitive { /// The content of the clip content: Box, }, + /// A primitive that applies a translation + Translate { + /// The top-left coordinate of the mesh + translation: Vector, + + /// The primitive to translate + content: Box, + }, /// A low-level primitive to render a mesh of triangles. /// /// It can be used to render many kinds of geometry freely. Mesh2D { - /// The top-left coordinate of the mesh - origin: Point, - /// The vertex and index buffers of the mesh buffers: triangle::Mesh2D, }, @@ -85,9 +90,6 @@ pub enum Primitive { /// This can be useful if you are implementing a widget where primitive /// generation is expensive. Cached { - /// The origin of the coordinate system of the cached primitives - origin: Point, - /// The cached primitive cache: Arc, }, diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index 481b310c..e93532bc 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -29,7 +29,7 @@ pub struct Renderer { struct Layer<'a> { bounds: Rectangle, quads: Vec, - meshes: Vec<(Point, &'a triangle::Mesh2D)>, + meshes: Vec<(Vector, &'a triangle::Mesh2D)>, text: Vec>, #[cfg(any(feature = "image", feature = "svg"))] @@ -214,10 +214,10 @@ impl Renderer { border_color: border_color.into_linear(), }); } - Primitive::Mesh2D { origin, buffers } => { + Primitive::Mesh2D { buffers } => { let layer = layers.last_mut().unwrap(); - layer.meshes.push((*origin + translation, buffers)); + layer.meshes.push((translation, buffers)); } Primitive::Clip { bounds, @@ -249,15 +249,21 @@ impl Renderer { layers.push(new_layer); } } - - Primitive::Cached { origin, cache } => { + Primitive::Translate { + translation: new_translation, + content, + } => { self.draw_primitive( - translation + Vector::new(origin.x, origin.y), - &cache, + translation + *new_translation, + &content, layers, ); } + Primitive::Cached { cache } => { + self.draw_primitive(translation, &cache, layers); + } + #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { let layer = layers.last_mut().unwrap(); diff --git a/wgpu/src/renderer/widget/pane_grid.rs b/wgpu/src/renderer/widget/pane_grid.rs index 2d201fec..11ba6347 100644 --- a/wgpu/src/renderer/widget/pane_grid.rs +++ b/wgpu/src/renderer/widget/pane_grid.rs @@ -59,12 +59,12 @@ impl pane_grid::Renderer for Renderer { height: bounds.height + 0.5, }, offset: Vector::new(0, 0), - content: Box::new(Primitive::Cached { - origin: Point::new( + content: Box::new(Primitive::Translate { + translation: Vector::new( cursor_position.x - bounds.x - bounds.width / 2.0, cursor_position.y - bounds.y - bounds.height / 2.0, ), - cache: std::sync::Arc::new(pane), + content: Box::new(pane), }), }; diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 99365a4b..b58cc03c 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -1,6 +1,6 @@ //! Draw meshes of triangles. use crate::{settings, Transformation}; -use iced_native::{Point, Rectangle}; +use iced_native::{Rectangle, Vector}; use std::mem; use zerocopy::AsBytes; @@ -201,7 +201,7 @@ impl Pipeline { target_width: u32, target_height: u32, transformation: Transformation, - meshes: &[(Point, &Mesh2D)], + meshes: &[(Vector, &Mesh2D)], bounds: Rectangle, ) { // This looks a bit crazy, but we are just counting how many vertices diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 2b485e18..744d901e 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -10,7 +10,7 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ input::mouse, layout, Clipboard, Element, Hasher, Layout, Length, - MouseCursor, Point, Size, Widget, + MouseCursor, Point, Size, Vector, Widget, }; use std::hash::Hash; @@ -190,20 +190,20 @@ impl Widget for Canvas { _cursor_position: Point, ) -> (Primitive, MouseCursor) { let bounds = layout.bounds(); - let origin = Point::new(bounds.x, bounds.y); + let translation = Vector::new(bounds.x, bounds.y); let size = Size::new(bounds.width, bounds.height); ( - Primitive::Group { - primitives: self - .state - .draw(size) - .into_iter() - .map(|geometry| Primitive::Cached { - origin, - cache: geometry.into_primitive(), - }) - .collect(), + Primitive::Translate { + translation, + content: Box::new(Primitive::Group { + primitives: self + .state + .draw(size) + .into_iter() + .map(Geometry::into_primitive) + .collect(), + }), }, MouseCursor::Idle, ) diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs index 310bc1d3..12cc6442 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/wgpu/src/widget/canvas/cache.rs @@ -57,21 +57,27 @@ impl Cache { if let State::Filled { bounds, primitive } = self.state.borrow().deref() { if *bounds == new_bounds { - return Geometry::from_primitive(primitive.clone()); + return Geometry::from_primitive(Primitive::Cached { + cache: primitive.clone(), + }); } } let mut frame = Frame::new(new_bounds); input.draw(&mut frame); - let primitive = Arc::new(frame.into_primitive()); + let primitive = { + let geometry = frame.into_geometry(); + + Arc::new(geometry.into_primitive()) + }; *self.state.borrow_mut() = State::Filled { bounds: new_bounds, primitive: primitive.clone(), }; - Geometry::from_primitive(primitive) + Geometry::from_primitive(Primitive::Cached { cache: primitive }) } pub fn with<'a, T>(&'a self, input: T) -> impl crate::canvas::State + 'a diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index a951a029..8623ce4d 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -1,7 +1,7 @@ use iced_native::{Point, Rectangle, Size, Vector}; use crate::{ - canvas::{Fill, Path, Stroke, Text}, + canvas::{Fill, Geometry, Path, Stroke, Text}, triangle, Primitive, }; @@ -260,13 +260,13 @@ impl Frame { self.transforms.current.is_identity = false; } - /// Produces the primitive representing everything drawn on the [`Frame`]. + /// Produces the [`Geometry`] representing everything drawn on the [`Frame`]. /// /// [`Frame`]: struct.Frame.html - pub fn into_primitive(mut self) -> Primitive { + /// [`Geometry`]: struct.Geometry.html + pub fn into_geometry(mut self) -> Geometry { if !self.buffers.indices.is_empty() { self.primitives.push(Primitive::Mesh2D { - origin: Point::ORIGIN, buffers: triangle::Mesh2D { vertices: self.buffers.vertices, indices: self.buffers.indices, @@ -274,9 +274,9 @@ impl Frame { }); } - Primitive::Group { + Geometry::from_primitive(Primitive::Group { primitives: self.primitives, - } + }) } } diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs index db7b4054..12ef828f 100644 --- a/wgpu/src/widget/canvas/geometry.rs +++ b/wgpu/src/widget/canvas/geometry.rs @@ -1,15 +1,20 @@ use crate::Primitive; -use std::sync::Arc; -#[derive(Debug)] -pub struct Geometry(Arc); +#[derive(Debug, Clone)] +pub struct Geometry(Primitive); impl Geometry { - pub(crate) fn from_primitive(primitive: Arc) -> Self { + pub(crate) fn from_primitive(primitive: Primitive) -> Self { Self(primitive) } - pub(crate) fn into_primitive(self) -> Arc { + pub fn into_primitive(self) -> Primitive { self.0 } } + +impl From for Primitive { + fn from(geometry: Geometry) -> Primitive { + geometry.0 + } +} -- cgit From 2ca73036ab5946b451fd2b184541ae4dc6eedb24 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 03:19:29 +0200 Subject: Implement `Drawable` for slices of drawables --- wgpu/src/widget/canvas/drawable.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs index 32258b71..5209fa6f 100644 --- a/wgpu/src/widget/canvas/drawable.rs +++ b/wgpu/src/widget/canvas/drawable.rs @@ -25,3 +25,12 @@ where T::draw(self, frame) } } + +impl Drawable for &[T] +where + T: Drawable, +{ + fn draw(&self, frame: &mut Frame) { + self.iter().for_each(|drawable| drawable.draw(frame)); + } +} -- cgit From e4eb0553de13053c9828fd5454c281e27e598d65 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 03:46:03 +0200 Subject: Allow `canvas::State` to produce messages --- wgpu/src/widget/canvas.rs | 25 +++++++++++++++++-------- wgpu/src/widget/canvas/cache.rs | 7 +++++-- wgpu/src/widget/canvas/state.rs | 14 ++++++++------ 3 files changed, 30 insertions(+), 16 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 744d901e..044bc3ec 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -13,6 +13,7 @@ use iced_native::{ MouseCursor, Point, Size, Vector, Widget, }; use std::hash::Hash; +use std::marker::PhantomData; pub mod path; @@ -91,16 +92,17 @@ pub use text::Text; /// let cache = Cache::new(); /// /// // Finally, we simply use our `Cache` to create the `Canvas`! -/// let canvas = Canvas::new(cache.with(Circle { radius: 50.0 })); +/// let canvas: Canvas<_, ()> = Canvas::new(cache.with(Circle { radius: 50.0 })); /// ``` #[derive(Debug)] -pub struct Canvas { +pub struct Canvas, Message> { width: Length, height: Length, state: S, + phantom: PhantomData, } -impl Canvas { +impl> Canvas { const DEFAULT_SIZE: u16 = 100; /// Creates a new [`Canvas`] with no layers. @@ -111,6 +113,7 @@ impl Canvas { width: Length::Units(Self::DEFAULT_SIZE), height: Length::Units(Self::DEFAULT_SIZE), state, + phantom: PhantomData, } } @@ -131,7 +134,9 @@ impl Canvas { } } -impl Widget for Canvas { +impl> Widget + for Canvas +{ fn width(&self) -> Length { self.width } @@ -156,7 +161,7 @@ impl Widget for Canvas { event: iced_native::Event, layout: Layout<'_>, cursor_position: Point, - _messages: &mut Vec, + messages: &mut Vec, _renderer: &Renderer, _clipboard: Option<&dyn Clipboard>, ) { @@ -178,7 +183,11 @@ impl Widget for Canvas { }; if let Some(canvas_event) = canvas_event { - self.state.update(canvas_event, bounds.size()) + if let Some(message) = + self.state.update(canvas_event, bounds.size()) + { + messages.push(message); + } } } @@ -218,12 +227,12 @@ impl Widget for Canvas { } } -impl<'a, Message, S: State + 'a> From> +impl<'a, Message, S: State + 'a> From> for Element<'a, Message, Renderer> where Message: 'static, { - fn from(canvas: Canvas) -> Element<'a, Message, Renderer> { + fn from(canvas: Canvas) -> Element<'a, Message, Renderer> { Element::new(canvas) } } diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs index 12cc6442..2beed0f7 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/wgpu/src/widget/canvas/cache.rs @@ -80,7 +80,10 @@ impl Cache { Geometry::from_primitive(Primitive::Cached { cache: primitive }) } - pub fn with<'a, T>(&'a self, input: T) -> impl crate::canvas::State + 'a + pub fn with<'a, T, Message>( + &'a self, + input: T, + ) -> impl crate::canvas::State + 'a where T: Drawable + std::fmt::Debug + 'a, { @@ -93,7 +96,7 @@ struct Bind<'a, T> { input: T, } -impl<'a, T> crate::canvas::State for Bind<'a, T> +impl<'a, T, Message> crate::canvas::State for Bind<'a, T> where T: Drawable + std::fmt::Debug + 'a, { diff --git a/wgpu/src/widget/canvas/state.rs b/wgpu/src/widget/canvas/state.rs index 8388f94d..ab433dd1 100644 --- a/wgpu/src/widget/canvas/state.rs +++ b/wgpu/src/widget/canvas/state.rs @@ -1,17 +1,19 @@ use crate::canvas::{Event, Geometry, Size}; -pub trait State { - fn update(&mut self, _event: Event, _bounds: Size) {} +pub trait State { + fn update(&mut self, _event: Event, _bounds: Size) -> Option { + None + } fn draw(&self, bounds: Size) -> Vec; } -impl State for &mut T +impl State for &mut T where - T: State, + T: State, { - fn update(&mut self, event: Event, bounds: Size) { - T::update(self, event, bounds); + fn update(&mut self, event: Event, bounds: Size) -> Option { + T::update(self, event, bounds) } fn draw(&self, bounds: Size) -> Vec { -- cgit From e65585ae17bf2fae1bbad1cde839d6f767a29b82 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 04:41:09 +0200 Subject: Clip and cull `Mesh2D` primitives in `iced_wgpu` --- wgpu/src/primitive.rs | 9 +++++++-- wgpu/src/renderer.rs | 36 +++++++++++++++++++++++------------- wgpu/src/triangle.rs | 23 +++++++++++++---------- wgpu/src/widget/canvas/frame.rs | 1 + 4 files changed, 44 insertions(+), 25 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index e9c0bf46..e73227ef 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -1,5 +1,5 @@ use iced_native::{ - image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, + image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Size, Vector, VerticalAlignment, }; @@ -72,7 +72,7 @@ pub enum Primitive { }, /// A primitive that applies a translation Translate { - /// The top-left coordinate of the mesh + /// The translation vector translation: Vector, /// The primitive to translate @@ -82,6 +82,11 @@ pub enum Primitive { /// /// It can be used to render many kinds of geometry freely. Mesh2D { + /// The size of the drawable region of the mesh. + /// + /// Any geometry that falls out of this region will be clipped. + size: Size, + /// The vertex and index buffers of the mesh buffers: triangle::Mesh2D, }, diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index e93532bc..5c38ce61 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -29,7 +29,7 @@ pub struct Renderer { struct Layer<'a> { bounds: Rectangle, quads: Vec, - meshes: Vec<(Vector, &'a triangle::Mesh2D)>, + meshes: Vec<(Vector, Rectangle, &'a triangle::Mesh2D)>, text: Vec>, #[cfg(any(feature = "image", feature = "svg"))] @@ -48,6 +48,12 @@ impl<'a> Layer<'a> { images: Vec::new(), } } + + pub fn intersection(&self, rectangle: Rectangle) -> Option> { + let layer_bounds: Rectangle = self.bounds.into(); + + layer_bounds.intersection(&rectangle).map(Into::into) + } } impl Renderer { @@ -214,10 +220,20 @@ impl Renderer { border_color: border_color.into_linear(), }); } - Primitive::Mesh2D { buffers } => { + Primitive::Mesh2D { size, buffers } => { let layer = layers.last_mut().unwrap(); - layer.meshes.push((translation, buffers)); + // Only draw visible content + if let Some(clip_bounds) = layer.intersection(Rectangle::new( + Point::new(translation.x, translation.y), + *size, + )) { + layer.meshes.push(( + translation, + clip_bounds.into(), + buffers, + )); + } } Primitive::Clip { bounds, @@ -226,16 +242,10 @@ impl Renderer { } => { let layer = layers.last_mut().unwrap(); - let layer_bounds: Rectangle = layer.bounds.into(); - - let clip = Rectangle { - x: bounds.x + translation.x, - y: bounds.y + translation.y, - ..*bounds - }; - // Only draw visible content - if let Some(clip_bounds) = layer_bounds.intersection(&clip) { + if let Some(clip_bounds) = + layer.intersection(*bounds + translation) + { let clip_layer = Layer::new(clip_bounds.into()); let new_layer = Layer::new(layer.bounds); @@ -356,8 +366,8 @@ impl Renderer { target_width, target_height, scaled, + scale_factor, &layer.meshes, - bounds, ); } diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index b58cc03c..246dc7ce 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -201,15 +201,15 @@ impl Pipeline { target_width: u32, target_height: u32, transformation: Transformation, - meshes: &[(Vector, &Mesh2D)], - bounds: Rectangle, + scale_factor: f32, + meshes: &[(Vector, Rectangle, &Mesh2D)], ) { // This looks a bit crazy, but we are just counting how many vertices // and indices we will need to handle. // TODO: Improve readability let (total_vertices, total_indices) = meshes .iter() - .map(|(_, mesh)| (mesh.vertices.len(), mesh.indices.len())) + .map(|(_, _, mesh)| (mesh.vertices.len(), mesh.indices.len())) .fold((0, 0), |(total_v, total_i), (v, i)| { (total_v + v, total_i + i) }); @@ -230,7 +230,7 @@ impl Pipeline { let mut last_index = 0; // We upload everything upfront - for (origin, mesh) in meshes { + for (origin, _, mesh) in meshes { let transform = (transformation * Transformation::translate(origin.x, origin.y)) .into(); @@ -316,16 +316,19 @@ impl Pipeline { }); render_pass.set_pipeline(&self.pipeline); - render_pass.set_scissor_rect( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ); for (i, (vertex_offset, index_offset, indices)) in offsets.into_iter().enumerate() { + let bounds = meshes[i].1 * scale_factor; + + render_pass.set_scissor_rect( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ); + render_pass.set_bind_group( 0, &self.constants, diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 8623ce4d..1c4a038a 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -267,6 +267,7 @@ impl Frame { pub fn into_geometry(mut self) -> Geometry { if !self.buffers.indices.is_empty() { self.primitives.push(Primitive::Mesh2D { + size: self.size, buffers: triangle::Mesh2D { vertices: self.buffers.vertices, indices: self.buffers.indices, -- cgit From 2539042b71d70afd4d8f262783d441e768811ee9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 28 Apr 2020 06:24:12 +0200 Subject: Remove `Drawable` and rename `State` to `Program` --- wgpu/src/widget/canvas.rs | 58 ++++++++++++++++++-------------------- wgpu/src/widget/canvas/cache.rs | 37 +++++------------------- wgpu/src/widget/canvas/drawable.rs | 36 ----------------------- wgpu/src/widget/canvas/program.rs | 22 +++++++++++++++ wgpu/src/widget/canvas/state.rs | 22 --------------- 5 files changed, 56 insertions(+), 119 deletions(-) delete mode 100644 wgpu/src/widget/canvas/drawable.rs create mode 100644 wgpu/src/widget/canvas/program.rs delete mode 100644 wgpu/src/widget/canvas/state.rs (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 044bc3ec..c0506cf7 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -18,34 +18,27 @@ use std::marker::PhantomData; pub mod path; mod cache; -mod drawable; mod event; mod fill; mod frame; mod geometry; -mod state; +mod program; mod stroke; mod text; pub use cache::Cache; -pub use drawable::Drawable; pub use event::Event; pub use fill::Fill; pub use frame::Frame; pub use geometry::Geometry; pub use path::Path; -pub use state::State; +pub use program::Program; pub use stroke::{LineCap, LineJoin, Stroke}; pub use text::Text; /// A widget capable of drawing 2D graphics. /// -/// A [`Canvas`] may contain multiple layers. A [`Layer`] is drawn using the -/// painter's algorithm. In other words, layers will be drawn on top of each -/// other in the same order they are pushed into the [`Canvas`]. -/// /// [`Canvas`]: struct.Canvas.html -/// [`Layer`]: layer/trait.Layer.html /// /// # Examples /// The repository has a couple of [examples] showcasing how to use a @@ -66,10 +59,10 @@ pub use text::Text; /// ```no_run /// # mod iced { /// # pub use iced_wgpu::canvas; -/// # pub use iced_native::Color; +/// # pub use iced_native::{Color, Size}; /// # } -/// use iced::canvas::{self, Cache, Canvas, Drawable, Fill, Frame, Path}; -/// use iced::Color; +/// use iced::canvas::{self, Cache, Canvas, Fill, Frame, Geometry, Path, Program}; +/// use iced::{Color, Size}; /// /// // First, we define the data we need for drawing /// #[derive(Debug)] @@ -77,42 +70,45 @@ pub use text::Text; /// radius: f32, /// } /// -/// // Then, we implement the `Drawable` trait -/// impl Drawable for Circle { -/// fn draw(&self, frame: &mut Frame) { +/// // Then, we implement the `Program` trait +/// impl Program<()> for Circle { +/// fn draw(&self, bounds: Size) -> Vec{ +/// // We prepare a new `Frame` +/// let mut frame = Frame::new(bounds); +/// /// // We create a `Path` representing a simple circle /// let circle = Path::circle(frame.center(), self.radius); /// /// // And fill it with some color /// frame.fill(&circle, Fill::Color(Color::BLACK)); +/// +/// // Finally, we produce the geometry +/// vec![frame.into_geometry()] /// } /// } /// -/// // We can use a `Cache` to avoid unnecessary re-tessellation -/// let cache = Cache::new(); -/// /// // Finally, we simply use our `Cache` to create the `Canvas`! -/// let canvas: Canvas<_, ()> = Canvas::new(cache.with(Circle { radius: 50.0 })); +/// let canvas = Canvas::new(Circle { radius: 50.0 }); /// ``` #[derive(Debug)] -pub struct Canvas, Message> { +pub struct Canvas> { width: Length, height: Length, - state: S, + program: P, phantom: PhantomData, } -impl> Canvas { +impl> Canvas { const DEFAULT_SIZE: u16 = 100; - /// Creates a new [`Canvas`] with no layers. + /// Creates a new [`Canvas`]. /// /// [`Canvas`]: struct.Canvas.html - pub fn new(state: S) -> Self { + pub fn new(program: P) -> Self { Canvas { width: Length::Units(Self::DEFAULT_SIZE), height: Length::Units(Self::DEFAULT_SIZE), - state, + program, phantom: PhantomData, } } @@ -134,8 +130,8 @@ impl> Canvas { } } -impl> Widget - for Canvas +impl> Widget + for Canvas { fn width(&self) -> Length { self.width @@ -184,7 +180,7 @@ impl> Widget if let Some(canvas_event) = canvas_event { if let Some(message) = - self.state.update(canvas_event, bounds.size()) + self.program.update(canvas_event, bounds.size()) { messages.push(message); } @@ -207,7 +203,7 @@ impl> Widget translation, content: Box::new(Primitive::Group { primitives: self - .state + .program .draw(size) .into_iter() .map(Geometry::into_primitive) @@ -227,12 +223,12 @@ impl> Widget } } -impl<'a, Message, S: State + 'a> From> +impl<'a, Message, P: Program + 'a> From> for Element<'a, Message, Renderer> where Message: 'static, { - fn from(canvas: Canvas) -> Element<'a, Message, Renderer> { + fn from(canvas: Canvas) -> Element<'a, Message, Renderer> { Element::new(canvas) } } diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs index 2beed0f7..03643f74 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/wgpu/src/widget/canvas/cache.rs @@ -1,5 +1,5 @@ use crate::{ - canvas::{Drawable, Frame, Geometry}, + canvas::{Frame, Geometry}, Primitive, }; @@ -48,10 +48,11 @@ impl Cache { *self.state.borrow_mut() = State::Empty; } - pub fn draw(&self, new_bounds: Size, input: T) -> Geometry - where - T: Drawable + std::fmt::Debug, - { + pub fn draw( + &self, + new_bounds: Size, + draw_fn: impl Fn(&mut Frame), + ) -> Geometry { use std::ops::Deref; if let State::Filled { bounds, primitive } = self.state.borrow().deref() @@ -64,7 +65,7 @@ impl Cache { } let mut frame = Frame::new(new_bounds); - input.draw(&mut frame); + draw_fn(&mut frame); let primitive = { let geometry = frame.into_geometry(); @@ -79,30 +80,6 @@ impl Cache { Geometry::from_primitive(Primitive::Cached { cache: primitive }) } - - pub fn with<'a, T, Message>( - &'a self, - input: T, - ) -> impl crate::canvas::State + 'a - where - T: Drawable + std::fmt::Debug + 'a, - { - Bind { cache: self, input } - } -} - -struct Bind<'a, T> { - cache: &'a Cache, - input: T, -} - -impl<'a, T, Message> crate::canvas::State for Bind<'a, T> -where - T: Drawable + std::fmt::Debug + 'a, -{ - fn draw(&self, bounds: Size) -> Vec { - vec![self.cache.draw(bounds, &self.input)] - } } impl std::fmt::Debug for State { diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs deleted file mode 100644 index 5209fa6f..00000000 --- a/wgpu/src/widget/canvas/drawable.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::canvas::Frame; - -/// A type that can be drawn on a [`Frame`]. -/// -/// [`Frame`]: struct.Frame.html -pub trait Drawable { - /// Draws the [`Drawable`] on the given [`Frame`]. - /// - /// [`Drawable`]: trait.Drawable.html - /// [`Frame`]: struct.Frame.html - fn draw(&self, frame: &mut Frame); -} - -impl<'a> Drawable for dyn Fn(&mut Frame) + 'a { - fn draw(&self, frame: &mut Frame) { - self(frame) - } -} - -impl Drawable for &T -where - T: Drawable, -{ - fn draw(&self, frame: &mut Frame) { - T::draw(self, frame) - } -} - -impl Drawable for &[T] -where - T: Drawable, -{ - fn draw(&self, frame: &mut Frame) { - self.iter().for_each(|drawable| drawable.draw(frame)); - } -} diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs new file mode 100644 index 00000000..8e35fdfb --- /dev/null +++ b/wgpu/src/widget/canvas/program.rs @@ -0,0 +1,22 @@ +use crate::canvas::{Event, Geometry, Size}; + +pub trait Program { + fn update(&mut self, _event: Event, _bounds: Size) -> Option { + None + } + + fn draw(&self, bounds: Size) -> Vec; +} + +impl Program for &mut T +where + T: Program, +{ + fn update(&mut self, event: Event, bounds: Size) -> Option { + T::update(self, event, bounds) + } + + fn draw(&self, bounds: Size) -> Vec { + T::draw(self, bounds) + } +} diff --git a/wgpu/src/widget/canvas/state.rs b/wgpu/src/widget/canvas/state.rs deleted file mode 100644 index ab433dd1..00000000 --- a/wgpu/src/widget/canvas/state.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::canvas::{Event, Geometry, Size}; - -pub trait State { - fn update(&mut self, _event: Event, _bounds: Size) -> Option { - None - } - - fn draw(&self, bounds: Size) -> Vec; -} - -impl State for &mut T -where - T: State, -{ - fn update(&mut self, event: Event, bounds: Size) -> Option { - T::update(self, event, bounds) - } - - fn draw(&self, bounds: Size) -> Vec { - T::draw(self, bounds) - } -} -- cgit From 59403b6ca80081fa419fbef76c92397db68f1ab1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 29 Apr 2020 03:11:15 +0200 Subject: Remove `OutOfBounds` variant from `MouseCursor` --- wgpu/src/renderer/widget/button.rs | 2 +- wgpu/src/renderer/widget/checkbox.rs | 2 +- wgpu/src/renderer/widget/column.rs | 2 +- wgpu/src/renderer/widget/image.rs | 2 +- wgpu/src/renderer/widget/pane_grid.rs | 2 +- wgpu/src/renderer/widget/progress_bar.rs | 2 +- wgpu/src/renderer/widget/radio.rs | 2 +- wgpu/src/renderer/widget/row.rs | 2 +- wgpu/src/renderer/widget/slider.rs | 2 +- wgpu/src/renderer/widget/space.rs | 2 +- wgpu/src/renderer/widget/svg.rs | 2 +- wgpu/src/renderer/widget/text.rs | 2 +- wgpu/src/renderer/widget/text_input.rs | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index 359b4866..5e55873a 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -86,7 +86,7 @@ impl iced_native::button::Renderer for Renderer { if is_mouse_over { MouseCursor::Pointer } else { - MouseCursor::OutOfBounds + MouseCursor::default() }, ) } diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs index c0f1bf21..7f7f6de3 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/wgpu/src/renderer/widget/checkbox.rs @@ -56,7 +56,7 @@ impl checkbox::Renderer for Renderer { if is_mouse_over { MouseCursor::Pointer } else { - MouseCursor::OutOfBounds + MouseCursor::default() }, ) } diff --git a/wgpu/src/renderer/widget/column.rs b/wgpu/src/renderer/widget/column.rs index 95a7463a..e6a9d8f0 100644 --- a/wgpu/src/renderer/widget/column.rs +++ b/wgpu/src/renderer/widget/column.rs @@ -9,7 +9,7 @@ impl column::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - let mut mouse_cursor = MouseCursor::OutOfBounds; + let mut mouse_cursor = MouseCursor::default(); ( Primitive::Group { diff --git a/wgpu/src/renderer/widget/image.rs b/wgpu/src/renderer/widget/image.rs index 70dc5d97..6b7f1c60 100644 --- a/wgpu/src/renderer/widget/image.rs +++ b/wgpu/src/renderer/widget/image.rs @@ -16,7 +16,7 @@ impl image::Renderer for Renderer { handle, bounds: layout.bounds(), }, - MouseCursor::OutOfBounds, + MouseCursor::default(), ) } } diff --git a/wgpu/src/renderer/widget/pane_grid.rs b/wgpu/src/renderer/widget/pane_grid.rs index 11ba6347..80e2471f 100644 --- a/wgpu/src/renderer/widget/pane_grid.rs +++ b/wgpu/src/renderer/widget/pane_grid.rs @@ -22,7 +22,7 @@ impl pane_grid::Renderer for Renderer { cursor_position }; - let mut mouse_cursor = MouseCursor::OutOfBounds; + let mut mouse_cursor = MouseCursor::default(); let mut dragged_pane = None; let mut panes: Vec<_> = content diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs index 34e33276..fe032fbf 100644 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -48,7 +48,7 @@ impl progress_bar::Renderer for Renderer { } else { background }, - MouseCursor::OutOfBounds, + MouseCursor::default(), ) } } diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs index 564f066b..551700c8 100644 --- a/wgpu/src/renderer/widget/radio.rs +++ b/wgpu/src/renderer/widget/radio.rs @@ -57,7 +57,7 @@ impl radio::Renderer for Renderer { if is_mouse_over { MouseCursor::Pointer } else { - MouseCursor::OutOfBounds + MouseCursor::default() }, ) } diff --git a/wgpu/src/renderer/widget/row.rs b/wgpu/src/renderer/widget/row.rs index bd9f1a04..c6a10c07 100644 --- a/wgpu/src/renderer/widget/row.rs +++ b/wgpu/src/renderer/widget/row.rs @@ -9,7 +9,7 @@ impl row::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - let mut mouse_cursor = MouseCursor::OutOfBounds; + let mut mouse_cursor = MouseCursor::default(); ( Primitive::Group { diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs index c8ebd0da..335e1b92 100644 --- a/wgpu/src/renderer/widget/slider.rs +++ b/wgpu/src/renderer/widget/slider.rs @@ -99,7 +99,7 @@ impl slider::Renderer for Renderer { } else if is_mouse_over { MouseCursor::Grab } else { - MouseCursor::OutOfBounds + MouseCursor::default() }, ) } diff --git a/wgpu/src/renderer/widget/space.rs b/wgpu/src/renderer/widget/space.rs index 28e05437..9ec0ed6d 100644 --- a/wgpu/src/renderer/widget/space.rs +++ b/wgpu/src/renderer/widget/space.rs @@ -3,6 +3,6 @@ use iced_native::{space, MouseCursor, Rectangle}; impl space::Renderer for Renderer { fn draw(&mut self, _bounds: Rectangle) -> Self::Output { - (Primitive::None, MouseCursor::OutOfBounds) + (Primitive::None, MouseCursor::default()) } } diff --git a/wgpu/src/renderer/widget/svg.rs b/wgpu/src/renderer/widget/svg.rs index 67bc3fe1..4ee983ea 100644 --- a/wgpu/src/renderer/widget/svg.rs +++ b/wgpu/src/renderer/widget/svg.rs @@ -16,7 +16,7 @@ impl svg::Renderer for Renderer { handle, bounds: layout.bounds(), }, - MouseCursor::OutOfBounds, + MouseCursor::default(), ) } } diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs index 80bff574..3cf32426 100644 --- a/wgpu/src/renderer/widget/text.rs +++ b/wgpu/src/renderer/widget/text.rs @@ -53,7 +53,7 @@ impl text::Renderer for Renderer { horizontal_alignment, vertical_alignment, }, - MouseCursor::OutOfBounds, + MouseCursor::default(), ) } } diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs index 6f72db68..97eb0114 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/wgpu/src/renderer/widget/text_input.rs @@ -234,7 +234,7 @@ impl text_input::Renderer for Renderer { if is_mouse_over { MouseCursor::Text } else { - MouseCursor::OutOfBounds + MouseCursor::default() }, ) } -- cgit From 52719c7076cafb7b01967edf4df11ea72ae45aff Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 29 Apr 2020 03:16:03 +0200 Subject: Let a `canvas::Program` control the mouse cursor --- wgpu/src/widget/canvas.rs | 2 +- wgpu/src/widget/canvas/program.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index c0506cf7..0006ca8d 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -210,7 +210,7 @@ impl> Widget .collect(), }), }, - MouseCursor::Idle, + self.program.mouse_cursor(size), ) } diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs index 8e35fdfb..9e4aca89 100644 --- a/wgpu/src/widget/canvas/program.rs +++ b/wgpu/src/widget/canvas/program.rs @@ -1,4 +1,5 @@ use crate::canvas::{Event, Geometry, Size}; +use iced_native::MouseCursor; pub trait Program { fn update(&mut self, _event: Event, _bounds: Size) -> Option { @@ -6,6 +7,10 @@ pub trait Program { } fn draw(&self, bounds: Size) -> Vec; + + fn mouse_cursor(&self, _bounds: Size) -> MouseCursor { + MouseCursor::default() + } } impl Program for &mut T @@ -19,4 +24,8 @@ where fn draw(&self, bounds: Size) -> Vec { T::draw(self, bounds) } + + fn mouse_cursor(&self, bounds: Size) -> MouseCursor { + T::mouse_cursor(self, bounds) + } } -- cgit From dc51080328caa12d2b1fc02febc72cab70bb9f50 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 29 Apr 2020 04:25:49 +0200 Subject: Introduce `Cursor` type in `canvas` --- wgpu/src/widget/canvas.rs | 38 +++++++++++++---------------- wgpu/src/widget/canvas/cursor.rs | 50 +++++++++++++++++++++++++++++++++++++++ wgpu/src/widget/canvas/program.rs | 32 ++++++++++++++++--------- 3 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 wgpu/src/widget/canvas/cursor.rs (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 0006ca8d..a5834330 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -9,8 +9,8 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ - input::mouse, layout, Clipboard, Element, Hasher, Layout, Length, - MouseCursor, Point, Size, Vector, Widget, + layout, Clipboard, Element, Hasher, Layout, Length, MouseCursor, Point, + Size, Vector, Widget, }; use std::hash::Hash; use std::marker::PhantomData; @@ -18,6 +18,7 @@ use std::marker::PhantomData; pub mod path; mod cache; +mod cursor; mod event; mod fill; mod frame; @@ -27,6 +28,7 @@ mod stroke; mod text; pub use cache::Cache; +pub use cursor::Cursor; pub use event::Event; pub use fill::Fill; pub use frame::Frame; @@ -59,10 +61,10 @@ pub use text::Text; /// ```no_run /// # mod iced { /// # pub use iced_wgpu::canvas; -/// # pub use iced_native::{Color, Size}; +/// # pub use iced_native::{Color, Rectangle}; /// # } -/// use iced::canvas::{self, Cache, Canvas, Fill, Frame, Geometry, Path, Program}; -/// use iced::{Color, Size}; +/// use iced::canvas::{self, Canvas, Cursor, Fill, Frame, Geometry, Path, Program}; +/// use iced::{Color, Rectangle}; /// /// // First, we define the data we need for drawing /// #[derive(Debug)] @@ -72,9 +74,9 @@ pub use text::Text; /// /// // Then, we implement the `Program` trait /// impl Program<()> for Circle { -/// fn draw(&self, bounds: Size) -> Vec{ +/// fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec{ /// // We prepare a new `Frame` -/// let mut frame = Frame::new(bounds); +/// let mut frame = Frame::new(bounds.size()); /// /// // We create a `Path` representing a simple circle /// let circle = Path::circle(frame.center(), self.radius); @@ -165,22 +167,16 @@ impl> Widget let canvas_event = match event { iced_native::Event::Mouse(mouse_event) => { - Some(Event::Mouse(match mouse_event { - mouse::Event::CursorMoved { .. } => { - mouse::Event::CursorMoved { - x: cursor_position.x - bounds.x, - y: cursor_position.y - bounds.y, - } - } - _ => mouse_event, - })) + Some(Event::Mouse(mouse_event)) } _ => None, }; + let cursor = Cursor::from_window_position(cursor_position); + if let Some(canvas_event) = canvas_event { if let Some(message) = - self.program.update(canvas_event, bounds.size()) + self.program.update(canvas_event, bounds, cursor) { messages.push(message); } @@ -192,11 +188,11 @@ impl> Widget _renderer: &mut Renderer, _defaults: &Defaults, layout: Layout<'_>, - _cursor_position: Point, + cursor_position: Point, ) -> (Primitive, MouseCursor) { let bounds = layout.bounds(); let translation = Vector::new(bounds.x, bounds.y); - let size = Size::new(bounds.width, bounds.height); + let cursor = Cursor::from_window_position(cursor_position); ( Primitive::Translate { @@ -204,13 +200,13 @@ impl> Widget content: Box::new(Primitive::Group { primitives: self .program - .draw(size) + .draw(bounds, cursor) .into_iter() .map(Geometry::into_primitive) .collect(), }), }, - self.program.mouse_cursor(size), + self.program.mouse_cursor(bounds, cursor), ) } diff --git a/wgpu/src/widget/canvas/cursor.rs b/wgpu/src/widget/canvas/cursor.rs new file mode 100644 index 00000000..a559782a --- /dev/null +++ b/wgpu/src/widget/canvas/cursor.rs @@ -0,0 +1,50 @@ +use iced_native::{Point, Rectangle}; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Cursor { + Available(Point), + Unavailable, +} + +impl Cursor { + // TODO: Remove this once this type is used in `iced_native` to encode + // proper cursor availability + pub(crate) fn from_window_position(position: Point) -> Self { + if position.x < 0.0 || position.y < 0.0 { + Cursor::Unavailable + } else { + Cursor::Available(position) + } + } + + pub fn position(&self) -> Option { + match self { + Cursor::Available(position) => Some(*position), + Cursor::Unavailable => None, + } + } + + pub fn relative_position(&self, bounds: &Rectangle) -> Option { + match self { + Cursor::Available(position) => { + Some(Point::new(position.x - bounds.x, position.y - bounds.y)) + } + _ => None, + } + } + + pub fn internal_position(&self, bounds: &Rectangle) -> Option { + if self.is_over(bounds) { + self.relative_position(bounds) + } else { + None + } + } + + pub fn is_over(&self, bounds: &Rectangle) -> bool { + match self { + Cursor::Available(position) => bounds.contains(*position), + Cursor::Unavailable => false, + } + } +} diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs index 9e4aca89..f8e54514 100644 --- a/wgpu/src/widget/canvas/program.rs +++ b/wgpu/src/widget/canvas/program.rs @@ -1,14 +1,19 @@ -use crate::canvas::{Event, Geometry, Size}; -use iced_native::MouseCursor; +use crate::canvas::{Cursor, Event, Geometry}; +use iced_native::{MouseCursor, Rectangle}; pub trait Program { - fn update(&mut self, _event: Event, _bounds: Size) -> Option { + fn update( + &mut self, + _event: Event, + _bounds: Rectangle, + _cursor: Cursor, + ) -> Option { None } - fn draw(&self, bounds: Size) -> Vec; + fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec; - fn mouse_cursor(&self, _bounds: Size) -> MouseCursor { + fn mouse_cursor(&self, _bounds: Rectangle, _cursor: Cursor) -> MouseCursor { MouseCursor::default() } } @@ -17,15 +22,20 @@ impl Program for &mut T where T: Program, { - fn update(&mut self, event: Event, bounds: Size) -> Option { - T::update(self, event, bounds) + fn update( + &mut self, + event: Event, + bounds: Rectangle, + cursor: Cursor, + ) -> Option { + T::update(self, event, bounds, cursor) } - fn draw(&self, bounds: Size) -> Vec { - T::draw(self, bounds) + fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec { + T::draw(self, bounds, cursor) } - fn mouse_cursor(&self, bounds: Size) -> MouseCursor { - T::mouse_cursor(self, bounds) + fn mouse_cursor(&self, bounds: Rectangle, cursor: Cursor) -> MouseCursor { + T::mouse_cursor(self, bounds, cursor) } } -- cgit From 5d12e194f45b4a01034f3f52fae16c10bc0192dd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 29 Apr 2020 20:58:59 +0200 Subject: Rename `Cursor::*_position` methods in `canvas` --- wgpu/src/widget/canvas/cursor.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/cursor.rs b/wgpu/src/widget/canvas/cursor.rs index a559782a..7ab58b87 100644 --- a/wgpu/src/widget/canvas/cursor.rs +++ b/wgpu/src/widget/canvas/cursor.rs @@ -24,23 +24,23 @@ impl Cursor { } } - pub fn relative_position(&self, bounds: &Rectangle) -> Option { - match self { - Cursor::Available(position) => { - Some(Point::new(position.x - bounds.x, position.y - bounds.y)) - } - _ => None, - } - } - - pub fn internal_position(&self, bounds: &Rectangle) -> Option { + pub fn position_in(&self, bounds: &Rectangle) -> Option { if self.is_over(bounds) { - self.relative_position(bounds) + self.position_from(bounds.position()) } else { None } } + pub fn position_from(&self, origin: Point) -> Option { + match self { + Cursor::Available(position) => { + Some(Point::new(position.x - origin.x, position.y - origin.y)) + } + Cursor::Unavailable => None, + } + } + pub fn is_over(&self, bounds: &Rectangle) -> bool { match self { Cursor::Available(position) => bounds.contains(*position), -- cgit From 38c4dd5fdbdb299c1c5b0e64f44855e98a0db85f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 29 Apr 2020 23:49:37 +0200 Subject: Reduce initial size of `triangle` buffers in `iced_wgpu` --- wgpu/src/triangle.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 246dc7ce..3e68a269 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -7,8 +7,8 @@ use zerocopy::AsBytes; mod msaa; const UNIFORM_BUFFER_SIZE: usize = 100; -const VERTEX_BUFFER_SIZE: usize = 100_000; -const INDEX_BUFFER_SIZE: usize = 100_000; +const VERTEX_BUFFER_SIZE: usize = 10_000; +const INDEX_BUFFER_SIZE: usize = 10_000; #[derive(Debug)] pub(crate) struct Pipeline { -- cgit From bb9ccc4f62ceea08dc1ef0c6c4d3d219897e44a1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 30 Apr 2020 05:04:45 +0200 Subject: Remove inconsistent `input` module in `iced_native` --- wgpu/src/widget/canvas/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs index 7a8b0829..4e7c1869 100644 --- a/wgpu/src/widget/canvas/event.rs +++ b/wgpu/src/widget/canvas/event.rs @@ -1,4 +1,4 @@ -use iced_native::input::mouse; +use iced_native::mouse; #[derive(Debug, Clone, Copy, PartialEq)] pub enum Event { -- cgit From d4c4198f7242f168de65146e0ca339e0c1cbfe9b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 30 Apr 2020 07:38:46 +0200 Subject: Write documentation for the new `canvas` API --- wgpu/src/lib.rs | 2 +- wgpu/src/widget/canvas.rs | 11 +++++++---- wgpu/src/widget/canvas/cache.rs | 36 ++++++++++++++++++++++++------------ wgpu/src/widget/canvas/cursor.rs | 22 ++++++++++++++++++++++ wgpu/src/widget/canvas/event.rs | 4 ++++ wgpu/src/widget/canvas/geometry.rs | 14 ++++++++++++++ wgpu/src/widget/canvas/program.rs | 36 ++++++++++++++++++++++++++++++++++++ wgpu/src/widget/canvas/stroke.rs | 14 ++++++++++++++ 8 files changed, 122 insertions(+), 17 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 30b5bb4a..799c1f34 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -20,7 +20,7 @@ //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph -//#![deny(missing_docs)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(unused_results)] #![forbid(unsafe_code)] diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index a5834330..05306e67 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -48,12 +48,15 @@ pub use text::Text; /// /// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock /// and its hands to display the current time. +/// - [`game_of_life`], an interactive version of the Game of Life, invented by +/// John Conway. /// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget /// and showcasing how to compose different transforms. /// -/// [examples]: https://github.com/hecrj/iced/tree/0.1/examples -/// [`clock`]: https://github.com/hecrj/iced/tree/0.1/examples/clock -/// [`solar_system`]: https://github.com/hecrj/iced/tree/0.1/examples/solar_system +/// [examples]: https://github.com/hecrj/iced/tree/master/examples +/// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock +/// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life +/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system /// /// ## Drawing a simple circle /// If you want to get a quick overview, here's how we can draw a simple circle: @@ -89,7 +92,7 @@ pub use text::Text; /// } /// } /// -/// // Finally, we simply use our `Cache` to create the `Canvas`! +/// // Finally, we simply use our `Circle` to create the `Canvas`! /// let canvas = Canvas::new(Circle { radius: 50.0 }); /// ``` #[derive(Debug)] diff --git a/wgpu/src/widget/canvas/cache.rs b/wgpu/src/widget/canvas/cache.rs index 03643f74..4b28d164 100644 --- a/wgpu/src/widget/canvas/cache.rs +++ b/wgpu/src/widget/canvas/cache.rs @@ -19,13 +19,14 @@ impl Default for State { State::Empty } } -/// A simple cache that stores generated geometry to avoid recomputation. +/// 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. /// /// [`Layer`]: ../trait.Layer.html /// [`Cache`]: struct.Cache.html +/// [`Geometry`]: struct.Geometry.html #[derive(Debug, Default)] pub struct Cache { state: RefCell, @@ -41,30 +42,41 @@ impl Cache { } } - /// Clears the cache, forcing a redraw the next time it is used. + /// Clears the [`Cache`], forcing a redraw the next time it is used. /// - /// [`Cached`]: struct.Cached.html + /// [`Cache`]: struct.Cache.html pub fn clear(&mut self) { *self.state.borrow_mut() = State::Empty; } - pub fn draw( - &self, - new_bounds: Size, - draw_fn: impl Fn(&mut Frame), - ) -> Geometry { + /// Draws [`Geometry`] using the provided closure and stores it in the + /// [`Cache`]. + /// + /// The closure will only be called when + /// - the bounds have changed since the previous draw call. + /// - the [`Cache`] is empty or has been explicitly cleared. + /// + /// Otherwise, the previously stored [`Geometry`] will be returned. The + /// [`Cache`] is not cleared in this case. In other words, it will keep + /// returning the stored [`Geometry`] if needed. + /// + /// [`Cache`]: struct.Cache.html + pub fn draw(&self, bounds: Size, draw_fn: impl Fn(&mut Frame)) -> Geometry { use std::ops::Deref; - if let State::Filled { bounds, primitive } = self.state.borrow().deref() + if let State::Filled { + bounds: cached_bounds, + primitive, + } = self.state.borrow().deref() { - if *bounds == new_bounds { + if *cached_bounds == bounds { return Geometry::from_primitive(Primitive::Cached { cache: primitive.clone(), }); } } - let mut frame = Frame::new(new_bounds); + let mut frame = Frame::new(bounds); draw_fn(&mut frame); let primitive = { @@ -74,7 +86,7 @@ impl Cache { }; *self.state.borrow_mut() = State::Filled { - bounds: new_bounds, + bounds, primitive: primitive.clone(), }; diff --git a/wgpu/src/widget/canvas/cursor.rs b/wgpu/src/widget/canvas/cursor.rs index 7ab58b87..456760ea 100644 --- a/wgpu/src/widget/canvas/cursor.rs +++ b/wgpu/src/widget/canvas/cursor.rs @@ -1,8 +1,12 @@ use iced_native::{Point, Rectangle}; +/// The mouse cursor state. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Cursor { + /// The cursor has a defined position. Available(Point), + + /// The cursor is currently unavailable (i.e. out of bounds or busy). Unavailable, } @@ -17,6 +21,9 @@ impl Cursor { } } + /// Returns the absolute position of the [`Cursor`], if available. + /// + /// [`Cursor`]: enum.Cursor.html pub fn position(&self) -> Option { match self { Cursor::Available(position) => Some(*position), @@ -24,6 +31,13 @@ impl Cursor { } } + /// Returns the relative position of the [`Cursor`] inside the given bounds, + /// if available. + /// + /// If the [`Cursor`] is not over the provided bounds, this method will + /// return `None`. + /// + /// [`Cursor`]: enum.Cursor.html pub fn position_in(&self, bounds: &Rectangle) -> Option { if self.is_over(bounds) { self.position_from(bounds.position()) @@ -32,6 +46,10 @@ impl Cursor { } } + /// Returns the relative position of the [`Cursor`] from the given origin, + /// if available. + /// + /// [`Cursor`]: enum.Cursor.html pub fn position_from(&self, origin: Point) -> Option { match self { Cursor::Available(position) => { @@ -41,6 +59,10 @@ impl Cursor { } } + /// Returns whether the [`Cursor`] is currently over the provided bounds + /// or not. + /// + /// [`Cursor`]: enum.Cursor.html pub fn is_over(&self, bounds: &Rectangle) -> bool { match self { Cursor::Available(position) => bounds.contains(*position), diff --git a/wgpu/src/widget/canvas/event.rs b/wgpu/src/widget/canvas/event.rs index 4e7c1869..ad11f51e 100644 --- a/wgpu/src/widget/canvas/event.rs +++ b/wgpu/src/widget/canvas/event.rs @@ -1,6 +1,10 @@ use iced_native::mouse; +/// A [`Canvas`] event. +/// +/// [`Canvas`]: struct.Event.html #[derive(Debug, Clone, Copy, PartialEq)] pub enum Event { + /// A mouse event. Mouse(mouse::Event), } diff --git a/wgpu/src/widget/canvas/geometry.rs b/wgpu/src/widget/canvas/geometry.rs index 12ef828f..4cadee39 100644 --- a/wgpu/src/widget/canvas/geometry.rs +++ b/wgpu/src/widget/canvas/geometry.rs @@ -1,5 +1,13 @@ use crate::Primitive; +/// A bunch of shapes that can be drawn. +/// +/// [`Geometry`] can be easily generated with a [`Frame`] or stored in a +/// [`Cache`]. +/// +/// [`Geometry`]: struct.Geometry.html +/// [`Frame`]: struct.Frame.html +/// [`Cache`]: struct.Cache.html #[derive(Debug, Clone)] pub struct Geometry(Primitive); @@ -8,6 +16,12 @@ impl Geometry { Self(primitive) } + /// Turns the [`Geometry`] into a [`Primitive`]. + /// + /// This can be useful if you are building a custom widget. + /// + /// [`Geometry`]: struct.Geometry.html + /// [`Primitive`]: ../enum.Primitive.html pub fn into_primitive(self) -> Primitive { self.0 } diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs index f8e54514..5b995bfa 100644 --- a/wgpu/src/widget/canvas/program.rs +++ b/wgpu/src/widget/canvas/program.rs @@ -1,7 +1,27 @@ use crate::canvas::{Cursor, Event, Geometry}; use iced_native::{MouseCursor, Rectangle}; +/// The state and logic of a [`Canvas`]. +/// +/// A [`Program`] can mutate internal state and produce messages for an +/// application. +/// +/// [`Canvas`]: struct.Canvas.html +/// [`Program`]: trait.Program.html pub trait Program { + /// Updates the state of the [`Program`]. + /// + /// When a [`Program`] is used in a [`Canvas`], the runtime will call this + /// method for each [`Event`]. + /// + /// This method can optionally return a `Message` to notify an application + /// of any meaningful interactions. + /// + /// By default, this method does and returns nothing. + /// + /// [`Program`]: trait.Program.html + /// [`Canvas`]: struct.Canvas.html + /// [`Event`]: enum.Event.html fn update( &mut self, _event: Event, @@ -11,8 +31,24 @@ pub trait Program { 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`]. + /// + /// [`Program`]: trait.Program.html + /// [`Geometry`]: struct.Geometry.html + /// [`Frame`]: struct.Frame.html + /// [`Cache`]: struct.Cache.html fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec; + /// Returns the mouse cursor state of the [`Program`]. + /// + /// The mouse cursor returned will be in effect even if the cursor position + /// is out of bounds of the program's [`Canvas`]. + /// + /// [`Program`]: trait.Program.html + /// [`Canvas`]: struct.Canvas.html fn mouse_cursor(&self, _bounds: Rectangle, _cursor: Cursor) -> MouseCursor { MouseCursor::default() } diff --git a/wgpu/src/widget/canvas/stroke.rs b/wgpu/src/widget/canvas/stroke.rs index e20379cd..5b6fc56a 100644 --- a/wgpu/src/widget/canvas/stroke.rs +++ b/wgpu/src/widget/canvas/stroke.rs @@ -15,18 +15,32 @@ pub struct Stroke { } impl Stroke { + /// Sets the color of the [`Stroke`]. + /// + /// [`Stroke`]: struct.Stroke.html pub fn with_color(self, color: Color) -> Stroke { Stroke { color, ..self } } + /// Sets the width of the [`Stroke`]. + /// + /// [`Stroke`]: struct.Stroke.html pub fn with_width(self, width: f32) -> Stroke { Stroke { width, ..self } } + /// Sets the [`LineCap`] of the [`Stroke`]. + /// + /// [`LineCap`]: enum.LineCap.html + /// [`Stroke`]: struct.Stroke.html pub fn with_line_cap(self, line_cap: LineCap) -> Stroke { Stroke { line_cap, ..self } } + /// Sets the [`LineJoin`] of the [`Stroke`]. + /// + /// [`LineJoin`]: enum.LineJoin.html + /// [`Stroke`]: struct.Stroke.html pub fn with_line_join(self, line_join: LineJoin) -> Stroke { Stroke { line_join, ..self } } -- cgit From 98bc8cf2a7c4944d762a0148ca9f615d6ccc0d6e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 30 Apr 2020 08:16:38 +0200 Subject: Rename `MouseCursor` to `mouse::Interaction` --- wgpu/src/renderer.rs | 11 +++++------ wgpu/src/renderer/widget/button.rs | 6 +++--- wgpu/src/renderer/widget/checkbox.rs | 6 +++--- wgpu/src/renderer/widget/column.rs | 12 ++++++------ wgpu/src/renderer/widget/container.rs | 6 +++--- wgpu/src/renderer/widget/image.rs | 4 ++-- wgpu/src/renderer/widget/pane_grid.rs | 19 ++++++++++--------- wgpu/src/renderer/widget/progress_bar.rs | 4 ++-- wgpu/src/renderer/widget/radio.rs | 6 +++--- wgpu/src/renderer/widget/row.rs | 12 ++++++------ wgpu/src/renderer/widget/scrollable.rs | 10 ++++------ wgpu/src/renderer/widget/slider.rs | 8 ++++---- wgpu/src/renderer/widget/space.rs | 4 ++-- wgpu/src/renderer/widget/svg.rs | 4 ++-- wgpu/src/renderer/widget/text.rs | 4 ++-- wgpu/src/renderer/widget/text_input.rs | 9 +++++---- wgpu/src/widget/canvas.rs | 8 ++++---- wgpu/src/widget/canvas/program.rs | 22 +++++++++++++++------- wgpu/src/window/backend.rs | 8 ++++---- 19 files changed, 85 insertions(+), 78 deletions(-) (limited to 'wgpu/src') diff --git a/wgpu/src/renderer.rs b/wgpu/src/renderer.rs index dccd0d82..71b4af38 100644 --- a/wgpu/src/renderer.rs +++ b/wgpu/src/renderer.rs @@ -7,8 +7,7 @@ use crate::{ use crate::image::{self, Image}; use iced_native::{ - layout, Background, Color, Layout, MouseCursor, Point, Rectangle, Vector, - Widget, + layout, mouse, Background, Color, Layout, Point, Rectangle, Vector, Widget, }; mod widget; @@ -94,10 +93,10 @@ impl Renderer { device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: Target<'_>, - (primitive, mouse_cursor): &(Primitive, MouseCursor), + (primitive, mouse_interaction): &(Primitive, mouse::Interaction), scale_factor: f64, overlay: &[T], - ) -> MouseCursor { + ) -> mouse::Interaction { log::debug!("Drawing"); let (width, height) = target.viewport.dimensions(); @@ -132,7 +131,7 @@ impl Renderer { #[cfg(any(feature = "image", feature = "svg"))] self.image_pipeline.trim_cache(); - *mouse_cursor + *mouse_interaction } fn draw_primitive<'a>( @@ -453,7 +452,7 @@ impl Renderer { } impl iced_native::Renderer for Renderer { - type Output = (Primitive, MouseCursor); + type Output = (Primitive, mouse::Interaction); type Defaults = Defaults; fn layout<'a, Message>( diff --git a/wgpu/src/renderer/widget/button.rs b/wgpu/src/renderer/widget/button.rs index 5e55873a..eb225038 100644 --- a/wgpu/src/renderer/widget/button.rs +++ b/wgpu/src/renderer/widget/button.rs @@ -1,6 +1,6 @@ use crate::{button::StyleSheet, defaults, Defaults, Primitive, Renderer}; use iced_native::{ - Background, Color, Element, Layout, MouseCursor, Point, Rectangle, Vector, + mouse, Background, Color, Element, Layout, Point, Rectangle, Vector, }; impl iced_native::button::Renderer for Renderer { @@ -84,9 +84,9 @@ impl iced_native::button::Renderer for Renderer { content }, if is_mouse_over { - MouseCursor::Pointer + mouse::Interaction::Pointer } else { - MouseCursor::default() + mouse::Interaction::default() }, ) } diff --git a/wgpu/src/renderer/widget/checkbox.rs b/wgpu/src/renderer/widget/checkbox.rs index 7f7f6de3..0340bf62 100644 --- a/wgpu/src/renderer/widget/checkbox.rs +++ b/wgpu/src/renderer/widget/checkbox.rs @@ -1,6 +1,6 @@ use crate::{checkbox::StyleSheet, Primitive, Renderer}; use iced_native::{ - checkbox, HorizontalAlignment, MouseCursor, Rectangle, VerticalAlignment, + checkbox, mouse, HorizontalAlignment, Rectangle, VerticalAlignment, }; impl checkbox::Renderer for Renderer { @@ -54,9 +54,9 @@ impl checkbox::Renderer for Renderer { }, }, if is_mouse_over { - MouseCursor::Pointer + mouse::Interaction::Pointer } else { - MouseCursor::default() + mouse::Interaction::default() }, ) } diff --git a/wgpu/src/renderer/widget/column.rs b/wgpu/src/renderer/widget/column.rs index e6a9d8f0..b853276d 100644 --- a/wgpu/src/renderer/widget/column.rs +++ b/wgpu/src/renderer/widget/column.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{column, Element, Layout, MouseCursor, Point}; +use iced_native::{column, mouse, Element, Layout, Point}; impl column::Renderer for Renderer { fn draw( @@ -9,7 +9,7 @@ impl column::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - let mut mouse_cursor = MouseCursor::default(); + let mut mouse_interaction = mouse::Interaction::default(); ( Primitive::Group { @@ -17,18 +17,18 @@ impl column::Renderer for Renderer { .iter() .zip(layout.children()) .map(|(child, layout)| { - let (primitive, new_mouse_cursor) = + let (primitive, new_mouse_interaction) = child.draw(self, defaults, layout, cursor_position); - if new_mouse_cursor > mouse_cursor { - mouse_cursor = new_mouse_cursor; + if new_mouse_interaction > mouse_interaction { + mouse_interaction = new_mouse_interaction; } primitive }) .collect(), }, - mouse_cursor, + mouse_interaction, ) } } diff --git a/wgpu/src/renderer/widget/container.rs b/wgpu/src/renderer/widget/container.rs index dda7dc8a..30cc3f07 100644 --- a/wgpu/src/renderer/widget/container.rs +++ b/wgpu/src/renderer/widget/container.rs @@ -21,7 +21,7 @@ impl iced_native::container::Renderer for Renderer { }, }; - let (content, mouse_cursor) = + let (content, mouse_interaction) = content.draw(self, &defaults, content_layout, cursor_position); if style.background.is_some() || style.border_width > 0 { @@ -39,10 +39,10 @@ impl iced_native::container::Renderer for Renderer { Primitive::Group { primitives: vec![quad, content], }, - mouse_cursor, + mouse_interaction, ) } else { - (content, mouse_cursor) + (content, mouse_interaction) } } } diff --git a/wgpu/src/renderer/widget/image.rs b/wgpu/src/renderer/widget/image.rs index 6b7f1c60..c4c04984 100644 --- a/wgpu/src/renderer/widget/image.rs +++ b/wgpu/src/renderer/widget/image.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{image, Layout, MouseCursor}; +use iced_native::{image, mouse, Layout}; impl image::Renderer for Renderer { fn dimensions(&self, handle: &image::Handle) -> (u32, u32) { @@ -16,7 +16,7 @@ impl image::Renderer for Renderer { handle, bounds: layout.bounds(), }, - MouseCursor::default(), + mouse::Interaction::default(), ) } } diff --git a/wgpu/src/renderer/widget/pane_grid.rs b/wgpu/src/renderer/widget/pane_grid.rs index 80e2471f..2253e4af 100644 --- a/wgpu/src/renderer/widget/pane_grid.rs +++ b/wgpu/src/renderer/widget/pane_grid.rs @@ -1,7 +1,8 @@ use crate::{Primitive, Renderer}; use iced_native::{ + mouse, pane_grid::{self, Axis, Pane}, - Element, Layout, MouseCursor, Point, Rectangle, Vector, + Element, Layout, Point, Rectangle, Vector, }; impl pane_grid::Renderer for Renderer { @@ -22,7 +23,7 @@ impl pane_grid::Renderer for Renderer { cursor_position }; - let mut mouse_cursor = MouseCursor::default(); + let mut mouse_interaction = mouse::Interaction::default(); let mut dragged_pane = None; let mut panes: Vec<_> = content @@ -30,11 +31,11 @@ impl pane_grid::Renderer for Renderer { .zip(layout.children()) .enumerate() .map(|(i, ((id, pane), layout))| { - let (primitive, new_mouse_cursor) = + let (primitive, new_mouse_interaction) = pane.draw(self, defaults, layout, pane_cursor_position); - if new_mouse_cursor > mouse_cursor { - mouse_cursor = new_mouse_cursor; + if new_mouse_interaction > mouse_interaction { + mouse_interaction = new_mouse_interaction; } if Some(*id) == dragging { @@ -78,14 +79,14 @@ impl pane_grid::Renderer for Renderer { ( Primitive::Group { primitives }, if dragging.is_some() { - MouseCursor::Grabbing + mouse::Interaction::Grabbing } else if let Some(axis) = resizing { match axis { - Axis::Horizontal => MouseCursor::ResizingVertically, - Axis::Vertical => MouseCursor::ResizingHorizontally, + Axis::Horizontal => mouse::Interaction::ResizingVertically, + Axis::Vertical => mouse::Interaction::ResizingHorizontally, } } else { - mouse_cursor + mouse_interaction }, ) } diff --git a/wgpu/src/renderer/widget/progress_bar.rs b/wgpu/src/renderer/widget/progress_bar.rs index fe032fbf..2baeeb14 100644 --- a/wgpu/src/renderer/widget/progress_bar.rs +++ b/wgpu/src/renderer/widget/progress_bar.rs @@ -1,5 +1,5 @@ use crate::{progress_bar::StyleSheet, Primitive, Renderer}; -use iced_native::{progress_bar, Color, MouseCursor, Rectangle}; +use iced_native::{mouse, progress_bar, Color, Rectangle}; impl progress_bar::Renderer for Renderer { type Style = Box; @@ -48,7 +48,7 @@ impl progress_bar::Renderer for Renderer { } else { background }, - MouseCursor::default(), + mouse::Interaction::default(), ) } } diff --git a/wgpu/src/renderer/widget/radio.rs b/wgpu/src/renderer/widget/radio.rs index 551700c8..2f1461db 100644 --- a/wgpu/src/renderer/widget/radio.rs +++ b/wgpu/src/renderer/widget/radio.rs @@ -1,5 +1,5 @@ use crate::{radio::StyleSheet, Primitive, Renderer}; -use iced_native::{radio, Background, Color, MouseCursor, Rectangle}; +use iced_native::{mouse, radio, Background, Color, Rectangle}; const SIZE: f32 = 28.0; const DOT_SIZE: f32 = SIZE / 2.0; @@ -55,9 +55,9 @@ impl radio::Renderer for Renderer { }, }, if is_mouse_over { - MouseCursor::Pointer + mouse::Interaction::Pointer } else { - MouseCursor::default() + mouse::Interaction::default() }, ) } diff --git a/wgpu/src/renderer/widget/row.rs b/wgpu/src/renderer/widget/row.rs index c6a10c07..d0b7ef09 100644 --- a/wgpu/src/renderer/widget/row.rs +++ b/wgpu/src/renderer/widget/row.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{row, Element, Layout, MouseCursor, Point}; +use iced_native::{mouse, row, Element, Layout, Point}; impl row::Renderer for Renderer { fn draw( @@ -9,7 +9,7 @@ impl row::Renderer for Renderer { layout: Layout<'_>, cursor_position: Point, ) -> Self::Output { - let mut mouse_cursor = MouseCursor::default(); + let mut mouse_interaction = mouse::Interaction::default(); ( Primitive::Group { @@ -17,18 +17,18 @@ impl row::Renderer for Renderer { .iter() .zip(layout.children()) .map(|(child, layout)| { - let (primitive, new_mouse_cursor) = + let (primitive, new_mouse_interaction) = child.draw(self, defaults, layout, cursor_position); - if new_mouse_cursor > mouse_cursor { - mouse_cursor = new_mouse_cursor; + if new_mouse_interaction > mouse_interaction { + mouse_interaction = new_mouse_interaction; } primitive }) .collect(), }, - mouse_cursor, + mouse_interaction, ) } } diff --git a/wgpu/src/renderer/widget/scrollable.rs b/wgpu/src/renderer/widget/scrollable.rs index 732523e3..8a400b82 100644 --- a/wgpu/src/renderer/widget/scrollable.rs +++ b/wgpu/src/renderer/widget/scrollable.rs @@ -1,7 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{ - scrollable, Background, Color, MouseCursor, Rectangle, Vector, -}; +use iced_native::{mouse, scrollable, Background, Color, Rectangle, Vector}; const SCROLLBAR_WIDTH: u16 = 10; const SCROLLBAR_MARGIN: u16 = 2; @@ -56,7 +54,7 @@ impl scrollable::Renderer for Renderer { scrollbar: Option, offset: u32, style_sheet: &Self::Style, - (content, mouse_cursor): Self::Output, + (content, mouse_interaction): Self::Output, ) -> Self::Output { ( if let Some(scrollbar) = scrollbar { @@ -118,9 +116,9 @@ impl scrollable::Renderer for Renderer { content }, if is_mouse_over_scrollbar || state.is_scroller_grabbed() { - MouseCursor::Idle + mouse::Interaction::Idle } else { - mouse_cursor + mouse_interaction }, ) } diff --git a/wgpu/src/renderer/widget/slider.rs b/wgpu/src/renderer/widget/slider.rs index 335e1b92..220feace 100644 --- a/wgpu/src/renderer/widget/slider.rs +++ b/wgpu/src/renderer/widget/slider.rs @@ -2,7 +2,7 @@ use crate::{ slider::{HandleShape, StyleSheet}, Primitive, Renderer, }; -use iced_native::{slider, Background, Color, MouseCursor, Point, Rectangle}; +use iced_native::{mouse, slider, Background, Color, Point, Rectangle}; const HANDLE_HEIGHT: f32 = 22.0; @@ -95,11 +95,11 @@ impl slider::Renderer for Renderer { primitives: vec![rail_top, rail_bottom, handle], }, if is_dragging { - MouseCursor::Grabbing + mouse::Interaction::Grabbing } else if is_mouse_over { - MouseCursor::Grab + mouse::Interaction::Grab } else { - MouseCursor::default() + mouse::Interaction::default() }, ) } diff --git a/wgpu/src/renderer/widget/space.rs b/wgpu/src/renderer/widget/space.rs index 9ec0ed6d..225f7e6c 100644 --- a/wgpu/src/renderer/widget/space.rs +++ b/wgpu/src/renderer/widget/space.rs @@ -1,8 +1,8 @@ use crate::{Primitive, Renderer}; -use iced_native::{space, MouseCursor, Rectangle}; +use iced_native::{mouse, space, Rectangle}; impl space::Renderer for Renderer { fn draw(&mut self, _bounds: Rectangle) -> Self::Output { - (Primitive::None, MouseCursor::default()) + (Primitive::None, mouse::Interaction::default()) } } diff --git a/wgpu/src/renderer/widget/svg.rs b/wgpu/src/renderer/widget/svg.rs index 4ee983ea..f6d6d0ba 100644 --- a/wgpu/src/renderer/widget/svg.rs +++ b/wgpu/src/renderer/widget/svg.rs @@ -1,5 +1,5 @@ use crate::{Primitive, Renderer}; -use iced_native::{svg, Layout, MouseCursor}; +use iced_native::{mouse, svg, Layout}; impl svg::Renderer for Renderer { fn dimensions(&self, handle: &svg::Handle) -> (u32, u32) { @@ -16,7 +16,7 @@ impl svg::Renderer for Renderer { handle, bounds: layout.bounds(), }, - MouseCursor::default(), + mouse::Interaction::default(), ) } } diff --git a/wgpu/src/renderer/widget/text.rs b/wgpu/src/renderer/widget/text.rs index 4a4ecef4..4605ed06 100644 --- a/wgpu/src/renderer/widget/text.rs +++ b/wgpu/src/renderer/widget/text.rs @@ -1,6 +1,6 @@ use crate::{Primitive, Renderer}; use iced_native::{ - text, Color, Font, HorizontalAlignment, MouseCursor, Rectangle, Size, + mouse, text, Color, Font, HorizontalAlignment, Rectangle, Size, VerticalAlignment, }; @@ -55,7 +55,7 @@ impl text::Renderer for Renderer { horizontal_alignment, vertical_alignment, }, - MouseCursor::default(), + mouse::Interaction::default(), ) } } diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs index 97eb0114..57be6692 100644 --- a/wgpu/src/renderer/widget/text_input.rs +++ b/wgpu/src/renderer/widget/text_input.rs @@ -1,9 +1,10 @@ use crate::{text_input::StyleSheet, Primitive, Renderer}; use iced_native::{ + mouse, text_input::{self, cursor}, - Background, Color, Font, HorizontalAlignment, MouseCursor, Point, - Rectangle, Size, Vector, VerticalAlignment, + Background, Color, Font, HorizontalAlignment, Point, Rectangle, Size, + Vector, VerticalAlignment, }; use std::f32; @@ -232,9 +233,9 @@ impl text_input::Renderer for Renderer { primitives: vec![input, contents], }, if is_mouse_over { - MouseCursor::Text + mouse::Interaction::Text } else { - MouseCursor::default() + mouse::Interaction::default() }, ) } diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 05306e67..2fc10ea0 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -9,8 +9,8 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ - layout, Clipboard, Element, Hasher, Layout, Length, MouseCursor, Point, - Size, Vector, Widget, + layout, mouse, Clipboard, Element, Hasher, Layout, Length, Point, Size, + Vector, Widget, }; use std::hash::Hash; use std::marker::PhantomData; @@ -192,7 +192,7 @@ impl> Widget _defaults: &Defaults, layout: Layout<'_>, cursor_position: Point, - ) -> (Primitive, MouseCursor) { + ) -> (Primitive, mouse::Interaction) { let bounds = layout.bounds(); let translation = Vector::new(bounds.x, bounds.y); let cursor = Cursor::from_window_position(cursor_position); @@ -209,7 +209,7 @@ impl> Widget .collect(), }), }, - self.program.mouse_cursor(bounds, cursor), + self.program.mouse_interaction(bounds, cursor), ) } diff --git a/wgpu/src/widget/canvas/program.rs b/wgpu/src/widget/canvas/program.rs index 5b995bfa..725d9d72 100644 --- a/wgpu/src/widget/canvas/program.rs +++ b/wgpu/src/widget/canvas/program.rs @@ -1,5 +1,5 @@ use crate::canvas::{Cursor, Event, Geometry}; -use iced_native::{MouseCursor, Rectangle}; +use iced_native::{mouse, Rectangle}; /// The state and logic of a [`Canvas`]. /// @@ -42,15 +42,19 @@ pub trait Program { /// [`Cache`]: struct.Cache.html fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec; - /// Returns the mouse cursor state of the [`Program`]. + /// Returns the current mouse interaction of the [`Program`]. /// - /// The mouse cursor returned will be in effect even if the cursor position + /// The interaction returned will be in effect even if the cursor position /// is out of bounds of the program's [`Canvas`]. /// /// [`Program`]: trait.Program.html /// [`Canvas`]: struct.Canvas.html - fn mouse_cursor(&self, _bounds: Rectangle, _cursor: Cursor) -> MouseCursor { - MouseCursor::default() + fn mouse_interaction( + &self, + _bounds: Rectangle, + _cursor: Cursor, + ) -> mouse::Interaction { + mouse::Interaction::default() } } @@ -71,7 +75,11 @@ where T::draw(self, bounds, cursor) } - fn mouse_cursor(&self, bounds: Rectangle, cursor: Cursor) -> MouseCursor { - T::mouse_cursor(self, bounds, cursor) + fn mouse_interaction( + &self, + bounds: Rectangle, + cursor: Cursor, + ) -> mouse::Interaction { + T::mouse_interaction(self, bounds, cursor) } } diff --git a/wgpu/src/window/backend.rs b/wgpu/src/window/backend.rs index e1b77700..7e40ae0c 100644 --- a/wgpu/src/window/backend.rs +++ b/wgpu/src/window/backend.rs @@ -1,6 +1,6 @@ use crate::{window::SwapChain, Renderer, Settings, Target}; -use iced_native::{futures, MouseCursor}; +use iced_native::{futures, mouse}; use raw_window_handle::HasRawWindowHandle; /// A window graphics backend for iced powered by `wgpu`. @@ -78,7 +78,7 @@ impl iced_native::window::Backend for Backend { output: &::Output, scale_factor: f64, overlay: &[T], - ) -> MouseCursor { + ) -> mouse::Interaction { let (frame, viewport) = swap_chain.next_frame().expect("Next frame"); let mut encoder = self.device.create_command_encoder( @@ -101,7 +101,7 @@ impl iced_native::window::Backend for Backend { depth_stencil_attachment: None, }); - let mouse_cursor = renderer.draw( + let mouse_interaction = renderer.draw( &mut self.device, &mut encoder, Target { @@ -115,6 +115,6 @@ impl iced_native::window::Backend for Backend { self.queue.submit(&[encoder.finish()]); - mouse_cursor + mouse_interaction } } -- cgit From 08b376c6d7d2f3c1fab1328202325cb47ce369e5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 1 May 2020 04:33:17 +0200 Subject: Implement `Frame::fill_rectangle` This method greatly improves performance when drawing axis-aligned rectangles. --- wgpu/src/widget/canvas/frame.rs | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'wgpu/src') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 1c4a038a..5262ab4e 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -120,6 +120,43 @@ impl Frame { let _ = result.expect("Tessellate path"); } + /// Draws an axis-aligned rectangle given its top-left corner coordinate and + /// its `Size` on the [`Frame`] by filling it with the provided style. + /// + /// [`Frame`]: struct.Frame.html + pub fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ) { + use lyon::tessellation::{BuffersBuilder, FillOptions}; + + let mut buffers = BuffersBuilder::new( + &mut self.buffers, + FillVertex(match fill.into() { + Fill::Color(color) => color.into_linear(), + }), + ); + + let top_left = + self.transforms.current.raw.transform_point( + lyon::math::Point::new(top_left.x, top_left.y), + ); + + let size = + self.transforms.current.raw.transform_vector( + lyon::math::Vector::new(size.width, size.height), + ); + + let _ = lyon::tessellation::basic_shapes::fill_rectangle( + &lyon::math::Rect::new(top_left, size.into()), + &FillOptions::default(), + &mut buffers, + ) + .expect("Fill rectangle"); + } + /// Draws the stroke of the given [`Path`] on the [`Frame`] with the /// provided style. /// @@ -283,6 +320,20 @@ impl Frame { struct FillVertex([f32; 4]); +impl lyon::tessellation::BasicVertexConstructor + for FillVertex +{ + fn new_vertex( + &mut self, + position: lyon::math::Point, + ) -> triangle::Vertex2D { + triangle::Vertex2D { + position: [position.x, position.y], + color: self.0, + } + } +} + impl lyon::tessellation::FillVertexConstructor for FillVertex { -- cgit