Write documentation for new `canvas` module
This commit is contained in:
parent
570f769744
commit
9c067562fa
|
@ -12,7 +12,7 @@ pub fn main() {
|
||||||
|
|
||||||
struct Clock {
|
struct Clock {
|
||||||
now: LocalTime,
|
now: LocalTime,
|
||||||
clock: canvas::layer::Cached<LocalTime>,
|
clock: canvas::layer::Cache<LocalTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -28,7 +28,7 @@ impl Application for Clock {
|
||||||
(
|
(
|
||||||
Clock {
|
Clock {
|
||||||
now: chrono::Local::now().into(),
|
now: chrono::Local::now().into(),
|
||||||
clock: canvas::layer::Cached::new(),
|
clock: canvas::layer::Cache::new(),
|
||||||
},
|
},
|
||||||
Command::none(),
|
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) {
|
fn draw(&self, frame: &mut canvas::Frame) {
|
||||||
let center = frame.center();
|
let center = frame.center();
|
||||||
let radius = frame.width().min(frame.height()) / 2.0;
|
let radius = frame.width().min(frame.height()) / 2.0;
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub fn main() {
|
||||||
|
|
||||||
struct SolarSystem {
|
struct SolarSystem {
|
||||||
state: State,
|
state: State,
|
||||||
solar_system: canvas::layer::Cached<State>,
|
solar_system: canvas::layer::Cache<State>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -38,7 +38,7 @@ impl Application for SolarSystem {
|
||||||
(
|
(
|
||||||
SolarSystem {
|
SolarSystem {
|
||||||
state: State::new(),
|
state: State::new(),
|
||||||
solar_system: canvas::layer::Cached::new(),
|
solar_system: canvas::layer::Cache::new(),
|
||||||
},
|
},
|
||||||
Command::none(),
|
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) {
|
fn draw(&self, frame: &mut canvas::Frame) {
|
||||||
use canvas::{Fill, Path, Stroke};
|
use canvas::{Fill, Path, Stroke};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
|
@ -179,7 +179,7 @@ pub trait Application: Sized {
|
||||||
iced_wgpu::Settings {
|
iced_wgpu::Settings {
|
||||||
default_font: _settings.default_font,
|
default_font: _settings.default_font,
|
||||||
antialiasing: if _settings.use_antialiasing {
|
antialiasing: if _settings.use_antialiasing {
|
||||||
Some(iced_wgpu::settings::MSAA::X4)
|
Some(iced_wgpu::settings::Antialiasing::MSAAx4)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||||
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
|
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
|
||||||
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
|
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
|
||||||
//#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(missing_debug_implementations)]
|
||||||
#![deny(unused_results)]
|
#![deny(unused_results)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
//! Configure a [`Renderer`].
|
||||||
|
//!
|
||||||
|
//! [`Renderer`]: struct.Renderer.html
|
||||||
|
|
||||||
/// The settings of a [`Renderer`].
|
/// The settings of a [`Renderer`].
|
||||||
///
|
///
|
||||||
/// [`Renderer`]: struct.Renderer.html
|
/// [`Renderer`]: ../struct.Renderer.html
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
/// The bytes of the font that will be used by default.
|
/// The bytes of the font that will be used by default.
|
||||||
|
@ -9,24 +13,29 @@ pub struct Settings {
|
||||||
pub default_font: Option<&'static [u8]>,
|
pub default_font: Option<&'static [u8]>,
|
||||||
|
|
||||||
/// The antialiasing strategy that will be used for triangle primitives.
|
/// 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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum MSAA {
|
pub enum Antialiasing {
|
||||||
X2,
|
/// Multisample AA with 2 samples
|
||||||
X4,
|
MSAAx2,
|
||||||
X8,
|
/// Multisample AA with 4 samples
|
||||||
X16,
|
MSAAx4,
|
||||||
|
/// Multisample AA with 8 samples
|
||||||
|
MSAAx8,
|
||||||
|
/// Multisample AA with 16 samples
|
||||||
|
MSAAx16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MSAA {
|
impl Antialiasing {
|
||||||
pub(crate) fn sample_count(&self) -> u32 {
|
pub(crate) fn sample_count(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
MSAA::X2 => 2,
|
Antialiasing::MSAAx2 => 2,
|
||||||
MSAA::X4 => 4,
|
Antialiasing::MSAAx4 => 4,
|
||||||
MSAA::X8 => 8,
|
Antialiasing::MSAAx8 => 8,
|
||||||
MSAA::X16 => 16,
|
Antialiasing::MSAAx16 => 16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl<T> Buffer<T> {
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: &mut wgpu::Device,
|
device: &mut wgpu::Device,
|
||||||
antialiasing: Option<settings::MSAA>,
|
antialiasing: Option<settings::Antialiasing>,
|
||||||
) -> Pipeline {
|
) -> Pipeline {
|
||||||
let constant_layout =
|
let constant_layout =
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
|
|
@ -10,7 +10,10 @@ pub struct Blit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
|
|
|
@ -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 crate::{Defaults, Primitive, Renderer};
|
||||||
|
|
||||||
use iced_native::{
|
use iced_native::{
|
||||||
|
@ -9,17 +16,26 @@ use std::hash::Hash;
|
||||||
pub mod layer;
|
pub mod layer;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
|
||||||
|
mod drawable;
|
||||||
mod fill;
|
mod fill;
|
||||||
mod frame;
|
mod frame;
|
||||||
mod stroke;
|
mod stroke;
|
||||||
|
|
||||||
|
pub use drawable::Drawable;
|
||||||
pub use fill::Fill;
|
pub use fill::Fill;
|
||||||
pub use frame::Frame;
|
pub use frame::Frame;
|
||||||
pub use layer::Layer;
|
pub use layer::Layer;
|
||||||
pub use path::Path;
|
pub use path::Path;
|
||||||
pub use stroke::{LineCap, LineJoin, Stroke};
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Canvas<'a> {
|
pub struct Canvas<'a> {
|
||||||
width: Length,
|
width: Length,
|
||||||
|
@ -30,6 +46,9 @@ pub struct Canvas<'a> {
|
||||||
impl<'a> Canvas<'a> {
|
impl<'a> Canvas<'a> {
|
||||||
const DEFAULT_SIZE: u16 = 100;
|
const DEFAULT_SIZE: u16 = 100;
|
||||||
|
|
||||||
|
/// Creates a new [`Canvas`] with no layers.
|
||||||
|
///
|
||||||
|
/// [`Canvas`]: struct.Canvas.html
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Canvas {
|
Canvas {
|
||||||
width: Length::Units(Self::DEFAULT_SIZE),
|
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 {
|
pub fn width(mut self, width: Length) -> Self {
|
||||||
self.width = width;
|
self.width = width;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the height of the [`Canvas`].
|
||||||
|
///
|
||||||
|
/// [`Canvas`]: struct.Canvas.html
|
||||||
pub fn height(mut self, height: Length) -> Self {
|
pub fn height(mut self, height: Length) -> Self {
|
||||||
self.height = height;
|
self.height = height;
|
||||||
self
|
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 {
|
pub fn push(mut self, layer: impl Layer + 'a) -> Self {
|
||||||
self.layers.push(Box::new(layer));
|
self.layers.push(Box::new(layer));
|
||||||
self
|
self
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
use iced_native::Color;
|
use iced_native::Color;
|
||||||
|
|
||||||
|
/// The style used to fill geometry.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Fill {
|
pub enum Fill {
|
||||||
|
/// Fill with a color.
|
||||||
Color(Color),
|
Color(Color),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,14 @@ use crate::{
|
||||||
triangle,
|
triangle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The frame of a [`Canvas`].
|
||||||
|
///
|
||||||
|
/// [`Canvas`]: struct.Canvas.html
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
width: f32,
|
width: f32,
|
||||||
height: f32,
|
height: f32,
|
||||||
buffers: lyon::tessellation::VertexBuffers<triangle::Vertex2D, u32>,
|
buffers: lyon::tessellation::VertexBuffers<triangle::Vertex2D, u32>,
|
||||||
|
|
||||||
transforms: Transforms,
|
transforms: Transforms,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +29,12 @@ struct Transform {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
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 {
|
pub fn new(width: f32, height: f32) -> Frame {
|
||||||
Frame {
|
Frame {
|
||||||
width,
|
width,
|
||||||
|
@ -42,26 +50,43 @@ impl Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the width of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn width(&self) -> f32 {
|
pub fn width(&self) -> f32 {
|
||||||
self.width
|
self.width
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the width of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn height(&self) -> f32 {
|
pub fn height(&self) -> f32 {
|
||||||
self.height
|
self.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the dimensions of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> Size {
|
pub fn size(&self) -> Size {
|
||||||
Size::new(self.width, self.height)
|
Size::new(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the coordinate of the center of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn center(&self) -> Point {
|
pub fn center(&self) -> Point {
|
||||||
Point::new(self.width / 2.0, self.height / 2.0)
|
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) {
|
pub fn fill(&mut self, path: &Path, fill: Fill) {
|
||||||
use lyon::tessellation::{
|
use lyon::tessellation::{
|
||||||
BuffersBuilder, FillOptions, FillTessellator,
|
BuffersBuilder, FillOptions, FillTessellator,
|
||||||
|
@ -95,6 +120,11 @@ impl Frame {
|
||||||
let _ = result.expect("Tessellate path");
|
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) {
|
pub fn stroke(&mut self, path: &Path, stroke: Stroke) {
|
||||||
use lyon::tessellation::{
|
use lyon::tessellation::{
|
||||||
BuffersBuilder, StrokeOptions, StrokeTessellator,
|
BuffersBuilder, StrokeOptions, StrokeTessellator,
|
||||||
|
@ -124,6 +154,13 @@ impl Frame {
|
||||||
let _ = result.expect("Stroke path");
|
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]
|
#[inline]
|
||||||
pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) {
|
pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) {
|
||||||
self.transforms.previous.push(self.transforms.current);
|
self.transforms.previous.push(self.transforms.current);
|
||||||
|
@ -133,6 +170,9 @@ impl Frame {
|
||||||
self.transforms.current = self.transforms.previous.pop().unwrap();
|
self.transforms.current = self.transforms.previous.pop().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies a translation to the current transform of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn translate(&mut self, translation: Vector) {
|
pub fn translate(&mut self, translation: Vector) {
|
||||||
self.transforms.current.raw = self
|
self.transforms.current.raw = self
|
||||||
|
@ -146,6 +186,9 @@ impl Frame {
|
||||||
self.transforms.current.is_identity = false;
|
self.transforms.current.is_identity = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies a rotation to the current transform of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn rotate(&mut self, angle: f32) {
|
pub fn rotate(&mut self, angle: f32) {
|
||||||
self.transforms.current.raw = self
|
self.transforms.current.raw = self
|
||||||
|
@ -156,6 +199,9 @@ impl Frame {
|
||||||
self.transforms.current.is_identity = false;
|
self.transforms.current.is_identity = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies a scaling to the current transform of the [`Frame`].
|
||||||
|
///
|
||||||
|
/// [`Frame`]: struct.Frame.html
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale(&mut self, scale: f32) {
|
pub fn scale(&mut self, scale: f32) {
|
||||||
self.transforms.current.raw =
|
self.transforms.current.raw =
|
||||||
|
@ -163,6 +209,9 @@ impl Frame {
|
||||||
self.transforms.current.is_identity = false;
|
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 {
|
pub fn into_mesh(self) -> triangle::Mesh2D {
|
||||||
triangle::Mesh2D {
|
triangle::Mesh2D {
|
||||||
vertices: self.buffers.vertices,
|
vertices: self.buffers.vertices,
|
||||||
|
|
|
@ -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 iced_native::Size;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// A layer that can be presented at a [`Canvas`].
|
||||||
|
///
|
||||||
|
/// [`Canvas`]: ../struct.Canvas.html
|
||||||
pub trait Layer: std::fmt::Debug {
|
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>;
|
fn draw(&self, bounds: Size) -> Arc<triangle::Mesh2D>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Drawable {
|
|
||||||
fn draw(&self, frame: &mut Frame);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
canvas::{layer::Drawable, Frame, Layer},
|
canvas::{Drawable, Frame, Layer},
|
||||||
triangle,
|
triangle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,14 +8,21 @@ use std::cell::RefCell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Cached<T: Drawable> {
|
pub struct Cache<T: Drawable> {
|
||||||
input: PhantomData<T>,
|
input: PhantomData<T>,
|
||||||
cache: RefCell<Cache>,
|
state: RefCell<State>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Cache {
|
enum State {
|
||||||
Empty,
|
Empty,
|
||||||
Filled {
|
Filled {
|
||||||
mesh: Arc<triangle::Mesh2D>,
|
mesh: Arc<triangle::Mesh2D>,
|
||||||
|
@ -23,24 +30,36 @@ enum Cache {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Cached<T>
|
impl<T> Cache<T>
|
||||||
where
|
where
|
||||||
T: Drawable + std::fmt::Debug,
|
T: Drawable + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
|
/// Creates a new empty [`Cache`].
|
||||||
|
///
|
||||||
|
/// [`Cache`]: struct.Cache.html
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Cached {
|
Cache {
|
||||||
input: PhantomData,
|
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) {
|
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 {
|
pub fn with<'a>(&'a self, input: &'a T) -> impl Layer + 'a {
|
||||||
Bind {
|
Bind {
|
||||||
layer: self,
|
cache: self,
|
||||||
input: input,
|
input: input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +67,7 @@ where
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Bind<'a, T: Drawable> {
|
struct Bind<'a, T: Drawable> {
|
||||||
layer: &'a Cached<T>,
|
cache: &'a Cache<T>,
|
||||||
input: &'a T,
|
input: &'a T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +78,8 @@ where
|
||||||
fn draw(&self, current_bounds: Size) -> Arc<triangle::Mesh2D> {
|
fn draw(&self, current_bounds: Size) -> Arc<triangle::Mesh2D> {
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
if let Cache::Filled { mesh, bounds } =
|
if let State::Filled { mesh, bounds } =
|
||||||
self.layer.cache.borrow().deref()
|
self.cache.state.borrow().deref()
|
||||||
{
|
{
|
||||||
if *bounds == current_bounds {
|
if *bounds == current_bounds {
|
||||||
return mesh.clone();
|
return mesh.clone();
|
||||||
|
@ -72,7 +91,7 @@ where
|
||||||
|
|
||||||
let mesh = Arc::new(frame.into_mesh());
|
let mesh = Arc::new(frame.into_mesh());
|
||||||
|
|
||||||
*self.layer.cache.borrow_mut() = Cache::Filled {
|
*self.cache.state.borrow_mut() = State::Filled {
|
||||||
mesh: mesh.clone(),
|
mesh: mesh.clone(),
|
||||||
bounds: current_bounds,
|
bounds: current_bounds,
|
||||||
};
|
};
|
|
@ -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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
raw: lyon::path::Path,
|
raw: lyon::path::Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 {
|
pub fn new(f: impl FnOnce(&mut Builder)) -> Self {
|
||||||
let mut builder = Builder::new();
|
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,16 @@
|
||||||
use iced_native::Color;
|
use iced_native::Color;
|
||||||
|
|
||||||
|
/// The style of a stroke.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Stroke {
|
pub struct Stroke {
|
||||||
|
/// The color of the stroke.
|
||||||
pub color: Color,
|
pub color: Color,
|
||||||
|
/// The distance between the two edges of the stroke.
|
||||||
pub width: f32,
|
pub width: f32,
|
||||||
|
/// The shape to be used at the end of open subpaths when they are stroked.
|
||||||
pub line_cap: LineCap,
|
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,
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum LineCap {
|
pub enum LineCap {
|
||||||
|
/// The stroke for each sub-path does not extend beyond its two endpoints.
|
||||||
Butt,
|
Butt,
|
||||||
|
/// At the end of each sub-path, the shape representing the stroke will be
|
||||||
|
/// extended by a square.
|
||||||
Square,
|
Square,
|
||||||
|
/// At the end of each sub-path, the shape representing the stroke will be
|
||||||
|
/// extended by a semicircle.
|
||||||
Round,
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum LineJoin {
|
pub enum LineJoin {
|
||||||
|
/// A sharp corner.
|
||||||
Miter,
|
Miter,
|
||||||
|
/// A round corner.
|
||||||
Round,
|
Round,
|
||||||
|
/// A bevelled corner.
|
||||||
Bevel,
|
Bevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue