Write docs for iced and iced_native
This commit is contained in:
parent
ba56a561b2
commit
a7dba612f0
30 changed files with 877 additions and 214 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
181
src/lib.rs
181
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")]
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
114
src/sandbox.rs
114
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue