Draft "The Pocket Guide" for the API reference
This commit is contained in:
parent
bdf0430880
commit
143f4c86ca
1 changed files with 281 additions and 124 deletions
405
src/lib.rs
405
src/lib.rs
|
|
@ -1,170 +1,327 @@
|
|||
//! Iced is a cross-platform GUI library focused on simplicity and type-safety.
|
||||
//! 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
|
||||
//! # Disclaimer
|
||||
//! iced is __experimental__ software. If you expect the documentation to hold your hand
|
||||
//! as you learn the ropes, you are in for a frustrating experience.
|
||||
//!
|
||||
//! Check out the [repository] and the [examples] for more details!
|
||||
//! The library leverages Rust to its full extent: ownership, borrowing, lifetimes, futures,
|
||||
//! streams, first-class functions, trait bounds, closures, and more. This documentation
|
||||
//! is not meant to teach you any of these. Far from it, it will assume you have __mastered__
|
||||
//! all of them.
|
||||
//!
|
||||
//! [Cross-platform support]: https://github.com/iced-rs/iced/blob/master/docs/images/todos_desktop.jpg?raw=true
|
||||
//! [text inputs]: https://iced.rs/examples/text_input.mp4
|
||||
//! [scrollables]: https://iced.rs/examples/scrollable.mp4
|
||||
//! [Debug overlay with performance metrics]: https://iced.rs/examples/debug.mp4
|
||||
//! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
|
||||
//! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/tree/0.12/runtime
|
||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||
//! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.12/wgpu
|
||||
//! [windowing shell]: https://github.com/iced-rs/iced/tree/0.12/winit
|
||||
//! [`dodrio`]: https://github.com/fitzgen/dodrio
|
||||
//! [web runtime]: https://github.com/iced-rs/iced_web
|
||||
//! [examples]: https://github.com/iced-rs/iced/tree/0.12/examples
|
||||
//! [repository]: https://github.com/iced-rs/iced
|
||||
//! Furthermore—just like Rust—iced is very unforgiving. It will not let you easily cut corners.
|
||||
//! The type signatures alone can be used to learn how to use most of the library.
|
||||
//! Everything is connected.
|
||||
//!
|
||||
//! # Overview
|
||||
//! Inspired by [The Elm Architecture], Iced expects you to split user
|
||||
//! interfaces into four different concepts:
|
||||
//! Therefore, iced is easy to learn for __advanced__ Rust programmers; but plenty of patient
|
||||
//! beginners have learned it and had a good time with it. Since it leverages a lot of what
|
||||
//! Rust has to offer in a type-safe way, it can be a great way to discover Rust itself.
|
||||
//!
|
||||
//! * __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__
|
||||
//! If you don't like the sound of that, you expect to be spoonfed, or you feel frustrated
|
||||
//! and struggle to use the library; then I recommend you to wait patiently until [the book]
|
||||
//! is finished.
|
||||
//!
|
||||
//! 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.
|
||||
//! [the book]: https://book.iced.rs
|
||||
//!
|
||||
//! We start by modelling the __state__ of our application:
|
||||
//! # The Pocket Guide
|
||||
//! Start by calling [`run`]:
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! pub fn main() -> iced::Result {
|
||||
//! iced::run("A cool counter", update, view)
|
||||
//! }
|
||||
//! # fn update(state: &mut (), message: ()) {}
|
||||
//! # fn view(state: &()) -> iced::Element<()> { iced::widget::text("").into() }
|
||||
//! ```
|
||||
//!
|
||||
//! Define an `update` function to __change__ your state:
|
||||
//!
|
||||
//! ```rust
|
||||
//! fn update(counter: &mut u64, message: Message) {
|
||||
//! match message {
|
||||
//! Message::Increment => *counter += 1,
|
||||
//! }
|
||||
//! }
|
||||
//! # #[derive(Clone)]
|
||||
//! # enum Message { Increment }
|
||||
//! ```
|
||||
//!
|
||||
//! Define a `view` function to __display__ your state:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use iced::widget::{button, text};
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(counter: &u64) -> Element<Message> {
|
||||
//! button(text(counter)).on_press(Message::Increment).into()
|
||||
//! }
|
||||
//! # #[derive(Clone)]
|
||||
//! # enum Message { Increment }
|
||||
//! ```
|
||||
//!
|
||||
//! And create a `Message` enum to __connect__ `view` and `update` together:
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[derive(Debug, Clone)]
|
||||
//! enum Message {
|
||||
//! Increment,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Custom State
|
||||
//! You can define your own struct for your state:
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[derive(Default)]
|
||||
//! struct Counter {
|
||||
//! // The counter value
|
||||
//! value: i32,
|
||||
//! value: u64,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Next, we need to define the possible user interactions of our counter:
|
||||
//! the button presses. These interactions are our __messages__:
|
||||
//! But you have to change `update` and `view` accordingly:
|
||||
//!
|
||||
//! ```
|
||||
//! #[derive(Debug, Clone, Copy)]
|
||||
//! pub enum Message {
|
||||
//! Increment,
|
||||
//! Decrement,
|
||||
//! ```rust
|
||||
//! # struct Counter { value: u64 }
|
||||
//! # #[derive(Clone)]
|
||||
//! # enum Message { Increment }
|
||||
//! # use iced::widget::{button, text};
|
||||
//! # use iced::Element;
|
||||
//! fn update(counter: &mut Counter, message: Message) {
|
||||
//! match message {
|
||||
//! Message::Increment => counter.value += 1,
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn view(counter: &Counter) -> Element<Message> {
|
||||
//! button(text(counter.value)).on_press(Message::Increment).into()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Now, let's show the actual counter by putting it all together in our
|
||||
//! __view logic__:
|
||||
//! ## Widgets and Elements
|
||||
//! The `view` function must return an [`Element`]. An [`Element`] is just a generic [`widget`].
|
||||
//!
|
||||
//! The [`widget`] module contains a bunch of functions to help you build
|
||||
//! and use widgets.
|
||||
//!
|
||||
//! Widgets are configured using the builder pattern:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # struct Counter { value: u64 }
|
||||
//! # #[derive(Clone)]
|
||||
//! # enum Message { Increment }
|
||||
//! use iced::widget::{button, column, text};
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(counter: &Counter) -> Element<Message> {
|
||||
//! column![
|
||||
//! text(counter.value).size(20),
|
||||
//! button("Increment").on_press(Message::Increment),
|
||||
//! ]
|
||||
//! .spacing(10)
|
||||
//! .into()
|
||||
//! }
|
||||
//! ```
|
||||
//! # struct Counter {
|
||||
//! # // The counter value
|
||||
//! # value: i32,
|
||||
//! # }
|
||||
//! #
|
||||
//! # #[derive(Debug, Clone, Copy)]
|
||||
//! # pub enum Message {
|
||||
//! # Increment,
|
||||
//! # Decrement,
|
||||
//! # }
|
||||
//! #
|
||||
//! use iced::widget::{button, column, text, Column};
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! pub fn view(&self) -> Column<Message> {
|
||||
//! // We use a column: a simple vertical layout
|
||||
//! A widget can be turned into an [`Element`] by calling `into`.
|
||||
//!
|
||||
//! Widgets and elements are generic over the message type they produce. The
|
||||
//! [`Element`] returned by `view` must have the same `Message` type as
|
||||
//! your `update`.
|
||||
//!
|
||||
//! ## Layout
|
||||
//! There is no unified layout system in iced. Instead, each widget implements
|
||||
//! its own layout strategy.
|
||||
//!
|
||||
//! Generally, building your layout will consist in using a combination of
|
||||
//! [rows], [columns], and [containers]:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # struct State;
|
||||
//! # enum Message {}
|
||||
//! use iced::widget::{column, container, row};
|
||||
//! use iced::{Fill, Element};
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! container(
|
||||
//! column![
|
||||
//! // The increment button. We tell it to produce an
|
||||
//! // `Increment` message when pressed
|
||||
//! button("+").on_press(Message::Increment),
|
||||
//!
|
||||
//! // We show the value of the counter here
|
||||
//! text(self.value).size(50),
|
||||
//!
|
||||
//! // The decrement button. We tell it to produce a
|
||||
//! // `Decrement` message when pressed
|
||||
//! button("-").on_press(Message::Decrement),
|
||||
//! "Top",
|
||||
//! row!["Left", "Right"].spacing(10),
|
||||
//! "Bottom"
|
||||
//! ]
|
||||
//! }
|
||||
//! .spacing(10)
|
||||
//! )
|
||||
//! .padding(10)
|
||||
//! .center_x(Fill)
|
||||
//! .center_y(Fill)
|
||||
//! .into()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Finally, we need to be able to react to any produced __messages__ and change
|
||||
//! our __state__ accordingly in our __update logic__:
|
||||
//! Rows and columns lay out their children horizontally and vertically,
|
||||
//! respectively. [Spacing] can be easily added between elements.
|
||||
//!
|
||||
//! ```
|
||||
//! # struct Counter {
|
||||
//! # // The counter value
|
||||
//! # value: i32,
|
||||
//! # }
|
||||
//! #
|
||||
//! # #[derive(Debug, Clone, Copy)]
|
||||
//! # pub enum Message {
|
||||
//! # Increment,
|
||||
//! # Decrement,
|
||||
//! # }
|
||||
//! impl Counter {
|
||||
//! // ...
|
||||
//! Containers position or align a single widget inside their bounds.
|
||||
//!
|
||||
//! pub fn update(&mut self, message: Message) {
|
||||
//! match message {
|
||||
//! Message::Increment => {
|
||||
//! self.value += 1;
|
||||
//! }
|
||||
//! Message::Decrement => {
|
||||
//! self.value -= 1;
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! [rows]: widget::Row
|
||||
//! [columns]: widget::Column
|
||||
//! [containers]: widget::Container
|
||||
//! [Spacing]: widget::Column::spacing
|
||||
//!
|
||||
//! ## Sizing
|
||||
//! The width and height of widgets can generally be defined using a [`Length`].
|
||||
//!
|
||||
//! - [`Fill`] will make the widget take all the available space in a given axis.
|
||||
//! - [`Shrink`] will make the widget use its intrinsic size.
|
||||
//!
|
||||
//! Most widgets use a [`Shrink`] sizing strategy by default, but will inherit
|
||||
//! a [`Fill`] strategy from their children.
|
||||
//!
|
||||
//! A fixed numeric [`Length`] in [`Pixels`] can also be used:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # struct State;
|
||||
//! # enum Message {}
|
||||
//! use iced::widget::container;
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! container("I am 300px tall!").height(300).into()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! And that's everything! We just wrote a whole user interface. Let's run it:
|
||||
//! ## Theming
|
||||
//! The default [`Theme`] of an application can be changed by defining a `theme`
|
||||
//! function and leveraging the [`Application`] builder, instead of directly
|
||||
//! calling [`run`]:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! ```rust,no_run
|
||||
//! # #[derive(Default)]
|
||||
//! # struct Counter;
|
||||
//! # impl Counter {
|
||||
//! # fn update(&mut self, _message: ()) {}
|
||||
//! # fn view(&self) -> iced::Element<()> { unimplemented!() }
|
||||
//! # }
|
||||
//! #
|
||||
//! fn main() -> iced::Result {
|
||||
//! iced::run("A cool counter", Counter::update, Counter::view)
|
||||
//! # struct State;
|
||||
//! use iced::Theme;
|
||||
//!
|
||||
//! pub fn main() -> iced::Result {
|
||||
//! iced::application("A cool application", update, view)
|
||||
//! .theme(theme)
|
||||
//! .run()
|
||||
//! }
|
||||
//!
|
||||
//! fn theme(state: &State) -> Theme {
|
||||
//! Theme::TokyoNight
|
||||
//! }
|
||||
//! # fn update(state: &mut State, message: ()) {}
|
||||
//! # fn view(state: &State) -> iced::Element<()> { iced::widget::text("").into() }
|
||||
//! ```
|
||||
//!
|
||||
//! The `theme` function takes the current state of the application, allowing the
|
||||
//! returned [`Theme`] to be completely dynamic—just like `view`.
|
||||
//!
|
||||
//! There are a bunch of built-in [`Theme`] variants at your disposal, but you can
|
||||
//! also [create your own](Theme::custom).
|
||||
//!
|
||||
//! ## Styling
|
||||
//! As with layout, iced does not have a unified styling system. However, all
|
||||
//! of the built-in widgets follow the same styling approach.
|
||||
//!
|
||||
//! The appearance of a widget can be changed by calling its `style` method:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # struct State;
|
||||
//! # enum Message {}
|
||||
//! use iced::widget::container;
|
||||
//! use iced::Element;
|
||||
//!
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! container("I am a rounded box!").style(container::rounded_box).into()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Iced will automatically:
|
||||
//! The `style` method of a widget takes a closure that, given the current active
|
||||
//! [`Theme`], returns the widget style:
|
||||
//!
|
||||
//! 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.
|
||||
//! ```rust
|
||||
//! # struct State;
|
||||
//! # #[derive(Clone)]
|
||||
//! # enum Message {}
|
||||
//! use iced::widget::button;
|
||||
//! use iced::{Element, Theme};
|
||||
//!
|
||||
//! # Usage
|
||||
//! Use [`run`] or the [`application`] builder.
|
||||
//! fn view(state: &State) -> Element<Message> {
|
||||
//! button("I am a styled button!").style(|theme: &Theme, status| {
|
||||
//! let palette = theme.extended_palette();
|
||||
//!
|
||||
//! match status {
|
||||
//! button::Status::Active => {
|
||||
//! button::Style::default()
|
||||
//! .with_background(palette.success.strong.color)
|
||||
//! }
|
||||
//! _ => button::primary(theme, status),
|
||||
//! }
|
||||
//! })
|
||||
//! .into()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Widgets that can be in multiple different states will also provide the closure
|
||||
//! with some [`Status`], allowing you to use a different style for each state.
|
||||
//!
|
||||
//! You can extract the [`Palette`] colors of a [`Theme`] with the [`palette`] or
|
||||
//! [`extended_palette`] methods.
|
||||
//!
|
||||
//! Most widgets provide styling functions for your convenience in their respective modules;
|
||||
//! like [`container::rounded_box`], [`button::primary`], or [`text::danger`].
|
||||
//!
|
||||
//! [`Status`]: widget::button::Status
|
||||
//! [`palette`]: Theme::palette
|
||||
//! [`extended_palette`]: Theme::extended_palette
|
||||
//! [`container::rounded_box`]: widget::container::rounded_box
|
||||
//! [`button::primary`]: widget::button::primary
|
||||
//! [`text::danger`]: widget::text::danger
|
||||
//!
|
||||
//! ## Concurrent Tasks
|
||||
//! The `update` function can _optionally_ return a [`Task`].
|
||||
//!
|
||||
//! A [`Task`] can be leveraged to perform asynchronous work, like running a
|
||||
//! future or a stream:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #[derive(Clone)]
|
||||
//! # struct Weather;
|
||||
//! use iced::Task;
|
||||
//!
|
||||
//! struct State {
|
||||
//! weather: Option<Weather>,
|
||||
//! }
|
||||
//!
|
||||
//! enum Message {
|
||||
//! FetchWeather,
|
||||
//! WeatherFetched(Weather),
|
||||
//! }
|
||||
//!
|
||||
//! fn update(state: &mut State, message: Message) -> Task<Message> {
|
||||
//! match message {
|
||||
//! Message::FetchWeather => Task::perform(
|
||||
//! fetch_weather(),
|
||||
//! Message::WeatherFetched,
|
||||
//! ),
|
||||
//! Message::WeatherFetched(weather) => {
|
||||
//! state.weather = Some(weather);
|
||||
//!
|
||||
//! Task::none()
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! async fn fetch_weather() -> Weather {
|
||||
//! // ...
|
||||
//! # unimplemented!()
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [Elm]: https://elm-lang.org/
|
||||
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
//! [`application`]: application()
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/bdf0430880f5c29443f5f0a0ae4895866dfef4c6/docs/logo.svg"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue