summaryrefslogtreecommitdiffstats
path: root/src
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 /src
parentba56a561b254c9a5f3d23cb54d23dc311759ab4c (diff)
downloadiced-a7dba612f03e58d7bd9527499d893987986b347c.tar.gz
iced-a7dba612f03e58d7bd9527499d893987986b347c.tar.bz2
iced-a7dba612f03e58d7bd9527499d893987986b347c.zip
Write docs for `iced` and `iced_native`
Diffstat (limited to 'src')
-rw-r--r--src/application.rs129
-rw-r--r--src/lib.rs181
-rw-r--r--src/native.rs62
-rw-r--r--src/sandbox.rs114
4 files changed, 480 insertions, 6 deletions
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)
}
}