From 8daf798e5760a0d35d5491027d51a5dd96898b0d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 11 Feb 2020 23:14:25 +0100 Subject: Add `canvas` feature to `iced_wgpu` And prepare `canvas` module --- wgpu/src/widget/canvas.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 wgpu/src/widget/canvas.rs (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs new file mode 100644 index 00000000..ebb84135 --- /dev/null +++ b/wgpu/src/widget/canvas.rs @@ -0,0 +1,5 @@ +//! Draw freely in 2D. + +/// A 2D drawable region. +#[derive(Debug)] +pub struct Canvas; -- cgit From f436f20eb86b2324126a54d4164b4cedf2134a45 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 03:47:36 +0100 Subject: Draft `Canvas` types and `clock` example --- wgpu/src/widget/canvas.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index ebb84135..7b84f36c 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -1,5 +1,158 @@ //! Draw freely in 2D. +use crate::{Defaults, Primitive, Renderer}; + +use iced_native::{ + layout, Color, Element, Hasher, Layout, Length, MouseCursor, Point, Size, + Widget, +}; +use std::hash::Hash; + +pub mod layer; +pub mod path; + +mod data; +mod frame; + +pub use data::Data; +pub use frame::Frame; +pub use layer::Layer; +pub use path::Path; /// A 2D drawable region. #[derive(Debug)] -pub struct Canvas; +pub struct Canvas<'a> { + width: Length, + height: Length, + layers: Vec>, +} + +impl<'a> Canvas<'a> { + const DEFAULT_SIZE: u16 = 100; + + pub fn new() -> Self { + Canvas { + width: Length::Units(Self::DEFAULT_SIZE), + height: Length::Units(Self::DEFAULT_SIZE), + layers: Vec::new(), + } + } + + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + pub fn push(mut self, layer: impl Layer + 'a) -> Self { + self.layers.push(Box::new(layer)); + self + } +} + +impl<'a, Message> Widget for Canvas<'a> { + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout( + &self, + _renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let limits = limits.width(self.width).height(self.height); + + let size = limits.resolve(Size::ZERO); + + layout::Node::new(size) + } + + fn draw( + &self, + _renderer: &mut Renderer, + _defaults: &Defaults, + _layout: Layout<'_>, + _cursor_position: Point, + ) -> (Primitive, MouseCursor) { + (Primitive::None, MouseCursor::Idle) + } + + fn hash_layout(&self, state: &mut Hasher) { + std::any::TypeId::of::>().hash(state); + + self.width.hash(state); + self.height.hash(state); + } +} + +impl<'a, Message> From> for Element<'a, Message, Renderer> +where + Message: 'static, +{ + fn from(canvas: Canvas<'a>) -> Element<'a, Message, Renderer> { + Element::new(canvas) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct Stroke { + pub color: Color, + pub width: f32, + pub line_cap: LineCap, + pub line_join: LineJoin, +} + +impl Default for Stroke { + fn default() -> Stroke { + Stroke { + color: Color::BLACK, + width: 1.0, + line_cap: LineCap::default(), + line_join: LineJoin::default(), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum LineCap { + Butt, + Square, + Round, +} + +impl Default for LineCap { + fn default() -> LineCap { + LineCap::Butt + } +} + +#[derive(Debug, Clone, Copy)] +pub enum LineJoin { + Miter, + Round, + Bevel, +} + +impl Default for LineJoin { + fn default() -> LineJoin { + LineJoin::Miter + } +} + +#[derive(Debug, Clone, Copy)] +pub enum Fill { + Color(Color), +} + +impl Default for Fill { + fn default() -> Fill { + Fill::Color(Color::BLACK) + } +} -- cgit From f34407bfdaf06c4bf204dc31b152be9451c243b8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 07:08:49 +0100 Subject: Implement `Frame::fill` and `Frame::stroke` --- wgpu/src/widget/canvas.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 7b84f36c..6bfeed9a 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -133,6 +133,16 @@ impl Default for LineCap { } } +impl From for lyon::tessellation::LineCap { + fn from(line_cap: LineCap) -> lyon::tessellation::LineCap { + match line_cap { + LineCap::Butt => lyon::tessellation::LineCap::Butt, + LineCap::Square => lyon::tessellation::LineCap::Square, + LineCap::Round => lyon::tessellation::LineCap::Round, + } + } +} + #[derive(Debug, Clone, Copy)] pub enum LineJoin { Miter, @@ -146,6 +156,16 @@ impl Default for LineJoin { } } +impl From for lyon::tessellation::LineJoin { + fn from(line_join: LineJoin) -> lyon::tessellation::LineJoin { + match line_join { + LineJoin::Miter => lyon::tessellation::LineJoin::Miter, + LineJoin::Round => lyon::tessellation::LineJoin::Round, + LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel, + } + } +} + #[derive(Debug, Clone, Copy)] pub enum Fill { Color(Color), -- cgit From 578ea4abb8a2dd0d53d7087322796bf9ad541b56 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 08:49:42 +0100 Subject: Finish `clock` example --- wgpu/src/widget/canvas.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 6bfeed9a..c984fee9 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -68,7 +68,6 @@ impl<'a, Message> Widget for Canvas<'a> { limits: &layout::Limits, ) -> layout::Node { let limits = limits.width(self.width).height(self.height); - let size = limits.resolve(Size::ZERO); layout::Node::new(size) @@ -78,10 +77,26 @@ impl<'a, Message> Widget for Canvas<'a> { &self, _renderer: &mut Renderer, _defaults: &Defaults, - _layout: Layout<'_>, + layout: Layout<'_>, _cursor_position: Point, ) -> (Primitive, MouseCursor) { - (Primitive::None, MouseCursor::Idle) + let bounds = layout.bounds(); + let origin = Point::new(bounds.x, bounds.y); + let size = Size::new(bounds.width, bounds.height); + + ( + Primitive::Group { + primitives: self + .layers + .iter() + .map(|layer| Primitive::Mesh2D { + origin, + buffers: layer.draw(size), + }) + .collect(), + }, + MouseCursor::Idle, + ) } fn hash_layout(&self, state: &mut Hasher) { -- cgit From de8f06b512ec65f625417e334dca30990248c968 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 09:12:35 +0100 Subject: Split `Fill` and `Stroke` into their own modules --- wgpu/src/widget/canvas.rs | 83 +++-------------------------------------------- 1 file changed, 5 insertions(+), 78 deletions(-) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index c984fee9..1fc3ff01 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -2,8 +2,7 @@ use crate::{Defaults, Primitive, Renderer}; use iced_native::{ - layout, Color, Element, Hasher, Layout, Length, MouseCursor, Point, Size, - Widget, + layout, Element, Hasher, Layout, Length, MouseCursor, Point, Size, Widget, }; use std::hash::Hash; @@ -11,12 +10,16 @@ pub mod layer; pub mod path; mod data; +mod fill; mod frame; +mod stroke; pub use data::Data; +pub use fill::Fill; pub use frame::Frame; pub use layer::Layer; pub use path::Path; +pub use stroke::{LineCap, LineJoin, Stroke}; /// A 2D drawable region. #[derive(Debug)] @@ -115,79 +118,3 @@ where Element::new(canvas) } } - -#[derive(Debug, Clone, Copy)] -pub struct Stroke { - pub color: Color, - pub width: f32, - pub line_cap: LineCap, - pub line_join: LineJoin, -} - -impl Default for Stroke { - fn default() -> Stroke { - Stroke { - color: Color::BLACK, - width: 1.0, - line_cap: LineCap::default(), - line_join: LineJoin::default(), - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum LineCap { - Butt, - Square, - Round, -} - -impl Default for LineCap { - fn default() -> LineCap { - LineCap::Butt - } -} - -impl From for lyon::tessellation::LineCap { - fn from(line_cap: LineCap) -> lyon::tessellation::LineCap { - match line_cap { - LineCap::Butt => lyon::tessellation::LineCap::Butt, - LineCap::Square => lyon::tessellation::LineCap::Square, - LineCap::Round => lyon::tessellation::LineCap::Round, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum LineJoin { - Miter, - Round, - Bevel, -} - -impl Default for LineJoin { - fn default() -> LineJoin { - LineJoin::Miter - } -} - -impl From for lyon::tessellation::LineJoin { - fn from(line_join: LineJoin) -> lyon::tessellation::LineJoin { - match line_join { - LineJoin::Miter => lyon::tessellation::LineJoin::Miter, - LineJoin::Round => lyon::tessellation::LineJoin::Round, - LineJoin::Bevel => lyon::tessellation::LineJoin::Bevel, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub enum Fill { - Color(Color), -} - -impl Default for Fill { - fn default() -> Fill { - Fill::Color(Color::BLACK) - } -} -- cgit From 629153582f1a43516092d941d2b4e2372a6ea054 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 09:24:22 +0100 Subject: Remove `canvas::Data` leftover --- wgpu/src/widget/canvas.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index 1fc3ff01..e8fdc1e8 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -9,12 +9,10 @@ use std::hash::Hash; pub mod layer; pub mod path; -mod data; mod fill; mod frame; mod stroke; -pub use data::Data; pub use fill::Fill; pub use frame::Frame; pub use layer::Layer; -- cgit From 9c067562fa765cfc49d09cd9b12fbba96d5619fa Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 18 Feb 2020 08:48:54 +0100 Subject: Write documentation for new `canvas` module --- wgpu/src/widget/canvas.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'wgpu/src/widget/canvas.rs') diff --git a/wgpu/src/widget/canvas.rs b/wgpu/src/widget/canvas.rs index e8fdc1e8..38c1ce62 100644 --- a/wgpu/src/widget/canvas.rs +++ b/wgpu/src/widget/canvas.rs @@ -1,4 +1,11 @@ -//! Draw freely in 2D. +//! Draw 2D graphics for your users. +//! +//! A [`Canvas`] widget can be used to draw different kinds of 2D shapes in a +//! [`Frame`]. It can be used for animation, data visualization, game graphics, +//! and more! +//! +//! [`Canvas`]: struct.Canvas.html +//! [`Frame`]: struct.Frame.html use crate::{Defaults, Primitive, Renderer}; use iced_native::{ @@ -9,17 +16,26 @@ use std::hash::Hash; pub mod layer; pub mod path; +mod drawable; mod fill; mod frame; mod stroke; +pub use drawable::Drawable; pub use fill::Fill; pub use frame::Frame; pub use layer::Layer; pub use path::Path; pub use stroke::{LineCap, LineJoin, Stroke}; -/// A 2D drawable region. +/// 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 in +/// the same order they are pushed into the [`Canvas`]. +/// +/// [`Canvas`]: struct.Canvas.html +/// [`Layer`]: layer/trait.Layer.html #[derive(Debug)] pub struct Canvas<'a> { width: Length, @@ -30,6 +46,9 @@ pub struct Canvas<'a> { impl<'a> Canvas<'a> { const DEFAULT_SIZE: u16 = 100; + /// Creates a new [`Canvas`] with no layers. + /// + /// [`Canvas`]: struct.Canvas.html pub fn new() -> Self { Canvas { width: Length::Units(Self::DEFAULT_SIZE), @@ -38,16 +57,28 @@ impl<'a> Canvas<'a> { } } + /// Sets the width of the [`Canvas`]. + /// + /// [`Canvas`]: struct.Canvas.html pub fn width(mut self, width: Length) -> Self { self.width = width; self } + /// Sets the height of the [`Canvas`]. + /// + /// [`Canvas`]: struct.Canvas.html pub fn height(mut self, height: Length) -> Self { 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 -- cgit