Write docs for iced and iced_native

This commit is contained in:
Héctor Ramón Jiménez 2019-11-22 19:36:57 +01:00
parent ba56a561b2
commit a7dba612f0
30 changed files with 877 additions and 214 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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(

View File

@ -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(),

View File

@ -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

View File

@ -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,

View File

@ -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
//!
//! To achieve this, it introduces a bunch of reusable interfaces:
//!
//! - 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
//! 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,
//! }
//! ```
//!
//! 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__.
//!
//! 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)]

View File

@ -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>,

View File

@ -4,6 +4,7 @@ use crate::{
Rectangle, Renderer, Size, VerticalAlignment,
};
/// A renderer that does nothing.
pub struct Null;
impl Renderer for Null {

View File

@ -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,

View File

@ -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,

View File

@ -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`].

View File

@ -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(

View File

@ -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>],

View File

@ -1,3 +1,4 @@
//! Decorate content and apply alignment.
use std::hash::Hash;
use crate::{

View File

@ -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`].

View File

@ -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(

View File

@ -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>],

View File

@ -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,

View File

@ -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`].

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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()
}
}

View File

@ -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")]

View File

@ -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>;

View File

@ -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)
}
}

View File

@ -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,