Write documentation for the new canvas API

This commit is contained in:
Héctor Ramón Jiménez 2020-04-30 07:38:46 +02:00
parent 1501a93915
commit d4c4198f72
8 changed files with 122 additions and 17 deletions

View File

@ -20,7 +20,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)]

View File

@ -48,12 +48,15 @@ pub use text::Text;
/// ///
/// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock /// - [`clock`], an application that uses the [`Canvas`] widget to draw a clock
/// and its hands to display the current time. /// and its hands to display the current time.
/// - [`game_of_life`], an interactive version of the Game of Life, invented by
/// John Conway.
/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget /// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget
/// and showcasing how to compose different transforms. /// and showcasing how to compose different transforms.
/// ///
/// [examples]: https://github.com/hecrj/iced/tree/0.1/examples /// [examples]: https://github.com/hecrj/iced/tree/master/examples
/// [`clock`]: https://github.com/hecrj/iced/tree/0.1/examples/clock /// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock
/// [`solar_system`]: https://github.com/hecrj/iced/tree/0.1/examples/solar_system /// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life
/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system
/// ///
/// ## Drawing a simple circle /// ## Drawing a simple circle
/// If you want to get a quick overview, here's how we can draw a simple circle: /// If you want to get a quick overview, here's how we can draw a simple circle:
@ -89,7 +92,7 @@ pub use text::Text;
/// } /// }
/// } /// }
/// ///
/// // Finally, we simply use our `Cache` to create the `Canvas`! /// // Finally, we simply use our `Circle` to create the `Canvas`!
/// let canvas = Canvas::new(Circle { radius: 50.0 }); /// let canvas = Canvas::new(Circle { radius: 50.0 });
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]

View File

@ -19,13 +19,14 @@ impl Default for State {
State::Empty 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 /// A [`Cache`] will not redraw its geometry unless the dimensions of its layer
/// change or it is explicitly cleared. /// change or it is explicitly cleared.
/// ///
/// [`Layer`]: ../trait.Layer.html /// [`Layer`]: ../trait.Layer.html
/// [`Cache`]: struct.Cache.html /// [`Cache`]: struct.Cache.html
/// [`Geometry`]: struct.Geometry.html
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Cache { pub struct Cache {
state: RefCell<State>, state: RefCell<State>,
@ -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) { pub fn clear(&mut self) {
*self.state.borrow_mut() = State::Empty; *self.state.borrow_mut() = State::Empty;
} }
pub fn draw( /// Draws [`Geometry`] using the provided closure and stores it in the
&self, /// [`Cache`].
new_bounds: Size, ///
draw_fn: impl Fn(&mut Frame), /// The closure will only be called when
) -> Geometry { /// - 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; 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 { return Geometry::from_primitive(Primitive::Cached {
cache: primitive.clone(), cache: primitive.clone(),
}); });
} }
} }
let mut frame = Frame::new(new_bounds); let mut frame = Frame::new(bounds);
draw_fn(&mut frame); draw_fn(&mut frame);
let primitive = { let primitive = {
@ -74,7 +86,7 @@ impl Cache {
}; };
*self.state.borrow_mut() = State::Filled { *self.state.borrow_mut() = State::Filled {
bounds: new_bounds, bounds,
primitive: primitive.clone(), primitive: primitive.clone(),
}; };

View File

@ -1,8 +1,12 @@
use iced_native::{Point, Rectangle}; use iced_native::{Point, Rectangle};
/// The mouse cursor state.
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Cursor { pub enum Cursor {
/// The cursor has a defined position.
Available(Point), Available(Point),
/// The cursor is currently unavailable (i.e. out of bounds or busy).
Unavailable, 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<Point> { pub fn position(&self) -> Option<Point> {
match self { match self {
Cursor::Available(position) => Some(*position), 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<Point> { pub fn position_in(&self, bounds: &Rectangle) -> Option<Point> {
if self.is_over(bounds) { if self.is_over(bounds) {
self.position_from(bounds.position()) 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<Point> { pub fn position_from(&self, origin: Point) -> Option<Point> {
match self { match self {
Cursor::Available(position) => { 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 { pub fn is_over(&self, bounds: &Rectangle) -> bool {
match self { match self {
Cursor::Available(position) => bounds.contains(*position), Cursor::Available(position) => bounds.contains(*position),

View File

@ -1,6 +1,10 @@
use iced_native::mouse; use iced_native::mouse;
/// A [`Canvas`] event.
///
/// [`Canvas`]: struct.Event.html
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Event { pub enum Event {
/// A mouse event.
Mouse(mouse::Event), Mouse(mouse::Event),
} }

View File

@ -1,5 +1,13 @@
use crate::Primitive; 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)] #[derive(Debug, Clone)]
pub struct Geometry(Primitive); pub struct Geometry(Primitive);
@ -8,6 +16,12 @@ impl Geometry {
Self(primitive) 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 { pub fn into_primitive(self) -> Primitive {
self.0 self.0
} }

View File

@ -1,7 +1,27 @@
use crate::canvas::{Cursor, Event, Geometry}; use crate::canvas::{Cursor, Event, Geometry};
use iced_native::{MouseCursor, Rectangle}; 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<Message> { pub trait Program<Message> {
/// 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( fn update(
&mut self, &mut self,
_event: Event, _event: Event,
@ -11,8 +31,24 @@ pub trait Program<Message> {
None 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<Geometry>; fn draw(&self, bounds: Rectangle, cursor: Cursor) -> Vec<Geometry>;
/// 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 { fn mouse_cursor(&self, _bounds: Rectangle, _cursor: Cursor) -> MouseCursor {
MouseCursor::default() MouseCursor::default()
} }

View File

@ -15,18 +15,32 @@ pub struct Stroke {
} }
impl Stroke { impl Stroke {
/// Sets the color of the [`Stroke`].
///
/// [`Stroke`]: struct.Stroke.html
pub fn with_color(self, color: Color) -> Stroke { pub fn with_color(self, color: Color) -> Stroke {
Stroke { color, ..self } Stroke { color, ..self }
} }
/// Sets the width of the [`Stroke`].
///
/// [`Stroke`]: struct.Stroke.html
pub fn with_width(self, width: f32) -> Stroke { pub fn with_width(self, width: f32) -> Stroke {
Stroke { width, ..self } 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 { pub fn with_line_cap(self, line_cap: LineCap) -> Stroke {
Stroke { line_cap, ..self } 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 { pub fn with_line_join(self, line_join: LineJoin) -> Stroke {
Stroke { line_join, ..self } Stroke { line_join, ..self }
} }