summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-02-18 08:48:54 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-02-18 08:48:54 +0100
commit9c067562fa765cfc49d09cd9b12fbba96d5619fa (patch)
tree7e0a37c5f2a867ec62260b934af91a7473f7b7bb
parent570f769744aabce2d9d9618feadb47e4b92f50ca (diff)
downloadiced-9c067562fa765cfc49d09cd9b12fbba96d5619fa.tar.gz
iced-9c067562fa765cfc49d09cd9b12fbba96d5619fa.tar.bz2
iced-9c067562fa765cfc49d09cd9b12fbba96d5619fa.zip
Write documentation for new `canvas` module
-rw-r--r--examples/clock/src/main.rs6
-rw-r--r--examples/solar_system/src/main.rs6
-rw-r--r--src/application.rs2
-rw-r--r--wgpu/src/lib.rs2
-rw-r--r--wgpu/src/settings.rs33
-rw-r--r--wgpu/src/triangle.rs2
-rw-r--r--wgpu/src/triangle/msaa.rs5
-rw-r--r--wgpu/src/widget/canvas.rs35
-rw-r--r--wgpu/src/widget/canvas/drawable.rs12
-rw-r--r--wgpu/src/widget/canvas/fill.rs2
-rw-r--r--wgpu/src/widget/canvas/frame.rs51
-rw-r--r--wgpu/src/widget/canvas/layer.rs23
-rw-r--r--wgpu/src/widget/canvas/layer/cache.rs (renamed from wgpu/src/widget/canvas/layer/cached.rs)45
-rw-r--r--wgpu/src/widget/canvas/path.rs168
-rw-r--r--wgpu/src/widget/canvas/path/arc.rs44
-rw-r--r--wgpu/src/widget/canvas/path/builder.rs177
-rw-r--r--wgpu/src/widget/canvas/stroke.rs17
17 files changed, 434 insertions, 196 deletions
diff --git a/examples/clock/src/main.rs b/examples/clock/src/main.rs
index d0995e0c..559f0192 100644
--- a/examples/clock/src/main.rs
+++ b/examples/clock/src/main.rs
@@ -12,7 +12,7 @@ pub fn main() {
struct Clock {
now: LocalTime,
- clock: canvas::layer::Cached<LocalTime>,
+ clock: canvas::layer::Cache<LocalTime>,
}
#[derive(Debug, Clone, Copy)]
@@ -28,7 +28,7 @@ impl Application for Clock {
(
Clock {
now: chrono::Local::now().into(),
- clock: canvas::layer::Cached::new(),
+ clock: canvas::layer::Cache::new(),
},
Command::none(),
)
@@ -91,7 +91,7 @@ impl From<chrono::DateTime<chrono::Local>> for LocalTime {
}
}
-impl canvas::layer::Drawable for LocalTime {
+impl canvas::Drawable for LocalTime {
fn draw(&self, frame: &mut canvas::Frame) {
let center = frame.center();
let radius = frame.width().min(frame.height()) / 2.0;
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs
index 3cabedbb..eee51dc2 100644
--- a/examples/solar_system/src/main.rs
+++ b/examples/solar_system/src/main.rs
@@ -22,7 +22,7 @@ pub fn main() {
struct SolarSystem {
state: State,
- solar_system: canvas::layer::Cached<State>,
+ solar_system: canvas::layer::Cache<State>,
}
#[derive(Debug, Clone, Copy)]
@@ -38,7 +38,7 @@ impl Application for SolarSystem {
(
SolarSystem {
state: State::new(),
- solar_system: canvas::layer::Cached::new(),
+ solar_system: canvas::layer::Cache::new(),
},
Command::none(),
)
@@ -125,7 +125,7 @@ impl State {
}
}
-impl canvas::layer::Drawable for State {
+impl canvas::Drawable for State {
fn draw(&self, frame: &mut canvas::Frame) {
use canvas::{Fill, Path, Stroke};
use std::f32::consts::PI;
diff --git a/src/application.rs b/src/application.rs
index 8a88b55a..a569163b 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -179,7 +179,7 @@ pub trait Application: Sized {
iced_wgpu::Settings {
default_font: _settings.default_font,
antialiasing: if _settings.use_antialiasing {
- Some(iced_wgpu::settings::MSAA::X4)
+ Some(iced_wgpu::settings::Antialiasing::MSAAx4)
} else {
None
},
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 90d28353..4f2b732d 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -19,7 +19,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/settings.rs b/wgpu/src/settings.rs
index c8a0cadf..65853ce2 100644
--- a/wgpu/src/settings.rs
+++ b/wgpu/src/settings.rs
@@ -1,6 +1,10 @@
+//! Configure a [`Renderer`].
+//!
+//! [`Renderer`]: struct.Renderer.html
+
/// The settings of a [`Renderer`].
///
-/// [`Renderer`]: struct.Renderer.html
+/// [`Renderer`]: ../struct.Renderer.html
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Settings {
/// The bytes of the font that will be used by default.
@@ -9,24 +13,29 @@ pub struct Settings {
pub default_font: Option<&'static [u8]>,
/// The antialiasing strategy that will be used for triangle primitives.
- pub antialiasing: Option<MSAA>,
+ pub antialiasing: Option<Antialiasing>,
}
+/// An antialiasing strategy.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum MSAA {
- X2,
- X4,
- X8,
- X16,
+pub enum Antialiasing {
+ /// Multisample AA with 2 samples
+ MSAAx2,
+ /// Multisample AA with 4 samples
+ MSAAx4,
+ /// Multisample AA with 8 samples
+ MSAAx8,
+ /// Multisample AA with 16 samples
+ MSAAx16,
}
-impl MSAA {
+impl Antialiasing {
pub(crate) fn sample_count(&self) -> u32 {
match self {
- MSAA::X2 => 2,
- MSAA::X4 => 4,
- MSAA::X8 => 8,
- MSAA::X16 => 16,
+ Antialiasing::MSAAx2 => 2,
+ Antialiasing::MSAAx4 => 4,
+ Antialiasing::MSAAx8 => 8,
+ Antialiasing::MSAAx16 => 16,
}
}
}
diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs
index 9159b0a2..d149eebc 100644
--- a/wgpu/src/triangle.rs
+++ b/wgpu/src/triangle.rs
@@ -61,7 +61,7 @@ impl<T> Buffer<T> {
impl Pipeline {
pub fn new(
device: &mut wgpu::Device,
- antialiasing: Option<settings::MSAA>,
+ antialiasing: Option<settings::Antialiasing>,
) -> Pipeline {
let constant_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
diff --git a/wgpu/src/triangle/msaa.rs b/wgpu/src/triangle/msaa.rs
index 93fbe49b..0def5352 100644
--- a/wgpu/src/triangle/msaa.rs
+++ b/wgpu/src/triangle/msaa.rs
@@ -10,7 +10,10 @@ pub struct Blit {
}
impl Blit {
- pub fn new(device: &wgpu::Device, antialiasing: settings::MSAA) -> Blit {
+ pub fn new(
+ device: &wgpu::Device,
+ antialiasing: settings::Antialiasing,
+ ) -> Blit {
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
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
diff --git a/wgpu/src/widget/canvas/drawable.rs b/wgpu/src/widget/canvas/drawable.rs
new file mode 100644
index 00000000..6c74071c
--- /dev/null
+++ b/wgpu/src/widget/canvas/drawable.rs
@@ -0,0 +1,12 @@
+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);
+}
diff --git a/wgpu/src/widget/canvas/fill.rs b/wgpu/src/widget/canvas/fill.rs
index 9c23f997..5ce24cf3 100644
--- a/wgpu/src/widget/canvas/fill.rs
+++ b/wgpu/src/widget/canvas/fill.rs
@@ -1,7 +1,9 @@
use iced_native::Color;
+/// The style used to fill geometry.
#[derive(Debug, Clone, Copy)]
pub enum Fill {
+ /// Fill with a color.
Color(Color),
}
diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs
index 27d676d6..fa6d8c0a 100644
--- a/wgpu/src/widget/canvas/frame.rs
+++ b/wgpu/src/widget/canvas/frame.rs
@@ -5,12 +5,14 @@ use crate::{
triangle,
};
+/// The frame of a [`Canvas`].
+///
+/// [`Canvas`]: struct.Canvas.html
#[derive(Debug)]
pub struct Frame {
width: f32,
height: f32,
buffers: lyon::tessellation::VertexBuffers<triangle::Vertex2D, u32>,
-
transforms: Transforms,
}
@@ -27,6 +29,12 @@ struct Transform {
}
impl Frame {
+ /// Creates a new empty [`Frame`] with the given dimensions.
+ ///
+ /// The default coordinate system of a [`Frame`] has its origin at the
+ /// top-left corner of its bounds.
+ ///
+ /// [`Frame`]: struct.Frame.html
pub fn new(width: f32, height: f32) -> Frame {
Frame {
width,
@@ -42,26 +50,43 @@ impl Frame {
}
}
+ /// Returns the width of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn width(&self) -> f32 {
self.width
}
+ /// Returns the width of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn height(&self) -> f32 {
self.height
}
+ /// Returns the dimensions of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn size(&self) -> Size {
Size::new(self.width, self.height)
}
+ /// Returns the coordinate of the center of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn center(&self) -> Point {
Point::new(self.width / 2.0, self.height / 2.0)
}
+ /// Draws the given [`Path`] on the [`Frame`] by filling it with the
+ /// provided style.
+ ///
+ /// [`Path`]: path/struct.Path.html
+ /// [`Frame`]: struct.Frame.html
pub fn fill(&mut self, path: &Path, fill: Fill) {
use lyon::tessellation::{
BuffersBuilder, FillOptions, FillTessellator,
@@ -95,6 +120,11 @@ impl Frame {
let _ = result.expect("Tessellate path");
}
+ /// Draws the stroke of the given [`Path`] on the [`Frame`] with the
+ /// provided style.
+ ///
+ /// [`Path`]: path/struct.Path.html
+ /// [`Frame`]: struct.Frame.html
pub fn stroke(&mut self, path: &Path, stroke: Stroke) {
use lyon::tessellation::{
BuffersBuilder, StrokeOptions, StrokeTessellator,
@@ -124,6 +154,13 @@ impl Frame {
let _ = result.expect("Stroke path");
}
+ /// Stores the current transform of the [`Frame`] and executes the given
+ /// drawing operations, restoring the transform afterwards.
+ ///
+ /// This method is useful to compose transforms and perform drawing
+ /// operations in different coordinate systems.
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) {
self.transforms.previous.push(self.transforms.current);
@@ -133,6 +170,9 @@ impl Frame {
self.transforms.current = self.transforms.previous.pop().unwrap();
}
+ /// Applies a translation to the current transform of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn translate(&mut self, translation: Vector) {
self.transforms.current.raw = self
@@ -146,6 +186,9 @@ impl Frame {
self.transforms.current.is_identity = false;
}
+ /// Applies a rotation to the current transform of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn rotate(&mut self, angle: f32) {
self.transforms.current.raw = self
@@ -156,6 +199,9 @@ impl Frame {
self.transforms.current.is_identity = false;
}
+ /// Applies a scaling to the current transform of the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
#[inline]
pub fn scale(&mut self, scale: f32) {
self.transforms.current.raw =
@@ -163,6 +209,9 @@ impl Frame {
self.transforms.current.is_identity = false;
}
+ /// Produces the geometry that has been drawn on the [`Frame`].
+ ///
+ /// [`Frame`]: struct.Frame.html
pub fn into_mesh(self) -> triangle::Mesh2D {
triangle::Mesh2D {
vertices: self.buffers.vertices,
diff --git a/wgpu/src/widget/canvas/layer.rs b/wgpu/src/widget/canvas/layer.rs
index 8c069f18..82d647bb 100644
--- a/wgpu/src/widget/canvas/layer.rs
+++ b/wgpu/src/widget/canvas/layer.rs
@@ -1,16 +1,25 @@
-mod cached;
+//! Produce, store, and reuse geometry.
+mod cache;
-pub use cached::Cached;
+pub use cache::Cache;
-use crate::{canvas::Frame, triangle};
+use crate::triangle;
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 [`Mesh2D`] as a
+ /// result.
+ ///
+ /// The [`Layer`] may choose to store the produced [`Mesh2D`] locally and
+ /// only recompute it when the bounds change, its contents change, or is
+ /// otherwise explicitly cleared by other means.
+ ///
+ /// [`Layer`]: trait.Layer.html
+ /// [`Mesh2D`]: ../../../triangle/struct.Mesh2D.html
fn draw(&self, bounds: Size) -> Arc<triangle::Mesh2D>;
}
-
-pub trait Drawable {
- fn draw(&self, frame: &mut Frame);
-}
diff --git a/wgpu/src/widget/canvas/layer/cached.rs b/wgpu/src/widget/canvas/layer/cache.rs
index c6741372..3071cce0 100644
--- a/wgpu/src/widget/canvas/layer/cached.rs
+++ b/wgpu/src/widget/canvas/layer/cache.rs
@@ -1,5 +1,5 @@
use crate::{
- canvas::{layer::Drawable, Frame, Layer},
+ canvas::{Drawable, Frame, Layer},
triangle,
};
@@ -8,14 +8,21 @@ use std::cell::RefCell;
use std::marker::PhantomData;
use std::sync::Arc;
+/// 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
+/// [`Cached`]: struct.Cached.html
#[derive(Debug)]
-pub struct Cached<T: Drawable> {
+pub struct Cache<T: Drawable> {
input: PhantomData<T>,
- cache: RefCell<Cache>,
+ state: RefCell<State>,
}
#[derive(Debug)]
-enum Cache {
+enum State {
Empty,
Filled {
mesh: Arc<triangle::Mesh2D>,
@@ -23,24 +30,36 @@ enum Cache {
},
}
-impl<T> Cached<T>
+impl<T> Cache<T>
where
T: Drawable + std::fmt::Debug,
{
+ /// Creates a new empty [`Cache`].
+ ///
+ /// [`Cache`]: struct.Cache.html
pub fn new() -> Self {
- Cached {
+ Cache {
input: PhantomData,
- cache: RefCell::new(Cache::Empty),
+ state: RefCell::new(State::Empty),
}
}
+ /// Clears the cache, forcing a redraw the next time it is used.
+ ///
+ /// [`Cached`]: struct.Cached.html
pub fn clear(&mut self) {
- *self.cache.borrow_mut() = Cache::Empty;
+ *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>(&'a self, input: &'a T) -> impl Layer + 'a {
Bind {
- layer: self,
+ cache: self,
input: input,
}
}
@@ -48,7 +67,7 @@ where
#[derive(Debug)]
struct Bind<'a, T: Drawable> {
- layer: &'a Cached<T>,
+ cache: &'a Cache<T>,
input: &'a T,
}
@@ -59,8 +78,8 @@ where
fn draw(&self, current_bounds: Size) -> Arc<triangle::Mesh2D> {
use std::ops::Deref;
- if let Cache::Filled { mesh, bounds } =
- self.layer.cache.borrow().deref()
+ if let State::Filled { mesh, bounds } =
+ self.cache.state.borrow().deref()
{
if *bounds == current_bounds {
return mesh.clone();
@@ -72,7 +91,7 @@ where
let mesh = Arc::new(frame.into_mesh());
- *self.layer.cache.borrow_mut() = Cache::Filled {
+ *self.cache.state.borrow_mut() = State::Filled {
mesh: mesh.clone(),
bounds: current_bounds,
};
diff --git a/wgpu/src/widget/canvas/path.rs b/wgpu/src/widget/canvas/path.rs
index b70d0aef..15c2e853 100644
--- a/wgpu/src/widget/canvas/path.rs
+++ b/wgpu/src/widget/canvas/path.rs
@@ -1,13 +1,28 @@
-use iced_native::{Point, Size, Vector};
+//! Build different kinds of 2D shapes.
+pub mod arc;
-use lyon::path::builder::{Build, FlatPathBuilder, PathBuilder, SvgBuilder};
+mod builder;
+pub use arc::Arc;
+pub use builder::Builder;
+
+/// An immutable set of points that may or may not be connected.
+///
+/// A single [`Path`] can represent different kinds of 2D shapes!
+///
+/// [`Path`]: struct.Path.html
#[derive(Debug, Clone)]
pub struct Path {
raw: lyon::path::Path,
}
impl Path {
+ /// Creates a new [`Path`] with the provided closure.
+ ///
+ /// Use the [`Builder`] to configure your [`Path`].
+ ///
+ /// [`Path`]: struct.Path.html
+ /// [`Builder`]: struct.Builder.html
pub fn new(f: impl FnOnce(&mut Builder)) -> Self {
let mut builder = Builder::new();
@@ -32,152 +47,3 @@ impl Path {
}
}
}
-
-#[allow(missing_debug_implementations)]
-pub struct Builder {
- raw: lyon::path::builder::SvgPathBuilder<lyon::path::Builder>,
-}
-
-impl Builder {
- pub fn new() -> Builder {
- Builder {
- raw: lyon::path::Path::builder().with_svg(),
- }
- }
-
- #[inline]
- pub fn move_to(&mut self, point: Point) {
- let _ = self.raw.move_to(lyon::math::Point::new(point.x, point.y));
- }
-
- #[inline]
- pub fn line_to(&mut self, point: Point) {
- let _ = self.raw.line_to(lyon::math::Point::new(point.x, point.y));
- }
-
- #[inline]
- pub fn arc(&mut self, arc: Arc) {
- self.ellipse(arc.into());
- }
-
- pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) {
- use lyon::{math, path};
-
- let a = math::Point::new(a.x, a.y);
-
- if self.raw.current_position() != a {
- let _ = self.raw.line_to(a);
- }
-
- let _ = self.raw.arc_to(
- math::Vector::new(radius, radius),
- math::Angle::radians(0.0),
- path::ArcFlags::default(),
- math::Point::new(b.x, b.y),
- );
- }
-
- pub fn ellipse(&mut self, ellipse: Ellipse) {
- use lyon::{geom, math};
-
- let arc = geom::Arc {
- center: math::Point::new(ellipse.center.x, ellipse.center.y),
- radii: math::Vector::new(ellipse.radii.x, ellipse.radii.y),
- x_rotation: math::Angle::radians(ellipse.rotation),
- start_angle: math::Angle::radians(ellipse.start_angle),
- sweep_angle: math::Angle::radians(ellipse.end_angle),
- };
-
- let _ = self.raw.move_to(arc.sample(0.0));
-
- arc.for_each_quadratic_bezier(&mut |curve| {
- let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to);
- });
- }
-
- #[inline]
- pub fn bezier_curve_to(
- &mut self,
- control_a: Point,
- control_b: Point,
- to: Point,
- ) {
- use lyon::math;
-
- let _ = self.raw.cubic_bezier_to(
- math::Point::new(control_a.x, control_a.y),
- math::Point::new(control_b.x, control_b.y),
- math::Point::new(to.x, to.y),
- );
- }
-
- #[inline]
- pub fn quadratic_curve_to(&mut self, control: Point, to: Point) {
- use lyon::math;
-
- let _ = self.raw.quadratic_bezier_to(
- math::Point::new(control.x, control.y),
- math::Point::new(to.x, to.y),
- );
- }
-
- #[inline]
- pub fn rectangle(&mut self, p: Point, size: Size) {
- self.move_to(p);
- self.line_to(Point::new(p.x + size.width, p.y));
- self.line_to(Point::new(p.x + size.width, p.y + size.height));
- self.line_to(Point::new(p.x, p.y + size.height));
- self.close();
- }
-
- #[inline]
- pub fn circle(&mut self, center: Point, radius: f32) {
- self.arc(Arc {
- center,
- radius,
- start_angle: 0.0,
- end_angle: 2.0 * std::f32::consts::PI,
- });
- }
-
- #[inline]
- pub fn close(&mut self) {
- self.raw.close()
- }
-
- #[inline]
- pub fn build(self) -> Path {
- Path {
- raw: self.raw.build(),
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Arc {
- pub center: Point,
- pub radius: f32,
- pub start_angle: f32,
- pub end_angle: f32,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Ellipse {
- pub center: Point,
- pub radii: Vector,
- pub rotation: f32,
- pub start_angle: f32,
- pub end_angle: f32,
-}
-
-impl From<Arc> for Ellipse {
- fn from(arc: Arc) -> Ellipse {
- Ellipse {
- center: arc.center,
- radii: Vector::new(arc.radius, arc.radius),
- rotation: 0.0,
- start_angle: arc.start_angle,
- end_angle: arc.end_angle,
- }
- }
-}
diff --git a/wgpu/src/widget/canvas/path/arc.rs b/wgpu/src/widget/canvas/path/arc.rs
new file mode 100644
index 00000000..343191f1
--- /dev/null
+++ b/wgpu/src/widget/canvas/path/arc.rs
@@ -0,0 +1,44 @@
+//! Build and draw curves.
+use iced_native::{Point, Vector};
+
+/// A segment of a differentiable curve.
+#[derive(Debug, Clone, Copy)]
+pub struct Arc {
+ /// The center of the arc.
+ pub center: Point,
+ /// The radius of the arc.
+ pub radius: f32,
+ /// The start of the segment's angle, clockwise rotation.
+ pub start_angle: f32,
+ /// The end of the segment's angle, clockwise rotation.
+ pub end_angle: f32,
+}
+
+/// An elliptical [`Arc`].
+///
+/// [`Arc`]: struct.Arc.html
+#[derive(Debug, Clone, Copy)]
+pub struct Elliptical {
+ /// The center of the arc.
+ pub center: Point,
+ /// The radii of the arc's ellipse, defining its axes.
+ pub radii: Vector,
+ /// The rotation of the arc's ellipse.
+ pub rotation: f32,
+ /// The start of the segment's angle, clockwise rotation.
+ pub start_angle: f32,
+ /// The end of the segment's angle, clockwise rotation.
+ pub end_angle: f32,
+}
+
+impl From<Arc> for Elliptical {
+ fn from(arc: Arc) -> Elliptical {
+ Elliptical {
+ center: arc.center,
+ radii: Vector::new(arc.radius, arc.radius),
+ rotation: 0.0,
+ start_angle: arc.start_angle,
+ end_angle: arc.end_angle,
+ }
+ }
+}
diff --git a/wgpu/src/widget/canvas/path/builder.rs b/wgpu/src/widget/canvas/path/builder.rs
new file mode 100644
index 00000000..a013149e
--- /dev/null
+++ b/wgpu/src/widget/canvas/path/builder.rs
@@ -0,0 +1,177 @@
+use crate::canvas::path::{arc, Arc, Path};
+
+use iced_native::{Point, Size};
+use lyon::path::builder::{Build, FlatPathBuilder, PathBuilder, SvgBuilder};
+
+/// A [`Path`] builder.
+///
+/// Once a [`Path`] is built, it can no longer be mutated.
+///
+/// [`Path`]: struct.Path.html
+#[allow(missing_debug_implementations)]
+pub struct Builder {
+ raw: lyon::path::builder::SvgPathBuilder<lyon::path::Builder>,
+}
+
+impl Builder {
+ /// Creates a new [`Builder`].
+ ///
+ /// [`Builder`]: struct.Builder.html
+ pub fn new() -> Builder {
+ Builder {
+ raw: lyon::path::Path::builder().with_svg(),
+ }
+ }
+
+ /// Moves the starting point of a new sub-path to the given `Point`.
+ #[inline]
+ pub fn move_to(&mut self, point: Point) {
+ let _ = self.raw.move_to(lyon::math::Point::new(point.x, point.y));
+ }
+
+ /// Connects the last point in the [`Path`] to the given `Point` with a
+ /// straight line.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn line_to(&mut self, point: Point) {
+ let _ = self.raw.line_to(lyon::math::Point::new(point.x, point.y));
+ }
+
+ /// Adds an [`Arc`] to the [`Path`] from `start_angle` to `end_angle` in
+ /// a clockwise direction.
+ ///
+ /// [`Arc`]: struct.Arc.html
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn arc(&mut self, arc: Arc) {
+ self.ellipse(arc.into());
+ }
+
+ /// Adds a circular arc to the [`Path`] with the given control points and
+ /// radius.
+ ///
+ /// The arc is connected to the previous point by a straight line, if
+ /// necessary.
+ ///
+ /// [`Path`]: struct.Path.html
+ pub fn arc_to(&mut self, a: Point, b: Point, radius: f32) {
+ use lyon::{math, path};
+
+ let a = math::Point::new(a.x, a.y);
+
+ if self.raw.current_position() != a {
+ let _ = self.raw.line_to(a);
+ }
+
+ let _ = self.raw.arc_to(
+ math::Vector::new(radius, radius),
+ math::Angle::radians(0.0),
+ path::ArcFlags::default(),
+ math::Point::new(b.x, b.y),
+ );
+ }
+
+ /// Adds an [`Ellipse`] to the [`Path`] using a clockwise direction.
+ ///
+ /// [`Ellipse`]: struct.Arc.html
+ /// [`Path`]: struct.Path.html
+ pub fn ellipse(&mut self, arc: arc::Elliptical) {
+ use lyon::{geom, math};
+
+ let arc = geom::Arc {
+ center: math::Point::new(arc.center.x, arc.center.y),
+ radii: math::Vector::new(arc.radii.x, arc.radii.y),
+ x_rotation: math::Angle::radians(arc.rotation),
+ start_angle: math::Angle::radians(arc.start_angle),
+ sweep_angle: math::Angle::radians(arc.end_angle),
+ };
+
+ let _ = self.raw.move_to(arc.sample(0.0));
+
+ arc.for_each_quadratic_bezier(&mut |curve| {
+ let _ = self.raw.quadratic_bezier_to(curve.ctrl, curve.to);
+ });
+ }
+
+ /// Adds a cubic Bézier curve to the [`Path`] given its two control points
+ /// and its end point.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn bezier_curve_to(
+ &mut self,
+ control_a: Point,
+ control_b: Point,
+ to: Point,
+ ) {
+ use lyon::math;
+
+ let _ = self.raw.cubic_bezier_to(
+ math::Point::new(control_a.x, control_a.y),
+ math::Point::new(control_b.x, control_b.y),
+ math::Point::new(to.x, to.y),
+ );
+ }
+
+ /// Adds a quadratic Bézier curve to the [`Path`] given its control point
+ /// and its end point.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn quadratic_curve_to(&mut self, control: Point, to: Point) {
+ use lyon::math;
+
+ let _ = self.raw.quadratic_bezier_to(
+ math::Point::new(control.x, control.y),
+ math::Point::new(to.x, to.y),
+ );
+ }
+
+ /// Adds a rectangle to the [`Path`] given its top-left corner coordinate
+ /// and its `Size`.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn rectangle(&mut self, p: Point, size: Size) {
+ self.move_to(p);
+ self.line_to(Point::new(p.x + size.width, p.y));
+ self.line_to(Point::new(p.x + size.width, p.y + size.height));
+ self.line_to(Point::new(p.x, p.y + size.height));
+ self.close();
+ }
+
+ /// Adds a circle to the [`Path`] given its center coordinate and its
+ /// radius.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn circle(&mut self, center: Point, radius: f32) {
+ self.arc(Arc {
+ center,
+ radius,
+ start_angle: 0.0,
+ end_angle: 2.0 * std::f32::consts::PI,
+ });
+ }
+
+ /// Closes the current sub-path in the [`Path`] with a straight line to
+ /// the starting point.
+ ///
+ /// [`Path`]: struct.Path.html
+ #[inline]
+ pub fn close(&mut self) {
+ self.raw.close()
+ }
+
+ /// Builds the [`Path`] of this [`Builder`].
+ ///
+ /// [`Path`]: struct.Path.html
+ /// [`Builder`]: struct.Builder.html
+ #[inline]
+ pub fn build(self) -> Path {
+ Path {
+ raw: self.raw.build(),
+ }
+ }
+}
diff --git a/wgpu/src/widget/canvas/stroke.rs b/wgpu/src/widget/canvas/stroke.rs
index 9bb260b2..46d669c4 100644
--- a/wgpu/src/widget/canvas/stroke.rs
+++ b/wgpu/src/widget/canvas/stroke.rs
@@ -1,10 +1,16 @@
use iced_native::Color;
+/// The style of a stroke.
#[derive(Debug, Clone, Copy)]
pub struct Stroke {
+ /// The color of the stroke.
pub color: Color,
+ /// The distance between the two edges of the stroke.
pub width: f32,
+ /// The shape to be used at the end of open subpaths when they are stroked.
pub line_cap: LineCap,
+ /// The shape to be used at the corners of paths or basic shapes when they
+ /// are stroked.
pub line_join: LineJoin,
}
@@ -19,10 +25,16 @@ impl Default for Stroke {
}
}
+/// The shape used at the end of open subpaths when they are stroked.
#[derive(Debug, Clone, Copy)]
pub enum LineCap {
+ /// The stroke for each sub-path does not extend beyond its two endpoints.
Butt,
+ /// At the end of each sub-path, the shape representing the stroke will be
+ /// extended by a square.
Square,
+ /// At the end of each sub-path, the shape representing the stroke will be
+ /// extended by a semicircle.
Round,
}
@@ -42,10 +54,15 @@ impl From<LineCap> for lyon::tessellation::LineCap {
}
}
+/// The shape used at the corners of paths or basic shapes when they are
+/// stroked.
#[derive(Debug, Clone, Copy)]
pub enum LineJoin {
+ /// A sharp corner.
Miter,
+ /// A round corner.
Round,
+ /// A bevelled corner.
Bevel,
}