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/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 ++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 wgpu/src/widget/canvas/event.rs create mode 100644 wgpu/src/widget/canvas/program.rs (limited to 'wgpu/src/widget/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 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/widget/canvas') 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/widget/canvas') 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/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 ++++++ 7 files changed, 154 insertions(+), 161 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/widget/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 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/widget/canvas') 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/widget/canvas') 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/widget/canvas/cache.rs | 12 +++++++++--- wgpu/src/widget/canvas/frame.rs | 12 ++++++------ wgpu/src/widget/canvas/geometry.rs | 15 ++++++++++----- 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'wgpu/src/widget/canvas') 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/widget/canvas') 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/cache.rs | 7 +++++-- wgpu/src/widget/canvas/state.rs | 14 ++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'wgpu/src/widget/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/widget/canvas/frame.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'wgpu/src/widget/canvas') 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/cache.rs | 37 +++++++------------------------------ wgpu/src/widget/canvas/drawable.rs | 36 ------------------------------------ wgpu/src/widget/canvas/program.rs | 22 ++++++++++++++++++++++ wgpu/src/widget/canvas/state.rs | 22 ---------------------- 4 files changed, 29 insertions(+), 88 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/widget/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 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/program.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'wgpu/src/widget/canvas') 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/cursor.rs | 50 +++++++++++++++++++++++++++++++++++++++ wgpu/src/widget/canvas/program.rs | 32 ++++++++++++++++--------- 2 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 wgpu/src/widget/canvas/cursor.rs (limited to 'wgpu/src/widget/canvas') 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/widget/canvas') 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 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/widget/canvas') 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/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 ++++++++++++++ 6 files changed, 114 insertions(+), 12 deletions(-) (limited to 'wgpu/src/widget/canvas') 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/widget/canvas/program.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'wgpu/src/widget/canvas') 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) } } -- 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/widget/canvas') 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