diff options
author | 2019-11-22 19:36:57 +0100 | |
---|---|---|
committer | 2019-11-22 19:36:57 +0100 | |
commit | a7dba612f03e58d7bd9527499d893987986b347c (patch) | |
tree | b8c3d8f997b714aa368bd6eaecf14065f7645c77 /src | |
parent | ba56a561b254c9a5f3d23cb54d23dc311759ab4c (diff) | |
download | iced-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.rs | 129 | ||||
-rw-r--r-- | src/lib.rs | 181 | ||||
-rw-r--r-- | src/native.rs | 62 | ||||
-rw-r--r-- | src/sandbox.rs | 114 |
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() } } @@ -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) } } |