summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-11-22 19:36:57 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2019-11-22 19:36:57 +0100
commita7dba612f03e58d7bd9527499d893987986b347c (patch)
treeb8c3d8f997b714aa368bd6eaecf14065f7645c77
parentba56a561b254c9a5f3d23cb54d23dc311759ab4c (diff)
downloadiced-a7dba612f03e58d7bd9527499d893987986b347c.tar.gz
iced-a7dba612f03e58d7bd9527499d893987986b347c.tar.bz2
iced-a7dba612f03e58d7bd9527499d893987986b347c.zip
Write docs for `iced` and `iced_native`
-rw-r--r--core/src/align.rs8
-rw-r--r--core/src/command.rs2
-rw-r--r--core/src/lib.rs2
-rw-r--r--native/src/element.rs64
-rw-r--r--native/src/input/mouse/event.rs8
-rw-r--r--native/src/layout.rs16
-rw-r--r--native/src/layout/flex.rs24
-rw-r--r--native/src/layout/limits.rs53
-rw-r--r--native/src/layout/node.rs23
-rw-r--r--native/src/lib.rs172
-rw-r--r--native/src/renderer.rs12
-rw-r--r--native/src/renderer/null.rs1
-rw-r--r--native/src/renderer/windowed.rs19
-rw-r--r--native/src/size.rs14
-rw-r--r--native/src/widget.rs9
-rw-r--r--native/src/widget/checkbox.rs9
-rw-r--r--native/src/widget/column.rs17
-rw-r--r--native/src/widget/container.rs1
-rw-r--r--native/src/widget/image.rs3
-rw-r--r--native/src/widget/radio.rs7
-rw-r--r--native/src/widget/row.rs17
-rw-r--r--native/src/widget/scrollable.rs24
-rw-r--r--native/src/widget/slider.rs25
-rw-r--r--native/src/widget/text.rs11
-rw-r--r--native/src/widget/text_input.rs60
-rw-r--r--src/application.rs129
-rw-r--r--src/lib.rs181
-rw-r--r--src/native.rs62
-rw-r--r--src/sandbox.rs114
-rw-r--r--web/src/widget/text.rs4
30 files changed, 877 insertions, 214 deletions
diff --git a/core/src/align.rs b/core/src/align.rs
index 8b571db4..05bd5e63 100644
--- a/core/src/align.rs
+++ b/core/src/align.rs
@@ -1,10 +1,4 @@
-/// Alignment on the cross axis of a container.
-///
-/// * On a [`Column`], it describes __horizontal__ alignment.
-/// * On a [`Row`], it describes __vertical__ alignment.
-///
-/// [`Column`]: widget/struct.Column.html
-/// [`Row`]: widget/struct.Row.html
+/// Alignment on an unspecified axis of a container.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Align {
/// Align at the start of the cross axis.
diff --git a/core/src/command.rs b/core/src/command.rs
index 698105aa..14b48b5b 100644
--- a/core/src/command.rs
+++ b/core/src/command.rs
@@ -2,7 +2,7 @@ use futures::future::{BoxFuture, Future, FutureExt};
/// A collection of async operations.
///
-/// You should be able to turn a future easily into a [`Command`], eiter by
+/// You should be able to turn a future easily into a [`Command`], either by
/// using the `From` trait or [`Command::perform`].
///
/// [`Command`]: struct.Command.html
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 5a608fe8..6c36e683 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -4,6 +4,8 @@
//! different runtime implementations. For instance, both [`iced_native`] and
//! [`iced_web`] are built on top of `iced_core`.
//!
+//! ![`iced_core` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/core.png?raw=true)
+//!
//! [Iced]: https://github.com/hecrj/iced
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
//! [`iced_web`]: https://github.com/hecrj/iced/tree/master/web
diff --git a/native/src/element.rs b/native/src/element.rs
index 3bf24317..5335fdc1 100644
--- a/native/src/element.rs
+++ b/native/src/element.rs
@@ -33,31 +33,6 @@ where
}
}
- pub fn width(&self) -> Length {
- self.widget.width()
- }
-
- pub fn height(&self) -> Length {
- self.widget.height()
- }
-
- pub fn layout(
- &self,
- renderer: &Renderer,
- limits: &layout::Limits,
- ) -> layout::Node {
- self.widget.layout(renderer, limits)
- }
-
- pub fn draw(
- &self,
- renderer: &mut Renderer,
- layout: Layout<'_>,
- cursor_position: Point,
- ) -> Renderer::Output {
- self.widget.draw(renderer, layout, cursor_position)
- }
-
/// Applies a transformation to the produced message of the [`Element`].
///
/// This method is useful when you want to decouple different parts of your
@@ -225,6 +200,45 @@ where
}
}
+ /// Returns the width of the [`Element`].
+ ///
+ /// [`Element`]: struct.Element.html
+ pub fn width(&self) -> Length {
+ self.widget.width()
+ }
+
+ /// Returns the height of the [`Element`].
+ ///
+ /// [`Element`]: struct.Element.html
+ pub fn height(&self) -> Length {
+ self.widget.height()
+ }
+
+ /// Computes the layout of the [`Element`] in the given [`Limits`].
+ ///
+ /// [`Element`]: struct.Element.html
+ /// [`Limits`]: layout/struct.Limits.html
+ pub fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.widget.layout(renderer, limits)
+ }
+
+ /// Draws the [`Element`] and its children using the given [`Layout`].
+ ///
+ /// [`Element`]: struct.Element.html
+ /// [`Layout`]: layout/struct.Layout.html
+ pub fn draw(
+ &self,
+ renderer: &mut Renderer,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ ) -> Renderer::Output {
+ self.widget.draw(renderer, layout, cursor_position)
+ }
+
pub(crate) fn hash_layout(&self, state: &mut Hasher) {
self.widget.hash_layout(state);
}
diff --git a/native/src/input/mouse/event.rs b/native/src/input/mouse/event.rs
index 478f9b4d..aafc4fe3 100644
--- a/native/src/input/mouse/event.rs
+++ b/native/src/input/mouse/event.rs
@@ -34,11 +34,16 @@ pub enum Event {
},
/// The mouse wheel was scrolled.
- WheelScrolled { delta: ScrollDelta },
+ WheelScrolled {
+ /// The scroll movement.
+ delta: ScrollDelta,
+ },
}
+/// A scroll movement.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ScrollDelta {
+ /// A line-based scroll movement
Lines {
/// The number of horizontal lines scrolled
x: f32,
@@ -46,6 +51,7 @@ pub enum ScrollDelta {
/// The number of vertical lines scrolled
y: f32,
},
+ /// A pixel-based scroll movement
Pixels {
/// The number of horizontal pixels scrolled
x: f32,
diff --git a/native/src/layout.rs b/native/src/layout.rs
index 0a744346..e945706b 100644
--- a/native/src/layout.rs
+++ b/native/src/layout.rs
@@ -1,3 +1,4 @@
+//! Position your widgets properly.
mod limits;
mod node;
@@ -8,6 +9,9 @@ pub use node::Node;
use crate::{Point, Rectangle, Vector};
+/// The bounds of a [`Node`] and its children, using absolute coordinates.
+///
+/// [`Node`]: struct.Node.html
#[derive(Debug, Clone, Copy)]
pub struct Layout<'a> {
position: Point,
@@ -28,6 +32,14 @@ impl<'a> Layout<'a> {
}
}
+ /// Gets the bounds of the [`Layout`].
+ ///
+ /// The returned [`Rectangle`] describes the position and size of a
+ /// [`Node`].
+ ///
+ /// [`Layout`]: struct.Layout.html
+ /// [`Rectangle`]: struct.Rectangle.html
+ /// [`Node`]: struct.Node.html
pub fn bounds(&self) -> Rectangle {
let bounds = self.node.bounds();
@@ -39,6 +51,10 @@ impl<'a> Layout<'a> {
}
}
+ /// Returns an iterator over the [`Layout`] of the children of a [`Node`].
+ ///
+ /// [`Layout`]: struct.Layout.html
+ /// [`Node`]: struct.Node.html
pub fn children(&'a self) -> impl Iterator<Item = Layout<'a>> {
self.node.children().iter().map(move |node| {
Layout::with_offset(
diff --git a/native/src/layout/flex.rs b/native/src/layout/flex.rs
index 7a2b0d70..bc90553e 100644
--- a/native/src/layout/flex.rs
+++ b/native/src/layout/flex.rs
@@ -1,3 +1,4 @@
+//! Distribute elements using a flex-based layout.
// This code is heavily inspired by the [`druid`] codebase.
//
// [`druid`]: https://github.com/xi-editor/druid
@@ -20,9 +21,13 @@ use crate::{
Align, Element, Size,
};
+/// The main axis of a flex layout.
#[derive(Debug)]
pub enum Axis {
+ /// The horizontal axis
Horizontal,
+
+ /// The vertical axis
Vertical,
}
@@ -49,7 +54,12 @@ impl Axis {
}
}
-// TODO: Remove `Message` type parameter
+/// Computes the flex layout with the given axis and limits, applying spacing,
+/// padding and alignment to the items as needed.
+///
+/// It returns a new layout [`Node`].
+///
+/// [`Node`]: ../struct.Node.html
pub fn resolve<Message, Renderer>(
axis: Axis,
renderer: &Renderer,
@@ -57,7 +67,7 @@ pub fn resolve<Message, Renderer>(
padding: f32,
spacing: f32,
align_items: Align,
- children: &[Element<'_, Message, Renderer>],
+ items: &[Element<'_, Message, Renderer>],
) -> Node
where
Renderer: crate::Renderer,
@@ -65,14 +75,14 @@ where
let limits = limits.pad(padding);
let mut total_non_fill =
- spacing as f32 * (children.len() as i32 - 1).max(0) as f32;
+ spacing as f32 * (items.len() as i32 - 1).max(0) as f32;
let mut fill_sum = 0;
let mut cross = axis.cross(limits.min());
- let mut nodes: Vec<Node> = Vec::with_capacity(children.len());
- nodes.resize(children.len(), Node::default());
+ let mut nodes: Vec<Node> = Vec::with_capacity(items.len());
+ nodes.resize(items.len(), Node::default());
- for (i, child) in children.iter().enumerate() {
+ for (i, child) in items.iter().enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.width(),
Axis::Vertical => child.height(),
@@ -97,7 +107,7 @@ where
let available = axis.main(limits.max());
let remaining = (available - total_non_fill).max(0.0);
- for (i, child) in children.iter().enumerate() {
+ for (i, child) in items.iter().enumerate() {
let fill_factor = match axis {
Axis::Horizontal => child.width(),
Axis::Vertical => child.height(),
diff --git a/native/src/layout/limits.rs b/native/src/layout/limits.rs
index af269acd..2705a47d 100644
--- a/native/src/layout/limits.rs
+++ b/native/src/layout/limits.rs
@@ -1,5 +1,6 @@
use crate::{Length, Size};
+/// A set of size constraints for layouting.
#[derive(Debug, Clone, Copy)]
pub struct Limits {
min: Size,
@@ -8,12 +9,17 @@ pub struct Limits {
}
impl Limits {
+ /// No limits
pub const NONE: Limits = Limits {
min: Size::ZERO,
max: Size::INFINITY,
fill: Size::INFINITY,
};
+ /// Creates new [`Limits`] with the given minimum and maximum [`Size`].
+ ///
+ /// [`Limits`]: struct.Limits.html
+ /// [`Size`]: ../struct.Size.html
pub fn new(min: Size, max: Size) -> Limits {
Limits {
min,
@@ -22,14 +28,25 @@ impl Limits {
}
}
+ /// Returns the minimum [`Size`] of the [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
+ /// [`Size`]: ../struct.Size.html
pub fn min(&self) -> Size {
self.min
}
+ /// Returns the maximum [`Size`] of the [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
+ /// [`Size`]: ../struct.Size.html
pub fn max(&self) -> Size {
self.max
}
+ /// Applies a width constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn width(mut self, width: Length) -> Limits {
match width {
Length::Shrink => {
@@ -51,6 +68,9 @@ impl Limits {
self
}
+ /// Applies a height constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn height(mut self, height: Length) -> Limits {
match height {
Length::Shrink => {
@@ -72,6 +92,9 @@ impl Limits {
self
}
+ /// Applies a minimum width constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn min_width(mut self, min_width: u32) -> Limits {
self.min.width =
self.min.width.max(min_width as f32).min(self.max.width);
@@ -79,6 +102,9 @@ impl Limits {
self
}
+ /// Applies a maximum width constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn max_width(mut self, max_width: u32) -> Limits {
self.max.width =
self.max.width.min(max_width as f32).max(self.min.width);
@@ -86,6 +112,19 @@ impl Limits {
self
}
+ /// Applies a minimum height constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
+ pub fn min_height(mut self, min_height: u32) -> Limits {
+ self.min.height =
+ self.min.height.max(min_height as f32).min(self.max.height);
+
+ self
+ }
+
+ /// Applies a maximum height constraint to the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn max_height(mut self, max_height: u32) -> Limits {
self.max.height =
self.max.height.min(max_height as f32).max(self.min.height);
@@ -93,10 +132,17 @@ impl Limits {
self
}
+ /// Shrinks the current [`Limits`] to account for the given padding.
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn pad(&self, padding: f32) -> Limits {
self.shrink(Size::new(padding * 2.0, padding * 2.0))
}
+ /// Shrinks the current [`Limits`] by the given [`Size`].
+ ///
+ /// [`Limits`]: struct.Limits.html
+ /// [`Size`]: ../struct.Size.html
pub fn shrink(&self, size: Size) -> Limits {
let min = Size::new(
(self.min().width - size.width).max(0.0),
@@ -116,6 +162,9 @@ impl Limits {
Limits { min, max, fill }
}
+ /// Removes the minimum width constraint for the current [`Limits`].
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn loose(&self) -> Limits {
Limits {
min: Size::ZERO,
@@ -124,6 +173,10 @@ impl Limits {
}
}
+ /// Computes the resulting [`Size`] that fits the [`Limits`] given the
+ /// intrinsic size of some content.
+ ///
+ /// [`Limits`]: struct.Limits.html
pub fn resolve(&self, intrinsic_size: Size) -> Size {
Size::new(
intrinsic_size
diff --git a/native/src/layout/node.rs b/native/src/layout/node.rs
index 64ebf2d0..ed1cd3da 100644
--- a/native/src/layout/node.rs
+++ b/native/src/layout/node.rs
@@ -1,16 +1,25 @@
use crate::{Align, Rectangle, Size};
+/// The bounds of an element and its children.
#[derive(Debug, Clone, Default)]
pub struct Node {
- pub bounds: Rectangle,
+ pub(crate) bounds: Rectangle,
children: Vec<Node>,
}
impl Node {
+ /// Creates a new [`Node`] with the given [`Size`].
+ ///
+ /// [`Node`]: struct.Node.html
+ /// [`Size`]: ../struct.Size.html
pub fn new(size: Size) -> Self {
Self::with_children(size, Vec::new())
}
+ /// Creates a new [`Node`] with the given [`Size`] and children.
+ ///
+ /// [`Node`]: struct.Node.html
+ /// [`Size`]: ../struct.Size.html
pub fn with_children(size: Size, children: Vec<Node>) -> Self {
Node {
bounds: Rectangle {
@@ -23,19 +32,29 @@ impl Node {
}
}
+ /// Returns the [`Size`] of the [`Node`].
+ ///
+ /// [`Node`]: struct.Node.html
+ /// [`Size`]: ../struct.Size.html
pub fn size(&self) -> Size {
Size::new(self.bounds.width, self.bounds.height)
}
+ /// Returns the bounds of the [`Node`].
+ ///
+ /// [`Node`]: struct.Node.html
pub fn bounds(&self) -> Rectangle {
self.bounds
}
+ /// Returns the children of the [`Node`].
+ ///
+ /// [`Node`]: struct.Node.html
pub fn children(&self) -> &[Node] {
&self.children
}
- pub fn align(
+ pub(crate) fn align(
&mut self,
horizontal_alignment: Align,
vertical_alignment: Align,
diff --git a/native/src/lib.rs b/native/src/lib.rs
index 55331ba5..57d014b6 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -1,162 +1,34 @@
-//! Iced is a renderer-agnostic GUI library focused on simplicity and
-//! type-safety. Inspired by [Elm].
+//! A renderer-agnostic native GUI runtime.
//!
-//! # Features
-//! * Simple, easy-to-use, renderer-agnostic API
-//! * Responsive, flexbox-based layouting
-//! * Type-safe, reactive programming model
-//! * Built-in widgets
-//! * Custom widget support
+//! ![`iced_native` crate graph](https://github.com/hecrj/iced/blob/cae26cb7bc627f4a5b3bcf1cd023a0c552e8c65e/docs/graphs/native.png?raw=true)
//!
-//! Check out the [repository] and the [examples] for more details!
+//! `iced_native` takes [`iced_core`] and builds a native runtime on top of it,
+//! featuring:
//!
-//! [examples]: https://github.com/hecrj/iced/tree/0.1.0/examples
-//! [repository]: https://github.com/hecrj/iced
+//! - A custom layout engine, greatly inspired by [`druid`]
+//! - Event handling for all the built-in widgets
+//! - A renderer-agnostic API
//!
-//! # Usage
-//! Inspired by [The Elm Architecture], Iced expects you to split user
-//! interfaces into four different concepts:
-//!
-//! * __State__ — the state of your application
-//! * __Messages__ — user interactions or meaningful events that you care
-//! about
-//! * __View logic__ — a way to display your __state__ as widgets that
-//! may produce __messages__ on user interaction
-//! * __Update logic__ — a way to react to __messages__ and update your
-//! __state__
-//!
-//! We can build something to see how this works! Let's say we want a simple
-//! counter that can be incremented and decremented using two buttons.
-//!
-//! We start by modelling the __state__ of our application:
-//!
-//! ```
-//! use iced_native::button;
-//!
-//! struct Counter {
-//! // The counter value
-//! value: i32,
-//!
-//! // The local state of the two buttons
-//! increment_button: button::State,
-//! decrement_button: button::State,
-//! }
-//! ```
-//!
-//! Next, we need to define the possible user interactions of our counter:
-//! the button presses. These interactions are our __messages__:
-//!
-//! ```
-//! #[derive(Debug, Clone, Copy)]
-//! pub enum Message {
-//! IncrementPressed,
-//! DecrementPressed,
-//! }
-//! ```
+//! To achieve this, it introduces a bunch of reusable interfaces:
//!
-//! Now, let's show the actual counter by putting it all together in our
-//! __view logic__:
-//!
-//! ```
-//! # use iced_native::button;
-//! #
-//! # struct Counter {
-//! # // The counter value
-//! # value: i32,
-//! #
-//! # // The local state of the two buttons
-//! # increment_button: button::State,
-//! # decrement_button: button::State,
-//! # }
-//! #
-//! # #[derive(Debug, Clone, Copy)]
-//! # pub enum Message {
-//! # IncrementPressed,
-//! # DecrementPressed,
-//! # }
-//! #
-//! # mod iced_wgpu {
-//! # pub use iced_native::renderer::Null as Renderer;
-//! # }
-//! use iced_native::{Button, Column, Text};
-//! use iced_wgpu::Renderer; // Iced does not include a renderer! We need to bring our own!
-//!
-//! impl Counter {
-//! pub fn view(&mut self) -> Column<Message, Renderer> {
-//! // We use a column: a simple vertical layout
-//! Column::new()
-//! .push(
-//! // The increment button. We tell it to produce an
-//! // `IncrementPressed` message when pressed
-//! Button::new(&mut self.increment_button, Text::new("+"))
-//! .on_press(Message::IncrementPressed),
-//! )
-//! .push(
-//! // We show the value of the counter here
-//! Text::new(&self.value.to_string()).size(50),
-//! )
-//! .push(
-//! // The decrement button. We tell it to produce a
-//! // `DecrementPressed` message when pressed
-//! Button::new(&mut self.decrement_button, Text::new("-"))
-//! .on_press(Message::DecrementPressed),
-//! )
-//! }
-//! }
-//! ```
-//!
-//! Finally, we need to be able to react to any produced __messages__ and change
-//! our __state__ accordingly in our __update logic__:
-//!
-//! ```
-//! # use iced_native::button;
-//! #
-//! # struct Counter {
-//! # // The counter value
-//! # value: i32,
-//! #
-//! # // The local state of the two buttons
-//! # increment_button: button::State,
-//! # decrement_button: button::State,
-//! # }
-//! #
-//! # #[derive(Debug, Clone, Copy)]
-//! # pub enum Message {
-//! # IncrementPressed,
-//! # DecrementPressed,
-//! # }
-//! impl Counter {
-//! // ...
-//!
-//! pub fn update(&mut self, message: Message) {
-//! match message {
-//! Message::IncrementPressed => {
-//! self.value += 1;
-//! }
-//! Message::DecrementPressed => {
-//! self.value -= 1;
-//! }
-//! }
-//! }
-//! }
-//! ```
-//!
-//! And that's everything! We just wrote a whole user interface. Iced is now
-//! able to:
-//!
-//! 1. Take the result of our __view logic__ and layout its widgets.
-//! 1. Process events from our system and produce __messages__ for our
-//! __update logic__.
-//! 1. Draw the resulting user interface using our chosen __renderer__.
+//! - A [`Widget`] trait, which is used to implement new widgets: from layout
+//! requirements to event and drawing logic.
+//! - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic.
+//! - A [`Windowed`] trait, leveraging [`raw-window-handle`], which can be
+//! implemented by graphical renderers that target _windows_. Window-based
+//! shells (like [`iced_winit`]) can use this trait to stay renderer-agnostic.
//!
+//! # Usage
//! Check out the [`UserInterface`] type to learn how to wire everything up!
//!
-//! [Elm]: https://elm-lang.org/
-//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
-//! [documentation]: https://docs.rs/iced
-//! [examples]: https://github.com/hecrj/iced/tree/master/examples
+//! [`iced_core`]: https://github.com/hecrj/iced/tree/master/core
+//! [`iced_winit`]: https://github.com/hecrj/iced/tree/master/winit
+//! [`druid`]: https://github.com/xi-editor/druid
+//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
+//! [`Widget`]: widget/trait.Widget.html
+//! [`Windowed`]: renderer/trait.Windowed.html
//! [`UserInterface`]: struct.UserInterface.html
-//#![deny(missing_docs)]
+#![deny(missing_docs)]
//#![deny(missing_debug_implementations)]
#![deny(unused_results)]
#![deny(unsafe_code)]
diff --git a/native/src/renderer.rs b/native/src/renderer.rs
index 3e19be33..7a68ada4 100644
--- a/native/src/renderer.rs
+++ b/native/src/renderer.rs
@@ -32,9 +32,21 @@ pub use windowed::{Target, Windowed};
use crate::{layout, Element};
+/// A component that can take the state of a user interface and produce an
+/// output for its users.
pub trait Renderer: Sized {
+ /// The type of output of the [`Renderer`].
+ ///
+ /// If you are implementing a graphical renderer, your output will most
+ /// likely be a tree of visual primitives.
+ ///
+ /// [`Renderer`]: trait.Renderer.html
type Output;
+ /// Lays out the elements of a user interface.
+ ///
+ /// You should override this if you need to perform any operations before or
+ /// after layouting. For instance, trimming the measurements cache.
fn layout<'a, Message>(
&mut self,
element: &Element<'a, Message, Self>,
diff --git a/native/src/renderer/null.rs b/native/src/renderer/null.rs
index 8933b09b..3334e6b6 100644
--- a/native/src/renderer/null.rs
+++ b/native/src/renderer/null.rs
@@ -4,6 +4,7 @@ use crate::{
Rectangle, Renderer, Size, VerticalAlignment,
};
+/// A renderer that does nothing.
pub struct Null;
impl Renderer for Null {
diff --git a/native/src/renderer/windowed.rs b/native/src/renderer/windowed.rs
index 6d0419d2..813a03f2 100644
--- a/native/src/renderer/windowed.rs
+++ b/native/src/renderer/windowed.rs
@@ -2,11 +2,21 @@ use crate::MouseCursor;
use raw_window_handle::HasRawWindowHandle;
+/// A renderer that can target windows.
pub trait Windowed: super::Renderer + Sized {
+ /// The type of target.
type Target: Target<Renderer = Self>;
+ /// Creates a new [`Windowed`] renderer.
+ ///
+ /// [`Windowed`]: trait.Windowed.html
fn new() -> Self;
+ /// Performs the drawing operations described in the output on the given
+ /// target.
+ ///
+ /// The overlay can be a bunch of debug text logs. It should be rendered on
+ /// top of the GUI on most scenarios.
fn draw<T: AsRef<str>>(
&mut self,
output: &Self::Output,
@@ -15,9 +25,15 @@ pub trait Windowed: super::Renderer + Sized {
) -> MouseCursor;
}
+/// A rendering target.
pub trait Target {
+ /// The renderer of this target.
type Renderer;
+ /// Creates a new rendering [`Target`] from the given window handle, width,
+ /// height and dpi factor.
+ ///
+ /// [`Target`]: trait.Target.html
fn new<W: HasRawWindowHandle>(
window: &W,
width: u16,
@@ -26,6 +42,9 @@ pub trait Target {
renderer: &Self::Renderer,
) -> Self;
+ /// Resizes the current [`Target`].
+ ///
+ /// [`Target`]: trait.Target.html
fn resize(
&mut self,
width: u16,
diff --git a/native/src/size.rs b/native/src/size.rs
index bd909292..30e2a57e 100644
--- a/native/src/size.rs
+++ b/native/src/size.rs
@@ -1,5 +1,6 @@
use std::f32;
+/// An amount of space in 2 dimensions.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Size {
/// The width.
@@ -9,13 +10,26 @@ pub struct Size {
}
impl Size {
+ /// A [`Size`] with zero width and height.
+ ///
+ /// [`Size`]: struct.Size.html
pub const ZERO: Size = Size::new(0., 0.);
+
+ /// A [`Size`] with infinite width and height.
+ ///
+ /// [`Size`]: struct.Size.html
pub const INFINITY: Size = Size::new(f32::INFINITY, f32::INFINITY);
+ /// A [`Size`] of infinite width and height.
+ ///
+ /// [`Size`]: struct.Size.html
pub const fn new(width: f32, height: f32) -> Self {
Size { width, height }
}
+ /// Increments the [`Size`] to account for the given padding.
+ ///
+ /// [`Size`]: struct.Size.html
pub fn pad(&self, padding: f32) -> Self {
Size {
width: self.width + padding * 2.0,
diff --git a/native/src/widget.rs b/native/src/widget.rs
index 61b66c5b..48605ee3 100644
--- a/native/src/widget.rs
+++ b/native/src/widget.rs
@@ -23,6 +23,7 @@
pub mod button;
pub mod checkbox;
pub mod column;
+pub mod container;
pub mod image;
pub mod radio;
pub mod row;
@@ -31,8 +32,6 @@ pub mod slider;
pub mod text;
pub mod text_input;
-mod container;
-
#[doc(no_inline)]
pub use button::Button;
#[doc(no_inline)]
@@ -69,8 +68,14 @@ pub trait Widget<Message, Renderer>
where
Renderer: crate::Renderer,
{
+ /// Returns the width of the [`Widget`].
+ ///
+ /// [`Widget`]: trait.Widget.html
fn width(&self) -> Length;
+ /// Returns the height of the [`Widget`].
+ ///
+ /// [`Widget`]: trait.Widget.html
fn height(&self) -> Length;
/// Returns the [`Node`] of the [`Widget`].
diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs
index f7bda146..8101e6be 100644
--- a/native/src/widget/checkbox.rs
+++ b/native/src/widget/checkbox.rs
@@ -166,15 +166,18 @@ where
/// [`Checkbox`]: struct.Checkbox.html
/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer {
+ /// Returns the default size of a [`Checkbox`].
+ ///
+ /// [`Checkbox`]: struct.Checkbox.html
fn default_size(&self) -> u32;
/// Draws a [`Checkbox`].
///
/// It receives:
- /// * the current cursor position
/// * the bounds of the [`Checkbox`]
- /// * the bounds of the label of the [`Checkbox`]
- /// * whether the [`Checkbox`] is checked or not
+ /// * whether the [`Checkbox`] is selected or not
+ /// * whether the mouse is over the [`Checkbox`] or not
+ /// * the drawn label of the [`Checkbox`]
///
/// [`Checkbox`]: struct.Checkbox.html
fn draw(
diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs
index 87c51f48..281437fd 100644
--- a/native/src/widget/column.rs
+++ b/native/src/widget/column.rs
@@ -1,3 +1,4 @@
+//! Distribute content vertically.
use std::hash::Hash;
use crate::{
@@ -189,7 +190,23 @@ where
}
}
+/// The renderer of a [`Column`].
+///
+/// Your [renderer] will need to implement this trait before being
+/// able to use a [`Column`] in your user interface.
+///
+/// [`Column`]: struct.Column.html
+/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer + Sized {
+ /// Draws a [`Column`].
+ ///
+ /// It receives:
+ /// - the children of the [`Column`]
+ /// - the [`Layout`] of the [`Column`] and its children
+ /// - the cursor position
+ ///
+ /// [`Column`]: struct.Row.html
+ /// [`Layout`]: ../layout/struct.Layout.html
fn draw<Message>(
&mut self,
content: &[Element<'_, Message, Self>],
diff --git a/native/src/widget/container.rs b/native/src/widget/container.rs
index 2f15573d..64a5f4da 100644
--- a/native/src/widget/container.rs
+++ b/native/src/widget/container.rs
@@ -1,3 +1,4 @@
+//! Decorate content and apply alignment.
use std::hash::Hash;
use crate::{
diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs
index 696de683..c64f07b1 100644
--- a/native/src/widget/image.rs
+++ b/native/src/widget/image.rs
@@ -116,6 +116,9 @@ where
/// [`Image`]: struct.Image.html
/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer {
+ /// Returns the dimensions of an [`Image`] located on the given path.
+ ///
+ /// [`Image`]: struct.Image.html
fn dimensions(&self, path: &str) -> (u32, u32);
/// Draws an [`Image`].
diff --git a/native/src/widget/radio.rs b/native/src/widget/radio.rs
index 3dc764fe..4e48728f 100644
--- a/native/src/widget/radio.rs
+++ b/native/src/widget/radio.rs
@@ -174,15 +174,18 @@ where
/// [`Radio`]: struct.Radio.html
/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer {
+ /// Returns the default size of a [`Radio`] button.
+ ///
+ /// [`Radio`]: struct.Radio.html
fn default_size(&self) -> u32;
/// Draws a [`Radio`] button.
///
/// It receives:
- /// * the current cursor position
/// * the bounds of the [`Radio`]
- /// * the bounds of the label of the [`Radio`]
/// * whether the [`Radio`] is selected or not
+ /// * whether the mouse is over the [`Radio`] or not
+ /// * the drawn label of the [`Radio`]
///
/// [`Radio`]: struct.Radio.html
fn draw(
diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs
index 33222b8a..34c7ca7c 100644
--- a/native/src/widget/row.rs
+++ b/native/src/widget/row.rs
@@ -1,3 +1,4 @@
+//! Distribute content horizontally.
use std::hash::Hash;
use crate::{
@@ -192,7 +193,23 @@ where
}
}
+/// The renderer of a [`Row`].
+///
+/// Your [renderer] will need to implement this trait before being
+/// able to use a [`Row`] in your user interface.
+///
+/// [`Row`]: struct.Row.html
+/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer + Sized {
+ /// Draws a [`Row`].
+ ///
+ /// It receives:
+ /// - the children of the [`Row`]
+ /// - the [`Layout`] of the [`Row`] and its children
+ /// - the cursor position
+ ///
+ /// [`Row`]: struct.Row.html
+ /// [`Layout`]: ../layout/struct.Layout.html
fn draw<Message>(
&mut self,
children: &[Element<'_, Message, Self>],
diff --git a/native/src/widget/scrollable.rs b/native/src/widget/scrollable.rs
index 438f04cf..7b231b5f 100644
--- a/native/src/widget/scrollable.rs
+++ b/native/src/widget/scrollable.rs
@@ -1,3 +1,4 @@
+//! Navigate an endless amount of content with a scrollbar.
use crate::{
column,
input::{mouse, ButtonState},
@@ -361,7 +362,18 @@ impl State {
}
}
+/// The renderer of a [`Scrollable`].
+///
+/// Your [renderer] will need to implement this trait before being
+/// able to use a [`Scrollable`] in your user interface.
+///
+/// [`Scrollable`]: struct.Scrollable.html
+/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer + Sized {
+ /// Returns whether the mouse is over the scrollbar given the bounds of
+ /// the [`Scrollable`] and its contents.
+ ///
+ /// [`Scrollable`]: struct.Scrollable.html
fn is_mouse_over_scrollbar(
&self,
bounds: Rectangle,
@@ -369,6 +381,18 @@ pub trait Renderer: crate::Renderer + Sized {
cursor_position: Point,
) -> bool;
+ /// Draws the [`Scrollable`].
+ ///
+ /// It receives:
+ /// - the [`State`] of the [`Scrollable`]
+ /// - the bounds of the [`Scrollable`]
+ /// - whether the mouse is over the [`Scrollable`] or not
+ /// - whether the mouse is over the scrollbar or not
+ /// - the scrolling offset
+ /// - the drawn content
+ ///
+ /// [`Scrollable`]: struct.Scrollable.html
+ /// [`State`]: struct.State.html
fn draw(
&mut self,
scrollable: &State,
diff --git a/native/src/widget/slider.rs b/native/src/widget/slider.rs
index 113cc2a4..fe503c34 100644
--- a/native/src/widget/slider.rs
+++ b/native/src/widget/slider.rs
@@ -13,6 +13,28 @@ use crate::{
use std::{hash::Hash, ops::RangeInclusive};
+/// An horizontal bar and a handle that selects a single value from a range of
+/// values.
+///
+/// A [`Slider`] will try to fill the horizontal space of its container.
+///
+/// [`Slider`]: struct.Slider.html
+///
+/// # Example
+/// ```
+/// # use iced_native::{slider, Slider};
+/// #
+/// pub enum Message {
+/// SliderChanged(f32),
+/// }
+///
+/// let state = &mut slider::State::new();
+/// let value = 50.0;
+///
+/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged);
+/// ```
+///
+/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)
pub struct Slider<'a, Message> {
state: &'a mut State,
range: RangeInclusive<f32>,
@@ -180,6 +202,9 @@ where
/// [`Slider`]: struct.Slider.html
/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer {
+ /// Returns the height of the [`Slider`].
+ ///
+ /// [`Slider`]: struct.Slider.html
fn height(&self) -> u32;
/// Draws a [`Slider`].
diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs
index c4ab88d3..cf0701b9 100644
--- a/native/src/widget/text.rs
+++ b/native/src/widget/text.rs
@@ -32,9 +32,9 @@ impl Text {
/// Create a new fragment of [`Text`] with the given contents.
///
/// [`Text`]: struct.Text.html
- pub fn new(label: &str) -> Self {
+ pub fn new<T: Into<String>>(label: T) -> Self {
Text {
- content: String::from(label),
+ content: label.into(),
size: None,
color: None,
font: Font::Default,
@@ -174,8 +174,15 @@ where
/// [renderer]: ../../renderer/index.html
/// [`UserInterface`]: ../../struct.UserInterface.html
pub trait Renderer: crate::Renderer {
+ /// Returns the default size of the [`Text`].
+ ///
+ /// [`Text`]: struct.Text.html
fn default_size(&self) -> u16;
+ /// Measures the [`Text`] in the given bounds and returns the minimum
+ /// boundaries that can fit the contents.
+ ///
+ /// [`Text`]: struct.Text.html
fn measure(
&self,
content: &str,
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index 65306504..c3876b1d 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -10,7 +10,26 @@ use crate::{
Widget,
};
-/// A widget that can be filled with text by using a keyboard.
+/// A field that can be filled with text.
+///
+/// # Example
+/// ```
+/// # use iced_native::{text_input, TextInput};
+/// #
+/// enum Message {
+/// TextInputChanged(String),
+/// }
+///
+/// let mut state = text_input::State::new();
+/// let value = "Some text";
+///
+/// let input = TextInput::new(
+/// &mut state,
+/// "This is the placeholder...",
+/// value,
+/// Message::TextInputChanged,
+/// );
+/// ```
pub struct TextInput<'a, Message> {
state: &'a mut State,
placeholder: String,
@@ -26,7 +45,14 @@ pub struct TextInput<'a, Message> {
impl<'a, Message> TextInput<'a, Message> {
/// Creates a new [`TextInput`].
///
+ /// It expects:
+ /// - some [`State`]
+ /// - a placeholder
+ /// - the current value
+ /// - a function that produces a message when the [`TextInput`] changes
+ ///
/// [`TextInput`]: struct.TextInput.html
+ /// [`State`]: struct.State.html
pub fn new<F>(
state: &'a mut State,
placeholder: &str,
@@ -232,9 +258,32 @@ where
}
}
+/// The renderer of a [`TextInput`].
+///
+/// Your [renderer] will need to implement this trait before being
+/// able to use a [`TextInput`] in your user interface.
+///
+/// [`TextInput`]: struct.TextInput.html
+/// [renderer]: ../../renderer/index.html
pub trait Renderer: crate::Renderer + Sized {
+ /// Returns the default size of the text of the [`TextInput`].
+ ///
+ /// [`TextInput`]: struct.TextInput.html
fn default_size(&self) -> u16;
+ /// Draws a [`TextInput`].
+ ///
+ /// It receives:
+ /// - its bounds of the [`TextInput`]
+ /// - the bounds of the text (i.e. the current value)
+ /// - the cursor position
+ /// - the placeholder to show when the value is empty
+ /// - the current [`Value`]
+ /// - the current [`State`]
+ ///
+ /// [`TextInput`]: struct.TextInput.html
+ /// [`Value`]: struct.Value.html
+ /// [`State`]: struct.State.html
fn draw(
&mut self,
bounds: Rectangle,
@@ -289,6 +338,9 @@ impl State {
}
}
+ /// Returns whether the [`TextInput`] is currently focused or not.
+ ///
+ /// [`TextInput`]: struct.TextInput.html
pub fn is_focused(&self) -> bool {
self.is_focused
}
@@ -303,7 +355,7 @@ impl State {
/// Moves the cursor of a [`TextInput`] to the right.
///
/// [`TextInput`]: struct.TextInput.html
- pub fn move_cursor_right(&mut self, value: &Value) {
+ pub(crate) fn move_cursor_right(&mut self, value: &Value) {
let current = self.cursor_position(value);
if current < value.len() {
@@ -314,7 +366,7 @@ impl State {
/// Moves the cursor of a [`TextInput`] to the left.
///
/// [`TextInput`]: struct.TextInput.html
- pub fn move_cursor_left(&mut self, value: &Value) {
+ pub(crate) fn move_cursor_left(&mut self, value: &Value) {
let current = self.cursor_position(value);
if current > 0 {
@@ -325,7 +377,7 @@ impl State {
/// Moves the cursor of a [`TextInput`] to the end.
///
/// [`TextInput`]: struct.TextInput.html
- pub fn move_cursor_to_end(&mut self, value: &Value) {
+ pub(crate) fn move_cursor_to_end(&mut self, value: &Value) {
self.cursor_position = value.len();
}
}
diff --git a/src/application.rs b/src/application.rs
index ba8da446..5ecb901e 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -1,19 +1,140 @@
use crate::{Command, Element};
+/// An interactive cross-platform application.
+///
+/// This trait is the main entrypoint of Iced. Once implemented, you can run
+/// your GUI application by simply calling [`run`](#method.run).
+///
+/// - On native platforms, it will run in its own window.
+/// - On the web, it will take control of the `<title>` and the `<body>` of the
+/// document.
+///
+/// An [`Application`](trait.Application.html) can execute asynchronous actions
+/// by returning a [`Command`](struct.Command.html) in some of its methods. If
+/// you do not intend to perform any background work in your program, the
+/// [`Sandbox`](trait.Sandbox.html) trait offers a simplified interface.
+///
+/// # Example
+/// Let's say we want to run the [`Counter` example we implemented
+/// before](index.html#overview). We just need to fill in the gaps:
+///
+/// ```no_run
+/// use iced::{button, Application, Button, Column, Command, Element, Text};
+///
+/// pub fn main() {
+/// Counter::run()
+/// }
+///
+/// #[derive(Default)]
+/// struct Counter {
+/// value: i32,
+/// increment_button: button::State,
+/// decrement_button: button::State,
+/// }
+///
+/// #[derive(Debug, Clone, Copy)]
+/// enum Message {
+/// IncrementPressed,
+/// DecrementPressed,
+/// }
+///
+/// impl Application for Counter {
+/// type Message = Message;
+///
+/// fn new() -> (Self, Command<Message>) {
+/// (Self::default(), Command::none())
+/// }
+///
+/// fn title(&self) -> String {
+/// String::from("A simple counter")
+/// }
+///
+/// fn update(&mut self, message: Message) -> Command<Message> {
+/// match message {
+/// Message::IncrementPressed => {
+/// self.value += 1;
+/// }
+/// Message::DecrementPressed => {
+/// self.value -= 1;
+/// }
+/// }
+///
+/// Command::none()
+/// }
+///
+/// fn view(&mut self) -> Element<Message> {
+/// Column::new()
+/// .push(
+/// Button::new(&mut self.increment_button, Text::new("Increment"))
+/// .on_press(Message::IncrementPressed),
+/// )
+/// .push(
+/// Text::new(self.value.to_string()).size(50),
+/// )
+/// .push(
+/// Button::new(&mut self.decrement_button, Text::new("Decrement"))
+/// .on_press(Message::DecrementPressed),
+/// )
+/// .into()
+/// }
+/// }
+/// ```
pub trait Application: Sized {
+ /// The type of __messages__ your [`Application`] will produce.
+ ///
+ /// [`Application`]: trait.Application.html
type Message: std::fmt::Debug + Send;
+ /// Initializes the [`Application`].
+ ///
+ /// Here is where you should return the initial state of your app.
+ ///
+ /// Additionally, you can return a [`Command`](struct.Command.html) if you
+ /// need to perform some async action in the background on startup. This is
+ /// useful if you want to load state from a file, perform an initial HTTP
+ /// request, etc.
+ ///
+ /// [`Application`]: trait.Application.html
fn new() -> (Self, Command<Self::Message>);
+ /// Returns the current title of the [`Application`].
+ ///
+ /// This title can be dynamic! The runtime will automatically update the
+ /// title of your application when necessary.
+ ///
+ /// [`Application`]: trait.Application.html
fn title(&self) -> String;
+ /// Handles a __message__ and updates the state of the [`Application`].
+ ///
+ /// This is where you define your __update logic__. All the __messages__,
+ /// produced by either user interactions or commands, will be handled by
+ /// this method.
+ ///
+ /// Any [`Command`] returned will be executed immediately in the background.
+ ///
+ /// [`Application`]: trait.Application.html
+ /// [`Command`]: struct.Command.html
fn update(&mut self, message: Self::Message) -> Command<Self::Message>;
- fn view(&mut self) -> Element<Self::Message>;
-
+ /// Returns the widgets to display in the [`Application`].
+ ///
+ /// These widgets can produce __messages__ based on user interaction.
+ ///
+ /// [`Application`]: trait.Application.html
+ fn view(&mut self) -> Element<'_, Self::Message>;
+
+ /// Runs the [`Application`].
+ ///
+ /// This method will take control of the current thread and __will NOT
+ /// return__.
+ ///
+ /// It should probably be that last thing you call in your `main` function.
+ ///
+ /// [`Application`]: trait.Application.html
fn run()
where
- Self: 'static + Sized,
+ Self: 'static,
{
#[cfg(not(target_arch = "wasm32"))]
<Instance<Self> as iced_winit::Application>::run();
@@ -47,7 +168,7 @@ where
self.0.update(message)
}
- fn view(&mut self) -> Element<Self::Message> {
+ fn view(&mut self) -> Element<'_, Self::Message> {
self.0.view()
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 8462cd3c..48588261 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,184 @@
+//! Iced is a cross-platform GUI library focused on simplicity and type-safety.
+//! Inspired by [Elm].
+//!
+//! # Features
+//! * Simple, easy-to-use, batteries-included API
+//! * Type-safe, reactive programming model
+//! * [Cross-platform support] (Windows, macOS, Linux, and the Web)
+//! * Responsive layout
+//! * Built-in widgets (including [text inputs], [scrollables], and more!)
+//! * Custom widget support (create your own!)
+//! * [Debug overlay with performance metrics]
+//! * First-class support for async actions (use futures!)
+//! * [Modular ecosystem] split into reusable parts:
+//! * A [renderer-agnostic native runtime] enabling integration with existing
+//! systems
+//! * A [built-in renderer] supporting Vulkan, Metal, DX11, and DX12
+//! * A [windowing shell]
+//! * A [web runtime] leveraging the DOM
+//!
+//! Check out the [repository] and the [examples] for more details!
+//!
+//! [Cross-platform support]: https://github.com/hecrj/iced/blob/master/docs/images/todos_desktop.jpg?raw=true
+//! [text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
+//! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
+//! [Debug overlay with performance metrics]: https://gfycat.com/artisticdiligenthorseshoebat-rust-gui
+//! [Modular ecosystem]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md
+//! [renderer-agnostic native runtime]: https://github.com/hecrj/iced/tree/master/native
+//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
+//! [built-in renderer]: https://github.com/hecrj/iced/tree/master/wgpu
+//! [windowing shell]: https://github.com/hecrj/iced/tree/master/winit
+//! [`dodrio`]: https://github.com/fitzgen/dodrio
+//! [web runtime]: https://github.com/hecrj/iced/tree/master/web
+//! [examples]: https://github.com/hecrj/iced/tree/0.1.0/examples
+//! [repository]: https://github.com/hecrj/iced
+//!
+//! # Overview
+//! Inspired by [The Elm Architecture], Iced expects you to split user
+//! interfaces into four different concepts:
+//!
+//! * __State__ — the state of your application
+//! * __Messages__ — user interactions or meaningful events that you care
+//! about
+//! * __View logic__ — a way to display your __state__ as widgets that
+//! may produce __messages__ on user interaction
+//! * __Update logic__ — a way to react to __messages__ and update your
+//! __state__
+//!
+//! We can build something to see how this works! Let's say we want a simple
+//! counter that can be incremented and decremented using two buttons.
+//!
+//! We start by modelling the __state__ of our application:
+//!
+//! ```
+//! use iced::button;
+//!
+//! struct Counter {
+//! // The counter value
+//! value: i32,
+//!
+//! // The local state of the two buttons
+//! increment_button: button::State,
+//! decrement_button: button::State,
+//! }
+//! ```
+//!
+//! Next, we need to define the possible user interactions of our counter:
+//! the button presses. These interactions are our __messages__:
+//!
+//! ```
+//! #[derive(Debug, Clone, Copy)]
+//! pub enum Message {
+//! IncrementPressed,
+//! DecrementPressed,
+//! }
+//! ```
+//!
+//! Now, let's show the actual counter by putting it all together in our
+//! __view logic__:
+//!
+//! ```
+//! # use iced::button;
+//! #
+//! # struct Counter {
+//! # // The counter value
+//! # value: i32,
+//! #
+//! # // The local state of the two buttons
+//! # increment_button: button::State,
+//! # decrement_button: button::State,
+//! # }
+//! #
+//! # #[derive(Debug, Clone, Copy)]
+//! # pub enum Message {
+//! # IncrementPressed,
+//! # DecrementPressed,
+//! # }
+//! #
+//! use iced::{Button, Column, Text};
+//!
+//! impl Counter {
+//! pub fn view(&mut self) -> Column<Message> {
+//! // We use a column: a simple vertical layout
+//! Column::new()
+//! .push(
+//! // The increment button. We tell it to produce an
+//! // `IncrementPressed` message when pressed
+//! Button::new(&mut self.increment_button, Text::new("+"))
+//! .on_press(Message::IncrementPressed),
+//! )
+//! .push(
+//! // We show the value of the counter here
+//! Text::new(self.value.to_string()).size(50),
+//! )
+//! .push(
+//! // The decrement button. We tell it to produce a
+//! // `DecrementPressed` message when pressed
+//! Button::new(&mut self.decrement_button, Text::new("-"))
+//! .on_press(Message::DecrementPressed),
+//! )
+//! }
+//! }
+//! ```
+//!
+//! Finally, we need to be able to react to any produced __messages__ and change
+//! our __state__ accordingly in our __update logic__:
+//!
+//! ```
+//! # use iced::button;
+//! #
+//! # struct Counter {
+//! # // The counter value
+//! # value: i32,
+//! #
+//! # // The local state of the two buttons
+//! # increment_button: button::State,
+//! # decrement_button: button::State,
+//! # }
+//! #
+//! # #[derive(Debug, Clone, Copy)]
+//! # pub enum Message {
+//! # IncrementPressed,
+//! # DecrementPressed,
+//! # }
+//! impl Counter {
+//! // ...
+//!
+//! pub fn update(&mut self, message: Message) {
+//! match message {
+//! Message::IncrementPressed => {
+//! self.value += 1;
+//! }
+//! Message::DecrementPressed => {
+//! self.value -= 1;
+//! }
+//! }
+//! }
+//! }
+//! ```
+//!
+//! And that's everything! We just wrote a whole user interface. Iced is now
+//! able to:
+//!
+//! 1. Take the result of our __view logic__ and layout its widgets.
+//! 1. Process events from our system and produce __messages__ for our
+//! __update logic__.
+//! 1. Draw the resulting user interface.
+//!
+//! # Usage
+//! Take a look at the [`Application`] trait, which streamlines all the process
+//! described above for you!
+//!
+//! [Elm]: https://elm-lang.org/
+//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
+//! [documentation]: https://docs.rs/iced
+//! [examples]: https://github.com/hecrj/iced/tree/master/examples
+//! [`Application`]: trait.Application.html
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+#![deny(unused_results)]
+#![deny(unsafe_code)]
+#![deny(rust_2018_idioms)]
mod application;
#[cfg_attr(target_arch = "wasm32", path = "web.rs")]
#[cfg_attr(not(target_arch = "wasm32"), path = "native.rs")]
diff --git a/src/native.rs b/src/native.rs
index fcb50d43..926b2d11 100644
--- a/src/native.rs
+++ b/src/native.rs
@@ -4,7 +4,36 @@ pub use iced_winit::{
};
pub mod widget {
+ //! Display information and interactive controls in your application.
+ //!
+ //! # Re-exports
+ //! For convenience, the contents of this module are available at the root
+ //! module. Therefore, you can directly type:
+ //!
+ //! ```
+ //! use iced::{button, Button};
+ //! ```
+ //!
+ //! # Stateful widgets
+ //! Some widgets need to keep track of __local state__.
+ //!
+ //! These widgets have their own module with a `State` type. For instance, a
+ //! [`TextInput`] has some [`text_input::State`].
+ //!
+ //! [`TextInput`]: text_input/struct.TextInput.html
+ //! [`text_input::State`]: text_input/struct.State.html
pub mod button {
+ //! Allow your users to perform actions by pressing a button.
+ //!
+ //! A [`Button`] has some local [`State`].
+ //!
+ //! [`Button`]: type.Button.html
+ //! [`State`]: struct.State.html
+
+ /// A widget that produces a message when clicked.
+ ///
+ /// This is an alias of an `iced_native` button with a default
+ /// `Renderer`.
pub type Button<'a, Message> =
iced_winit::Button<'a, Message, iced_wgpu::Renderer>;
@@ -12,6 +41,13 @@ pub mod widget {
}
pub mod scrollable {
+ //! Navigate an endless amount of content with a scrollbar.
+
+ /// A widget that can vertically display an infinite amount of content
+ /// with a scrollbar.
+ ///
+ /// This is an alias of an `iced_native` scrollable with a default
+ /// `Renderer`.
pub type Scrollable<'a, Message> =
iced_winit::Scrollable<'a, Message, iced_wgpu::Renderer>;
@@ -19,10 +55,23 @@ pub mod widget {
}
pub mod text_input {
+ //! Ask for information using text fields.
+ //!
+ //! A [`TextInput`] has some local [`State`].
+ //!
+ //! [`TextInput`]: struct.TextInput.html
+ //! [`State`]: struct.State.html
pub use iced_winit::text_input::{State, TextInput};
}
pub mod slider {
+ //! Display an interactive selector of a single value from a range of
+ //! values.
+ //!
+ //! A [`Slider`] has some local [`State`].
+ //!
+ //! [`Slider`]: struct.Slider.html
+ //! [`State`]: struct.State.html
pub use iced_winit::slider::{Slider, State};
}
@@ -34,12 +83,22 @@ pub mod widget {
text_input::TextInput,
};
+ /// A container that distributes its contents vertically.
+ ///
+ /// This is an alias of an `iced_native` column with a default `Renderer`.
pub type Column<'a, Message> =
iced_winit::Column<'a, Message, iced_wgpu::Renderer>;
+ /// A container that distributes its contents horizontally.
+ ///
+ /// This is an alias of an `iced_native` row with a default `Renderer`.
pub type Row<'a, Message> =
iced_winit::Row<'a, Message, iced_wgpu::Renderer>;
+ /// An element decorating some content.
+ ///
+ /// This is an alias of an `iced_native` container with a default
+ /// `Renderer`.
pub type Container<'a, Message> =
iced_winit::Container<'a, Message, iced_wgpu::Renderer>;
}
@@ -47,5 +106,8 @@ pub mod widget {
#[doc(no_inline)]
pub use widget::*;
+/// A generic widget.
+///
+/// This is an alias of an `iced_native` element with a default `Renderer`.
pub type Element<'a, Message> =
iced_winit::Element<'a, Message, iced_wgpu::Renderer>;
diff --git a/src/sandbox.rs b/src/sandbox.rs
index 8ff374f7..698578f4 100644
--- a/src/sandbox.rs
+++ b/src/sandbox.rs
@@ -1,16 +1,126 @@
use crate::{Application, Command, Element};
+/// A sandboxed [`Application`].
+///
+/// A [`Sandbox`] is just an [`Application`] that cannot run any asynchronous
+/// actions.
+///
+/// If you do not need to leverage a [`Command`], you can use a [`Sandbox`]
+/// instead of returning a [`Command::none`] everywhere.
+///
+/// [`Application`]: trait.Application.html
+/// [`Sandbox`]: trait.Sandbox.html
+/// [`Command`]: struct.Command.html
+/// [`Command::none`]: struct.Command.html#method.none
+///
+/// # Example
+/// We can use a [`Sandbox`] to run the [`Counter` example we implemented
+/// before](index.html#overview), instead of an [`Application`]. We just need
+/// to remove the use of [`Command`]:
+///
+/// ```no_run
+/// use iced::{button, Button, Column, Element, Sandbox, Text};
+///
+/// pub fn main() {
+/// Counter::run()
+/// }
+///
+/// #[derive(Default)]
+/// struct Counter {
+/// value: i32,
+/// increment_button: button::State,
+/// decrement_button: button::State,
+/// }
+///
+/// #[derive(Debug, Clone, Copy)]
+/// enum Message {
+/// IncrementPressed,
+/// DecrementPressed,
+/// }
+///
+/// impl Sandbox for Counter {
+/// type Message = Message;
+///
+/// fn new() -> Self {
+/// Self::default()
+/// }
+///
+/// fn title(&self) -> String {
+/// String::from("A simple counter")
+/// }
+///
+/// fn update(&mut self, message: Message) {
+/// match message {
+/// Message::IncrementPressed => {
+/// self.value += 1;
+/// }
+/// Message::DecrementPressed => {
+/// self.value -= 1;
+/// }
+/// }
+/// }
+///
+/// fn view(&mut self) -> Element<Message> {
+/// Column::new()
+/// .push(
+/// Button::new(&mut self.increment_button, Text::new("Increment"))
+/// .on_press(Message::IncrementPressed),
+/// )
+/// .push(
+/// Text::new(self.value.to_string()).size(50),
+/// )
+/// .push(
+/// Button::new(&mut self.decrement_button, Text::new("Decrement"))
+/// .on_press(Message::DecrementPressed),
+/// )
+/// .into()
+/// }
+/// }
+/// ```
pub trait Sandbox {
+ /// The type of __messages__ your [`Sandbox`] will produce.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
type Message: std::fmt::Debug + Send;
+ /// Initializes the [`Sandbox`].
+ ///
+ /// Here is where you should return the initial state of your app.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
fn new() -> Self;
+ /// Returns the current title of the [`Sandbox`].
+ ///
+ /// This title can be dynamic! The runtime will automatically update the
+ /// title of your application when necessary.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
fn title(&self) -> String;
+ /// Handles a __message__ and updates the state of the [`Sandbox`].
+ ///
+ /// This is where you define your __update logic__. All the __messages__,
+ /// produced by user interactions, will be handled by this method.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
fn update(&mut self, message: Self::Message);
- fn view(&mut self) -> Element<Self::Message>;
+ /// Returns the widgets to display in the [`Sandbox`].
+ ///
+ /// These widgets can produce __messages__ based on user interaction.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
+ fn view(&mut self) -> Element<'_, Self::Message>;
+ /// Runs the [`Sandbox`].
+ ///
+ /// This method will take control of the current thread and __will NOT
+ /// return__.
+ ///
+ /// It should probably be that last thing you call in your `main` function.
+ ///
+ /// [`Sandbox`]: trait.Sandbox.html
fn run()
where
Self: 'static + Sized,
@@ -39,7 +149,7 @@ where
Command::none()
}
- fn view(&mut self) -> Element<T::Message> {
+ fn view(&mut self) -> Element<'_, T::Message> {
T::view(self)
}
}
diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs
index 3740af13..1183a3cd 100644
--- a/web/src/widget/text.rs
+++ b/web/src/widget/text.rs
@@ -30,9 +30,9 @@ impl Text {
/// Create a new fragment of [`Text`] with the given contents.
///
/// [`Text`]: struct.Text.html
- pub fn new(label: &str) -> Self {
+ pub fn new<T: Into<String>>(label: T) -> Self {
Text {
- content: String::from(label),
+ content: label.into(),
size: None,
color: None,
font: Font::Default,