Merge pull request #1327 from iced-rs/update-docs

Update documentation
This commit is contained in:
Héctor Ramón 2022-05-02 21:21:24 +02:00 committed by GitHub
commit 5acba65c11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 755 additions and 187 deletions

View file

@ -2,7 +2,7 @@
Thank you for considering contributing to Iced! Feel free to read [the ecosystem overview] and [the roadmap] to get an idea of the current state of the library.
The main advice for new contributors is to share your ideas with the community. Introduce yourself over our [Discord server] or [start a discussion in an issue](https://github.com/hecrj/iced/issues) explaining what you have in mind (do not be afraid of duplicated issues!). If you want to talk directly to me (@hecrj), you can also find me on Discord (`lone_scientist#9554`).
The main advice for new contributors is to share your ideas with the community. Introduce yourself over our [Discord server] or [start a discussion in an issue](https://github.com/iced-rs/iced/issues) explaining what you have in mind (do not be afraid of duplicated issues!). If you want to talk directly to me (@hecrj), you can also find me on Discord (`lone_scientist#9554`).
This is a very important step. It helps to coordinate work, get on the same page, and start building trust. Please, do not skip it! Remember that [Code is the Easy Part] and also [The Hard Parts of Open Source]!

View file

@ -116,4 +116,4 @@ iced_wgpu = { version = "0.4", path = "wgpu", features = ["webgl"], optional = t
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
features = ["image", "svg", "canvas", "qr_code"]
features = ["image", "svg", "canvas", "qr_code", "pure"]

View file

@ -2,13 +2,13 @@
<img src="docs/logo.svg" width="140px" />
# iced
# Iced
[![Documentation](https://docs.rs/iced/badge.svg)][documentation]
[![Crates.io](https://img.shields.io/crates/v/iced.svg)](https://crates.io/crates/iced)
[![License](https://img.shields.io/crates/l/iced.svg)](https://github.com/hecrj/iced/blob/master/LICENSE)
[![License](https://img.shields.io/crates/l/iced.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
[![Downloads](https://img.shields.io/crates/d/iced.svg)](https://crates.io/crates/iced)
[![Test Status](https://github.com/hecrj/iced/workflows/Test/badge.svg?event=push)](https://github.com/hecrj/iced/actions)
[![Test Status](https://github.com/iced-rs/iced/workflows/Test/badge.svg?event=push)](https://github.com/iced-rs/iced/actions)
[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
A cross-platform GUI library for Rust focused on simplicity and type-safety.
@ -40,11 +40,11 @@ Inspired by [Elm].
* A [windowing shell]
* A [web runtime] leveraging the DOM
__iced is currently experimental software.__ [Take a look at the roadmap],
__Iced is currently experimental software.__ [Take a look at the roadmap],
[check out the issues], and [feel free to contribute!]
[Cross-platform support]: https://raw.githubusercontent.com/iced-rs/iced/master/docs/images/todos_desktop.jpg
[the Web]: https://iced.rs/
[the Web]: https://github.com/iced-rs/iced_web
[text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
[scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
[Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
@ -69,13 +69,13 @@ Add `iced` as a dependency in your `Cargo.toml`:
iced = "0.3"
```
__iced moves fast and the `master` branch can contain breaking changes!__ If
__Iced moves fast and the `master` branch can contain breaking changes!__ If
you want to learn about a specific release, check out [the release list].
[the release list]: https://github.com/iced-rs/iced/releases
## Overview
Inspired by [The Elm Architecture], iced expects you to split user interfaces
Inspired by [The Elm Architecture], Iced expects you to split user interfaces
into four different concepts:
* __State__ — the state of your application
@ -165,7 +165,7 @@ impl Counter {
}
```
And that's everything! We just wrote a whole user interface. iced is now able
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.
@ -176,7 +176,7 @@ to:
Browse the [documentation] and the [examples] to learn more!
## Implementation details
iced was originally born as an attempt at bringing the simplicity of [Elm] and
Iced was originally born as an attempt at bringing the simplicity of [Elm] and
[The Elm Architecture] into [Coffee], a 2D game engine I am working on.
The core of the library was implemented during May 2019 in [this pull request].
@ -189,7 +189,7 @@ end-user-oriented GUI library, while keeping [the ecosystem] modular:
<p align="center">
<a href="ECOSYSTEM.md">
<img alt="iced ecosystem" src="docs/graphs/ecosystem.png" width="80%">
<img alt="The Iced Ecosystem" src="docs/graphs/ecosystem.png" width="80%">
</a>
</p>
@ -222,7 +222,7 @@ iced = { version = "0.3", default-features = false, features = ["glow"] }
but if you don't, right now there's no software fallback, so it means your hardware
doesn't support Iced.
[built-in renderer]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md#Renderers
[built-in renderer]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md#Renderers
## Contributing / Feedback
Contributions are greatly appreciated! If you want to contribute, please
@ -234,15 +234,15 @@ awesome folks) over the `#games-and-graphics` and `#gui-and-ui` channels in
the [Rust Community Discord]. I go by `lone_scientist#9554` there.
## Sponsors
The development of iced is sponsored by the [Cryptowatch] team at [Kraken.com]
The development of Iced is sponsored by the [Cryptowatch] team at [Kraken.com]
[documentation]: https://docs.rs/iced/
[examples]: https://github.com/hecrj/iced/tree/master/examples
[examples]: https://github.com/iced-rs/iced/tree/master/examples
[Coffee]: https://github.com/hecrj/coffee
[Elm]: https://elm-lang.org/
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
[the current issues]: https://github.com/hecrj/iced/issues
[contributing guidelines]: https://github.com/hecrj/iced/blob/master/CONTRIBUTING.md
[the current issues]: https://github.com/iced-rs/iced/issues
[contributing guidelines]: https://github.com/iced-rs/iced/blob/master/CONTRIBUTING.md
[Discord server]: https://discord.gg/3xZJ65GAhd
[Rust Community Discord]: https://bit.ly/rust-community
[Cryptowatch]: https://cryptowat.ch/charts

View file

@ -41,21 +41,29 @@ impl Modifiers {
};
/// Returns true if the [`SHIFT`] key is pressed in the [`Modifiers`].
///
/// [`SHIFT`]: Self::SHIFT
pub fn shift(self) -> bool {
self.contains(Self::SHIFT)
}
/// Returns true if the [`CTRL`] key is pressed in the [`Modifiers`].
///
/// [`CTRL`]: Self::CTRL
pub fn control(self) -> bool {
self.contains(Self::CTRL)
}
/// Returns true if the [`ALT`] key is pressed in the [`Modifiers`].
///
/// [`ALT`]: Self::ALT
pub fn alt(self) -> bool {
self.contains(Self::ALT)
}
/// Returns true if the [`LOGO`] key is pressed in the [`Modifiers`].
///
/// [`LOGO`]: Self::LOGO
pub fn logo(self) -> bool {
self.contains(Self::LOGO)
}

View file

@ -7,8 +7,11 @@
//! ![The foundations of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/foundations.png?raw=true)
//!
//! [Iced]: https://github.com/iced-rs/iced
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/master/native
//! [`iced_web`]: https://github.com/iced-rs/iced/tree/master/web
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
//! [`iced_web`]: https://github.com/iced-rs/iced_web
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unused_results)]

View file

@ -17,7 +17,7 @@ impl<T> Command<T> {
Self(Internal::None)
}
/// Creates a [`Command`] that performs a single [`Action`].
/// Creates a [`Command`] that performs a single action.
pub const fn single(action: T) -> Self {
Self(Internal::Single(action))
}

View file

@ -9,6 +9,8 @@ use std::marker::PhantomData;
///
/// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any
/// [`Command`] or [`Subscription`] and get notified of the results!
///
/// [`Command`]: crate::Command
#[derive(Debug)]
pub struct Runtime<Hasher, Event, Executor, Sender, Message> {
executor: Executor,
@ -51,10 +53,12 @@ where
self.executor.enter(f)
}
/// Spawns a [`Command`] in the [`Runtime`].
/// Spawns a [`Future`] in the [`Runtime`].
///
/// The resulting `Message` will be forwarded to the `Sender` of the
/// [`Runtime`].
///
/// [`Future`]: BoxFuture
pub fn spawn(&mut self, future: BoxFuture<Message>) {
use futures::{FutureExt, SinkExt};

View file

@ -125,9 +125,9 @@ impl<I, O, H> std::fmt::Debug for Subscription<I, O, H> {
/// - [`stopwatch`], a watch with start/stop and reset buttons showcasing how
/// to listen to time.
///
/// [examples]: https://github.com/iced-rs/iced/tree/0.3/examples
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.3/examples/download_progress
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.3/examples/stopwatch
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.4/examples/download_progress
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.4/examples/stopwatch
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
/// The events that will be produced by a [`Subscription`] with this
/// [`Recipe`].

View file

@ -1,12 +1,12 @@
# `iced_glow`
[![Documentation](https://docs.rs/iced_glow/badge.svg)][documentation]
[![Crates.io](https://img.shields.io/crates/v/iced_glow.svg)](https://crates.io/crates/iced_glow)
[![License](https://img.shields.io/crates/l/iced_glow.svg)](https://github.com/hecrj/iced/blob/master/LICENSE)
[![License](https://img.shields.io/crates/l/iced_glow.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
`iced_glow` is a [`glow`] renderer for [`iced_native`]. This renderer supports OpenGL 3.0+ and OpenGL ES 2.0.
This is renderer is mostly used as a fallback for hardware that doesn't support [`wgpu`] (Vulkan, Metal or DX12).
This renderer is mostly used as a fallback for hardware that doesn't support [`wgpu`] (Vulkan, Metal or DX12).
Currently, `iced_glow` supports the following primitives:
- Text, which is rendered using [`glow_glyph`]. No shaping at all.
@ -34,7 +34,7 @@ iced_glow = "0.2"
__Iced moves fast and the `master` branch can contain breaking changes!__ If
you want to learn about a specific release, check out [the release list].
[the release list]: https://github.com/hecrj/iced/releases
[the release list]: https://github.com/iced-rs/iced/releases
## Current limitations

View file

@ -13,7 +13,7 @@ use iced_native::{Font, Size};
/// A [`glow`] graphics backend for [`iced`].
///
/// [`glow`]: https://github.com/grovesNL/glow
/// [`iced`]: https://github.com/hecrj/iced
/// [`iced`]: https://github.com/iced-rs/iced
#[derive(Debug)]
pub struct Backend {
quad_pipeline: quad::Pipeline,

View file

@ -1,9 +1,9 @@
//! A [`glow`] renderer for [`iced_native`].
//!
//! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//!
//! [`glow`]: https://github.com/grovesNL/glow
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]
@ -37,5 +37,5 @@ pub use iced_native::{Alignment, Background, Color, Command, Length, Vector};
/// A [`glow`] graphics renderer for [`iced`].
///
/// [`glow`]: https://github.com/grovesNL/glow
/// [`iced`]: https://github.com/hecrj/iced
/// [`iced`]: https://github.com/iced-rs/iced
pub type Renderer = iced_graphics::Renderer<Backend>;

View file

@ -1,9 +1,9 @@
//! A bunch of backend-agnostic types that can be leveraged to build a renderer
//! for [`iced`].
//!
//! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//!
//! [`iced`]: https://github.com/hecrj/iced
//! [`iced`]: https://github.com/iced-rs/iced
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]

View file

@ -51,10 +51,10 @@ use std::marker::PhantomData;
/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget
/// and showcasing how to compose different transforms.
///
/// [examples]: https://github.com/hecrj/iced/tree/master/examples
/// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock
/// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life
/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.4/examples/clock
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.4/examples/game_of_life
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.4/examples/solar_system
///
/// ## Drawing a simple circle
/// If you want to get a quick overview, here's how we can draw a simple circle:

View file

@ -10,10 +10,10 @@ use crate::Rectangle;
///
/// [`Canvas`]: crate::widget::Canvas
pub trait Program<Message> {
/// The internal [`State`] mutated by the [`Program`].
/// The internal state mutated by the [`Program`].
type State: Default + 'static;
/// Updates the state of the [`Program`].
/// Updates the [`State`](Self::State) of the [`Program`].
///
/// When a [`Program`] is used in a [`Canvas`], the runtime will call this
/// method for each [`Event`].

View file

@ -40,7 +40,8 @@ pub trait Compositor: Sized {
/// Presents the [`Renderer`] primitives to the next frame of the given [`Surface`].
///
/// [`SwapChain`]: Self::SwapChain
/// [`Renderer`]: Self::Renderer
/// [`Surface`]: Self::Surface
fn present<T: AsRef<str>>(
&mut self,
renderer: &mut Self::Renderer,
@ -51,7 +52,7 @@ pub trait Compositor: Sized {
) -> Result<(), SurfaceError>;
}
/// Result of an unsuccessful call to [`Compositor::draw`].
/// Result of an unsuccessful call to [`Compositor::present`].
#[derive(Clone, PartialEq, Eq, Debug, Error)]
pub enum SurfaceError {
/// A timeout was encountered while trying to acquire the next frame.

View file

@ -1,7 +1,12 @@
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod component;
pub mod responsive;
#[cfg(feature = "pure")]
#[cfg_attr(docsrs, doc(cfg(feature = "pure")))]
pub mod pure;
pub use component::Component;

View file

@ -10,6 +10,8 @@ use std::fmt;
/// [`Command`]: crate::Command
pub enum Action<T> {
/// Run a [`Future`] to completion.
///
/// [`Future`]: iced_futures::BoxFuture
Future(iced_futures::BoxFuture<T>),
/// Run a clipboard action.
@ -21,6 +23,8 @@ pub enum Action<T> {
impl<T> Action<T> {
/// Applies a transformation to the result of a [`Command`].
///
/// [`Command`]: crate::Command
pub fn map<A>(
self,
f: impl Fn(T) -> A + 'static + MaybeSend + Sync,

View file

@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher as _};
use std::path::PathBuf;
use std::sync::Arc;
/// An [`Image`] handle.
/// A handle of some image data.
#[derive(Debug, Clone)]
pub struct Handle {
id: u64,
@ -79,7 +79,7 @@ impl Hash for Handle {
}
}
/// The data of an [`Image`].
/// The data of a raster image.
#[derive(Clone, Hash)]
pub enum Data {
/// File data

View file

@ -23,8 +23,8 @@
//! - Build a new renderer, see the [renderer] module.
//! - Build a custom widget, start at the [`Widget`] trait.
//!
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/master/core
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/master/winit
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.4/core
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.4/winit
//! [`druid`]: https://github.com/xi-editor/druid
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
//! [renderer]: crate::renderer

View file

@ -63,7 +63,7 @@ where
event::Status::Ignored
}
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
/// Returns the current [`mouse::Interaction`] of the [`Overlay`].
///
/// By default, it returns [`mouse::Interaction::Idle`].
fn mouse_interaction(

View file

@ -1,24 +1,4 @@
//! Write your own renderer.
//!
//! You will need to implement the `Renderer` trait first. It simply contains
//! an `Output` associated type.
//!
//! There is no common trait to draw all the widgets. Instead, every [`Widget`]
//! constrains its generic `Renderer` type as necessary.
//!
//! This approach is flexible and composable. For instance, the
//! [`Text`] widget only needs a [`text::Renderer`] while a [`Checkbox`] widget
//! needs both a [`text::Renderer`] and a [`checkbox::Renderer`], reusing logic.
//!
//! In the end, a __renderer__ satisfying all the constraints is
//! needed to build a [`UserInterface`].
//!
//! [`Widget`]: crate::Widget
//! [`UserInterface`]: crate::UserInterface
//! [`Text`]: crate::widget::Text
//! [`text::Renderer`]: crate::widget::text::Renderer
//! [`Checkbox`]: crate::widget::Checkbox
//! [`checkbox::Renderer`]: crate::widget::checkbox::Renderer
#[cfg(debug_assertions)]
mod null;
#[cfg(debug_assertions)]
@ -27,8 +7,7 @@ pub use null::Null;
use crate::layout;
use crate::{Background, Color, Element, Rectangle, Vector};
/// A component that can take the state of a user interface and produce an
/// output for its users.
/// A component that can be used by widgets to draw themselves on a screen.
pub trait Renderer: Sized {
/// Lays out the elements of a user interface.
///

View file

@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher as _};
use std::path::PathBuf;
use std::sync::Arc;
/// An [`Svg`] handle.
/// A handle of Svg data.
#[derive(Debug, Clone)]
pub struct Handle {
id: u64,
@ -55,7 +55,7 @@ impl Hash for Handle {
}
}
/// The data of an [`Svg`].
/// The data of a vectorial image.
#[derive(Clone, Hash)]
pub enum Data {
/// File data

View file

@ -39,7 +39,7 @@ pub enum Hit {
}
impl Hit {
/// Computes the cursor position corresponding to this [`HitTestResult`] .
/// Computes the cursor position of the [`Hit`] .
pub fn cursor(self) -> usize {
match self {
Self::CharOffset(i) => i,

View file

@ -16,7 +16,7 @@ use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
/// The [`integration` example] uses a [`UserInterface`] to integrate Iced in
/// an existing graphical application.
///
/// [`integration` example]: https://github.com/iced-rs/iced/tree/0.3/examples/integration
/// [`integration` example]: https://github.com/iced-rs/iced/tree/0.4/examples/integration
#[allow(missing_debug_implementations)]
pub struct UserInterface<'a, Message, Renderer> {
root: Element<'a, Message, Renderer>,
@ -264,11 +264,10 @@ where
/// Draws the [`UserInterface`] with the provided [`Renderer`].
///
/// It returns the some [`Renderer::Output`]. You should update the icon of
/// the mouse cursor accordingly in your system.
/// It returns the current [`mouse::Interaction`]. You should update the
/// icon of the mouse cursor accordingly in your system.
///
/// [`Renderer`]: crate::Renderer
/// [`Renderer::Output`]: crate::Renderer::Output
///
/// # Example
/// We can finally draw our [counter](index.html#usage) by

View file

@ -93,12 +93,12 @@ use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell};
/// - [`geometry`], a custom widget showcasing how to draw geometry with the
/// `Mesh2D` primitive in [`iced_wgpu`].
///
/// [examples]: https://github.com/iced-rs/iced/tree/0.3/examples
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.3/examples/bezier_tool
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.3/examples/custom_widget
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.3/examples/geometry
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.4/examples/bezier_tool
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.4/examples/custom_widget
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.4/examples/geometry
/// [`lyon`]: https://github.com/nical/lyon
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.3/wgpu
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/wgpu
pub trait Widget<Message, Renderer>
where
Renderer: crate::Renderer,

View file

@ -102,7 +102,7 @@ impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> {
/// Sets the [`Font`] of the text of the [`Checkbox`].
///
/// [`Font`]: crate::widget::text::Renderer::Font
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self

View file

@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
/// Sets the vertical spacing _between_ elements.
///
/// Custom margins per element do not exist in Iced. You should use this
/// Custom margins per element do not exist in iced. You should use this
/// method instead! While less flexible, it helps you keep spacing between
/// elements consistent.
pub fn spacing(mut self, units: u16) -> Self {

View file

@ -6,7 +6,7 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
mod axis;
mod configuration;
mod content;

View file

@ -2,7 +2,7 @@ use crate::widget::pane_grid::Axis;
/// The arrangement of a [`PaneGrid`].
///
/// [`PaneGrid`]: crate::pane_grid::PaneGrid
/// [`PaneGrid`]: crate::widget::PaneGrid
#[derive(Debug, Clone)]
pub enum Configuration<T> {
/// A split of the available space.
@ -21,6 +21,6 @@ pub enum Configuration<T> {
},
/// A [`Pane`].
///
/// [`Pane`]: crate::pane_grid::Pane
/// [`Pane`]: crate::widget::pane_grid::Pane
Pane(T),
}

View file

@ -55,7 +55,7 @@ where
{
/// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].
///
/// [`Renderer`]: crate::widget::pane_grid::Renderer
/// [`Renderer`]: crate::Renderer
pub fn draw(
&self,
renderer: &mut Renderer,

View file

@ -1,4 +1,6 @@
//! The state of a [`PaneGrid`].
//!
//! [`PaneGrid`]: crate::widget::PaneGrid
use crate::widget::pane_grid::{
Axis, Configuration, Direction, Node, Pane, Split,
};
@ -21,9 +23,13 @@ use std::collections::{BTreeMap, HashMap};
#[derive(Debug, Clone)]
pub struct State<T> {
/// The panes of the [`PaneGrid`].
///
/// [`PaneGrid`]: crate::widget::PaneGrid
pub panes: HashMap<Pane, T>,
/// The internal state of the [`PaneGrid`].
///
/// [`PaneGrid`]: crate::widget::PaneGrid
pub internal: Internal,
pub(super) action: Action,
@ -198,6 +204,8 @@ impl<T> State<T> {
}
/// The internal state of a [`PaneGrid`].
///
/// [`PaneGrid`]: crate::widget::PaneGrid
#[derive(Debug, Clone)]
pub struct Internal {
layout: Node,
@ -207,6 +215,8 @@ pub struct Internal {
impl Internal {
/// Initializes the [`Internal`] state of a [`PaneGrid`] from a
/// [`Configuration`].
///
/// [`PaneGrid`]: crate::widget::PaneGrid
pub fn from_configuration<T>(
panes: &mut HashMap<Pane, T>,
content: Configuration<T>,
@ -248,11 +258,17 @@ impl Internal {
}
/// The current action of a [`PaneGrid`].
///
/// [`PaneGrid`]: crate::widget::PaneGrid
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Action {
/// The [`PaneGrid`] is idle.
///
/// [`PaneGrid`]: crate::widget::PaneGrid
Idle,
/// A [`Pane`] in the [`PaneGrid`] is being dragged.
///
/// [`PaneGrid`]: crate::widget::PaneGrid
Dragging {
/// The [`Pane`] being dragged.
pane: Pane,
@ -260,6 +276,8 @@ pub enum Action {
origin: Point,
},
/// A [`Split`] in the [`PaneGrid`] is being dragged.
///
/// [`PaneGrid`]: crate::widget::PaneGrid
Resizing {
/// The [`Split`] being dragged.
split: Split,
@ -288,6 +306,8 @@ impl Action {
impl Internal {
/// Calculates the current [`Pane`] regions from the [`PaneGrid`] layout.
///
/// [`PaneGrid`]: crate::widget::PaneGrid
pub fn pane_regions(
&self,
spacing: f32,
@ -297,6 +317,8 @@ impl Internal {
}
/// Calculates the current [`Split`] regions from the [`PaneGrid`] layout.
///
/// [`PaneGrid`]: crate::widget::PaneGrid
pub fn split_regions(
&self,
spacing: f32,

View file

@ -82,7 +82,7 @@ where
{
/// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].
///
/// [`Renderer`]: crate::widget::pane_grid::Renderer
/// [`Renderer`]: crate::Renderer
pub fn draw(
&self,
renderer: &mut Renderer,

View file

@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
/// Sets the horizontal spacing _between_ elements.
///
/// Custom margins per element do not exist in Iced. You should use this
/// Custom margins per element do not exist in iced. You should use this
/// method instead! While less flexible, it helps you keep spacing between
/// elements consistent.
pub fn spacing(mut self, units: u16) -> Self {

View file

@ -59,7 +59,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
/// Sets the [`Font`] of the [`Text`].
///
/// [`Font`]: Renderer::Font
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
self.font = font.into();
self
@ -77,7 +77,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
self
}
/// Sets the [`HorizontalAlignment`] of the [`Text`].
/// Sets the [`alignment::Horizontal`] of the [`Text`].
pub fn horizontal_alignment(
mut self,
alignment: alignment::Horizontal,
@ -86,7 +86,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
self
}
/// Sets the [`VerticalAlignment`] of the [`Text`].
/// Sets the [`alignment::Vertical`] of the [`Text`].
pub fn vertical_alignment(
mut self,
alignment: alignment::Vertical,

View file

@ -108,10 +108,9 @@ where
self
}
/// Sets the [`Font`] of the [`Text`].
/// Sets the [`Font`] of the [`TextInput`].
///
/// [`Font`]: crate::widget::text::Renderer::Font
/// [`Text`]: crate::widget::Text
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self
@ -157,6 +156,8 @@ where
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
/// [`Value`] if provided.
///
/// [`Renderer`]: text::Renderer
pub fn draw(
&self,
renderer: &mut Renderer,
@ -570,6 +571,8 @@ where
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
/// [`Value`] if provided.
///
/// [`Renderer`]: text::Renderer
pub fn draw<Renderer>(
renderer: &mut Renderer,
layout: Layout<'_>,

View file

@ -107,6 +107,8 @@ impl<'a, Message, Renderer: text::Renderer> Toggler<'a, Message, Renderer> {
}
/// Sets the [`Font`] of the text of the [`Toggler`]
///
/// [`Font`]: crate::text::Renderer::Font
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self

View file

@ -29,7 +29,7 @@ where
/// The default padding of a [`Tooltip`] drawn by this renderer.
const DEFAULT_PADDING: u16 = 5;
/// Creates an empty [`Tooltip`].
/// Creates a new [`Tooltip`].
///
/// [`Tooltip`]: struct.Tooltip.html
pub fn new(

View file

@ -8,25 +8,171 @@ use iced_native::mouse;
use iced_native::renderer;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
/// A generic [`Widget`].
///
/// It is useful to build composable user interfaces that do not leak
/// implementation details in their __view logic__.
///
/// If you have a [built-in widget], you should be able to use `Into<Element>`
/// to turn it into an [`Element`].
///
/// [built-in widget]: crate::widget
pub struct Element<'a, Message, Renderer> {
widget: Box<dyn Widget<Message, Renderer> + 'a>,
}
impl<'a, Message, Renderer> Element<'a, Message, Renderer> {
/// Creates a new [`Element`] containing the given [`Widget`].
pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self {
Self {
widget: Box::new(widget),
}
}
/// Returns a reference to the [`Widget`] of the [`Element`],
pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> {
self.widget.as_ref()
}
/// Returns a mutable reference to the [`Widget`] of the [`Element`],
pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Renderer> {
self.widget.as_mut()
}
/// Applies a transformation to the produced message of the [`Element`].
///
/// This method is useful when you want to decouple different parts of your
/// UI and make them __composable__.
///
/// # Example
/// Imagine we want to use [our counter](index.html#usage). But instead of
/// showing a single counter, we want to display many of them. We can reuse
/// the `Counter` type as it is!
///
/// We use composition to model the __state__ of our new application:
///
/// ```
/// # mod counter {
/// # pub struct Counter;
/// # }
/// use counter::Counter;
///
/// struct ManyCounters {
/// counters: Vec<Counter>,
/// }
/// ```
///
/// We can store the state of multiple counters now. However, the
/// __messages__ we implemented before describe the user interactions
/// of a __single__ counter. Right now, we need to also identify which
/// counter is receiving user interactions. Can we use composition again?
/// Yes.
///
/// ```
/// # mod counter {
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {}
/// # }
/// #[derive(Debug, Clone, Copy)]
/// pub enum Message {
/// Counter(usize, counter::Message)
/// }
/// ```
///
/// We compose the previous __messages__ with the index of the counter
/// producing them. Let's implement our __view logic__ now:
///
/// ```
/// # mod counter {
/// # type Text = iced_pure::widget::Text<iced_native::renderer::Null>;
/// #
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {}
/// # pub struct Counter;
/// #
/// # impl Counter {
/// # pub fn view(&mut self) -> Text {
/// # Text::new("")
/// # }
/// # }
/// # }
/// #
/// # mod iced_wgpu {
/// # pub use iced_native::renderer::Null as Renderer;
/// # }
/// #
/// # use counter::Counter;
/// #
/// # struct ManyCounters {
/// # counters: Vec<Counter>,
/// # }
/// #
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {
/// # Counter(usize, counter::Message)
/// # }
/// use iced_pure::Element;
/// use iced_pure::widget::Row;
/// use iced_wgpu::Renderer;
///
/// impl ManyCounters {
/// pub fn view(&mut self) -> Row<Message, Renderer> {
/// // We can quickly populate a `Row` by folding over our counters
/// self.counters.iter_mut().enumerate().fold(
/// Row::new().spacing(20),
/// |row, (index, counter)| {
/// // We display the counter
/// let element: Element<counter::Message, Renderer> =
/// counter.view().into();
///
/// row.push(
/// // Here we turn our `Element<counter::Message>` into
/// // an `Element<Message>` by combining the `index` and the
/// // message of the `element`.
/// element.map(move |message| Message::Counter(index, message))
/// )
/// }
/// )
/// }
/// }
/// ```
///
/// Finally, our __update logic__ is pretty straightforward: simple
/// delegation.
///
/// ```
/// # mod counter {
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {}
/// # pub struct Counter;
/// #
/// # impl Counter {
/// # pub fn update(&mut self, _message: Message) {}
/// # }
/// # }
/// #
/// # use counter::Counter;
/// #
/// # struct ManyCounters {
/// # counters: Vec<Counter>,
/// # }
/// #
/// # #[derive(Debug, Clone, Copy)]
/// # pub enum Message {
/// # Counter(usize, counter::Message)
/// # }
/// impl ManyCounters {
/// pub fn update(&mut self, message: Message) {
/// match message {
/// Message::Counter(index, counter_msg) => {
/// if let Some(counter) = self.counters.get_mut(index) {
/// counter.update(counter_msg);
/// }
/// }
/// }
/// }
/// }
/// ```
pub fn map<B>(
self,
f: impl Fn(Message) -> B + 'a,

View file

@ -65,7 +65,7 @@ pub fn resolve<Message, Renderer>(
padding: Padding,
spacing: f32,
align_items: Alignment,
items: &[Element<Message, Renderer>],
items: &[Element<'_, Message, Renderer>],
) -> Node
where
Renderer: iced_native::Renderer,

View file

@ -1,3 +1,4 @@
//! Helper functions to create pure widgets.
use crate::widget;
use crate::Element;
@ -5,6 +6,9 @@ use iced_native::Length;
use std::borrow::Cow;
use std::ops::RangeInclusive;
/// Creates a new [`Container`] with the provided content.
///
/// [`Container`]: widget::Container
pub fn container<'a, Message, Renderer>(
content: impl Into<Element<'a, Message, Renderer>>,
) -> widget::Container<'a, Message, Renderer>
@ -14,15 +18,24 @@ where
widget::Container::new(content)
}
/// Creates a new [`Column`].
///
/// [`Column`]: widget::Column
pub fn column<'a, Message, Renderer>() -> widget::Column<'a, Message, Renderer>
{
widget::Column::new()
}
/// Creates a new [`Row`].
///
/// [`Row`]: widget::Row
pub fn row<'a, Message, Renderer>() -> widget::Row<'a, Message, Renderer> {
widget::Row::new()
}
/// Creates a new [`Scrollable`] with the provided content.
///
/// [`Scrollable`]: widget::Scrollable
pub fn scrollable<'a, Message, Renderer>(
content: impl Into<Element<'a, Message, Renderer>>,
) -> widget::Scrollable<'a, Message, Renderer>
@ -32,12 +45,19 @@ where
widget::Scrollable::new(content)
}
/// Creates a new [`Button`] with the provided content.
///
/// [`Button`]: widget::Button
pub fn button<'a, Message, Renderer>(
content: impl Into<Element<'a, Message, Renderer>>,
) -> widget::Button<'a, Message, Renderer> {
widget::Button::new(content)
}
/// Creates a new [`Tooltip`] with the provided content, tooltip text, and [`tooltip::Position`].
///
/// [`Tooltip`]: widget::Tooltip
/// [`tooltip::Position`]: widget::tooltip::Position
pub fn tooltip<'a, Message, Renderer>(
content: impl Into<Element<'a, Message, Renderer>>,
tooltip: impl ToString,
@ -49,6 +69,9 @@ where
widget::Tooltip::new(content, tooltip, position)
}
/// Creates a new [`Text`] widget with the provided content.
///
/// [`Text`]: widget::Text
pub fn text<Renderer>(text: impl Into<String>) -> widget::Text<Renderer>
where
Renderer: iced_native::text::Renderer,
@ -56,6 +79,9 @@ where
widget::Text::new(text)
}
/// Creates a new [`Checkbox`].
///
/// [`Checkbox`]: widget::Checkbox
pub fn checkbox<'a, Message, Renderer>(
label: impl Into<String>,
is_checked: bool,
@ -67,6 +93,9 @@ where
widget::Checkbox::new(is_checked, label, f)
}
/// Creates a new [`Radio`].
///
/// [`Radio`]: widget::Radio
pub fn radio<'a, Message, Renderer, V>(
label: impl Into<String>,
value: V,
@ -81,6 +110,9 @@ where
widget::Radio::new(value, label, selected, on_click)
}
/// Creates a new [`Toggler`].
///
/// [`Toggler`]: widget::Toggler
pub fn toggler<'a, Message, Renderer>(
label: impl Into<Option<String>>,
is_checked: bool,
@ -92,6 +124,9 @@ where
widget::Toggler::new(is_checked, label, f)
}
/// Creates a new [`TextInput`].
///
/// [`TextInput`]: widget::TextInput
pub fn text_input<'a, Message, Renderer>(
placeholder: &str,
value: &str,
@ -104,6 +139,9 @@ where
widget::TextInput::new(placeholder, value, on_change)
}
/// Creates a new [`Slider`].
///
/// [`Slider`]: widget::Slider
pub fn slider<'a, Message, T>(
range: std::ops::RangeInclusive<T>,
value: T,
@ -116,6 +154,9 @@ where
widget::Slider::new(range, value, on_change)
}
/// Creates a new [`PickList`].
///
/// [`PickList`]: widget::PickList
pub fn pick_list<'a, Message, Renderer, T>(
options: impl Into<Cow<'a, [T]>>,
selected: Option<T>,
@ -129,24 +170,37 @@ where
widget::PickList::new(options, selected, on_selected)
}
/// Creates a new [`Image`].
///
/// [`Image`]: widget::Image
pub fn image<Handle>(handle: impl Into<Handle>) -> widget::Image<Handle> {
widget::Image::new(handle.into())
}
/// Creates a new horizontal [`Space`] with the given [`Length`].
///
/// [`Space`]: widget::Space
pub fn horizontal_space(width: Length) -> widget::Space {
widget::Space::with_width(width)
}
/// Creates a new vertical [`Space`] with the given [`Length`].
///
/// [`Space`]: widget::Space
pub fn vertical_space(height: Length) -> widget::Space {
widget::Space::with_height(height)
}
/// Creates a horizontal [`Rule`] with the given height.
///
/// [`Rule`]: widget::Rule
pub fn horizontal_rule<'a>(height: u16) -> widget::Rule<'a> {
widget::Rule::horizontal(height)
}
/// Creates a vertical [`Rule`] with the given width.
///
/// [`Rule`]: widget::Rule
pub fn vertical_rule<'a>(width: u16) -> widget::Rule<'a> {
widget::Rule::horizontal(width)
}
@ -154,8 +208,10 @@ pub fn vertical_rule<'a>(width: u16) -> widget::Rule<'a> {
/// Creates a new [`ProgressBar`].
///
/// It expects:
/// * an inclusive range of possible values
/// * the current value of the [`ProgressBar`]
/// * an inclusive range of possible values, and
/// * the current value of the [`ProgressBar`].
///
/// [`ProgressBar`]: widget::ProgressBar
pub fn progress_bar<'a>(
range: RangeInclusive<f32>,
value: f32,

View file

@ -1,3 +1,92 @@
//! Stateless, pure widgets for iced.
//!
//! # The Elm Architecture, purity, and continuity
//! As you may know, applications made with `iced` use [The Elm Architecture].
//!
//! In a nutshell, this architecture defines the initial state of the application, a way to `view` it, and a way to `update` it after a user interaction. The `update` logic is called after a meaningful user interaction, which in turn updates the state of the application. Then, the `view` logic is executed to redisplay the application.
//!
//! Since `view` logic is only run after an `update`, all of the mutations to the application state must only happen in the `update` logic. If the application state changes anywhere else, the `view` logic will not be rerun and, therefore, the previously generated `view` may stay outdated.
//!
//! However, the `Application` trait in `iced` defines `view` as:
//!
//! ```ignore
//! pub trait Application {
//! fn view(&mut self) -> Element<Self::Message>;
//! }
//! ```
//!
//! As a consequence, the application state can be mutated in `view` logic. The `view` logic in `iced` is __impure__.
//!
//! This impurity is necessary because `iced` puts the burden of widget __continuity__ on its users. In other words, it's up to you to provide `iced` with the internal state of each widget every time `view` is called.
//!
//! If we take a look at the classic `counter` example:
//!
//! ```ignore
//! struct Counter {
//! value: i32,
//! increment_button: button::State,
//! decrement_button: button::State,
//! }
//!
//! // ...
//!
//! impl Counter {
//! pub fn view(&mut self) -> Column<Message> {
//! Column::new()
//! .push(
//! Button::new(&mut self.increment_button, Text::new("+"))
//! .on_press(Message::IncrementPressed),
//! )
//! .push(Text::new(self.value.to_string()).size(50))
//! .push(
//! Button::new(&mut self.decrement_button, Text::new("-"))
//! .on_press(Message::DecrementPressed),
//! )
//! }
//! }
//! ```
//!
//! We can see how we need to keep track of the `button::State` of each `Button` in our `Counter` state and provide a mutable reference to the widgets in our `view` logic. The widgets produced by `view` are __stateful__.
//!
//! While this approach forces users to keep track of widget state and causes impurity, I originally chose it because it allows `iced` to directly consume the widget tree produced by `view`. Since there is no internal state decoupled from `view` maintained by the runtime, `iced` does not need to compare (e.g. reconciliate) widget trees in order to ensure continuity.
//!
//! # Stateless widgets
//! As the library matures, the need for some kind of persistent widget data (see #553) between `view` calls becomes more apparent (e.g. incremental rendering, animations, accessibility, etc.).
//!
//! If we are going to end up having persistent widget data anyways... There is no reason to have impure, stateful widgets anymore!
//!
//! And so I started exploring and ended up creating a new subcrate called `iced_pure`, which introduces a completely stateless implementation for every widget in `iced`.
//!
//! With the help of this crate, we can now write a pure `counter` example:
//!
//! ```ignore
//! struct Counter {
//! value: i32,
//! }
//!
//! // ...
//!
//! impl Counter {
//! fn view(&self) -> Column<Message> {
//! Column::new()
//! .push(Button::new("Increment").on_press(Message::IncrementPressed))
//! .push(Text::new(self.value.to_string()).size(50))
//! .push(Button::new("Decrement").on_press(Message::DecrementPressed))
//! }
//! }
//! ```
//!
//! Notice how we no longer need to keep track of the `button::State`! The widgets in `iced_pure` do not take any mutable application state in `view`. They are __stateless__ widgets. As a consequence, we do not need mutable access to `self` in `view` anymore. `view` becomes __pure__.
//!
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
#![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)]
#![deny(missing_docs)]
#![deny(unused_results)]
#![forbid(unsafe_code)]
#![forbid(rust_2018_idioms)]
pub mod helpers;
pub mod overlay;
pub mod widget;
@ -16,6 +105,32 @@ use iced_native::mouse;
use iced_native::renderer;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
/// A bridge between impure and pure widgets.
///
/// If you already have an existing `iced` application, you do not need to switch completely to the new traits in order to benefit from the `pure` module. Instead, you can leverage the new `Pure` widget to include `pure` widgets in your impure `Application`.
///
/// For instance, let's say we want to use our pure `Counter` in an impure application:
///
/// ```ignore
/// use iced_pure::{self, Pure};
///
/// struct Impure {
/// state: pure::State,
/// counter: Counter,
/// }
///
/// impl Sandbox for Impure {
/// // ...
///
/// pub fn view(&mut self) -> Element<Self::Message> {
/// Pure::new(&mut self.state, self.counter.view()).into()
/// }
/// }
/// ```
///
/// [`Pure`] acts as a bridge between pure and impure widgets. It is completely opt-in and can be used to slowly migrate your application to the new architecture.
///
/// The purification of your application may trigger a bunch of important refactors, since it's far easier to keep your data decoupled from the GUI state with stateless widgets. For this reason, I recommend starting small in the most nested views of your application and slowly expand the purity upwards.
pub struct Pure<'a, Message, Renderer> {
state: &'a mut State,
element: Element<'a, Message, Renderer>,
@ -26,6 +141,7 @@ where
Message: 'a,
Renderer: iced_native::Renderer + 'a,
{
/// Creates a new [`Pure`] widget with the given [`State`] and impure [`Element`].
pub fn new(
state: &'a mut State,
content: impl Into<Element<'a, Message, Renderer>>,
@ -37,6 +153,7 @@ where
}
}
/// The internal state of a [`Pure`] widget.
pub struct State {
state_tree: widget::Tree,
}
@ -48,6 +165,7 @@ impl Default for State {
}
impl State {
/// Creates a new [`State`] for a [`Pure`] widget.
pub fn new() -> Self {
Self {
state_tree: widget::Tree::empty(),
@ -56,7 +174,7 @@ impl State {
fn diff<Message, Renderer>(
&mut self,
new_element: &Element<Message, Renderer>,
new_element: &Element<'_, Message, Renderer>,
) {
self.state_tree.diff(new_element);
}

View file

@ -1,9 +1,14 @@
//! Display interactive elements on top of other widgets.
use crate::widget::Tree;
use iced_native::Layout;
pub use iced_native::overlay::*;
/// Obtains the first overlay [`Element`] found in the given children.
///
/// This method will generally only be used by advanced users that are
/// implementing the [`Widget`](crate::Widget) trait.
pub fn from_children<'a, Message, Renderer>(
children: &'a [crate::Element<'_, Message, Renderer>],
tree: &'a mut Tree,

View file

@ -1,3 +1,4 @@
//! Use the built-in widgets or create your own.
pub mod button;
pub mod checkbox;
pub mod container;
@ -48,17 +49,28 @@ use iced_native::overlay;
use iced_native::renderer;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
/// A component that displays information and allows interaction.
///
/// If you want to build your own widgets, you will need to implement this
/// trait.
pub trait Widget<Message, Renderer> {
/// Returns the width of the [`Widget`].
fn width(&self) -> Length;
/// Returns the height of the [`Widget`].
fn height(&self) -> Length;
/// Returns the [`layout::Node`] of the [`Widget`].
///
/// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the
/// user interface.
fn layout(
&self,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node;
/// Draws the [`Widget`] using the associated `Renderer`.
fn draw(
&self,
state: &Tree,
@ -69,31 +81,31 @@ pub trait Widget<Message, Renderer> {
viewport: &Rectangle,
);
/// Returns the [`Tag`] of the [`Widget`].
///
/// [`Tag`]: tree::Tag
fn tag(&self) -> tree::Tag {
tree::Tag::stateless()
}
/// Returns the [`State`] of the [`Widget`].
///
/// [`State`]: tree::State
fn state(&self) -> tree::State {
tree::State::None
}
/// Returns the state [`Tree`] of the children of the [`Widget`].
fn children(&self) -> Vec<Tree> {
Vec::new()
}
/// Reconciliates the [`Widget`] with the provided [`Tree`].
fn diff(&self, _tree: &mut Tree) {}
fn mouse_interaction(
&self,
_state: &Tree,
_layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse::Interaction::Idle
}
/// Processes a runtime [`Event`].
///
/// By default, it does nothing.
fn on_event(
&mut self,
_state: &mut Tree,
@ -107,6 +119,21 @@ pub trait Widget<Message, Renderer> {
event::Status::Ignored
}
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
///
/// By default, it returns [`mouse::Interaction::Idle`].
fn mouse_interaction(
&self,
_state: &Tree,
_layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse::Interaction::Idle
}
/// Returns the overlay of the [`Widget`], if there is any.
fn overlay<'a>(
&'a self,
_state: &'a mut Tree,

View file

@ -1,3 +1,4 @@
//! Allow your users to perform actions by pressing a button.
use crate::overlay;
use crate::widget::tree::{self, Tree};
use crate::{Element, Widget};
@ -15,6 +16,40 @@ pub use iced_style::button::{Style, StyleSheet};
use button::State;
/// A generic widget that produces a message when pressed.
///
/// ```
/// # type Button<'a, Message> =
/// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>;
/// #
/// #[derive(Clone)]
/// enum Message {
/// ButtonPressed,
/// }
///
/// let button = Button::new("Press me!").on_press(Message::ButtonPressed);
/// ```
///
/// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will
/// be disabled:
///
/// ```
/// # type Button<'a, Message> =
/// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>;
/// #
/// #[derive(Clone)]
/// enum Message {
/// ButtonPressed,
/// }
///
/// fn disabled_button<'a>() -> Button<'a, Message> {
/// Button::new("I'm disabled!")
/// }
///
/// fn enabled_button<'a>() -> Button<'a, Message> {
/// disabled_button().on_press(Message::ButtonPressed)
/// }
/// ```
pub struct Button<'a, Message, Renderer> {
content: Element<'a, Message, Renderer>,
on_press: Option<Message>,
@ -25,6 +60,7 @@ pub struct Button<'a, Message, Renderer> {
}
impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
/// Creates a new [`Button`] with the given content.
pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self {
Button {
content: content.into(),

View file

@ -1,3 +1,4 @@
//! Show toggle controls using checkboxes.
use crate::widget::Tree;
use crate::{Element, Widget};

View file

@ -13,6 +13,7 @@ use iced_native::{
use std::u32;
/// A container that distributes its contents vertically.
pub struct Column<'a, Message, Renderer> {
spacing: u16,
padding: Padding,
@ -24,10 +25,12 @@ pub struct Column<'a, Message, Renderer> {
}
impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
/// Creates an empty [`Column`].
pub fn new() -> Self {
Self::with_children(Vec::new())
}
/// Creates a [`Column`] with the given elements.
pub fn with_children(
children: Vec<Element<'a, Message, Renderer>>,
) -> Self {
@ -42,21 +45,29 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
}
}
/// Sets the vertical spacing _between_ elements.
///
/// Custom margins per element do not exist in iced. You should use this
/// method instead! While less flexible, it helps you keep spacing between
/// elements consistent.
pub fn spacing(mut self, units: u16) -> Self {
self.spacing = units;
self
}
/// Sets the [`Padding`] of the [`Column`].
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into();
self
}
/// Sets the width of the [`Column`].
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
/// Sets the height of the [`Column`].
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
@ -68,11 +79,13 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
self
}
/// Sets the horizontal alignment of the contents of the [`Column`] .
pub fn align_items(mut self, align: Alignment) -> Self {
self.align_items = align;
self
}
/// Adds an element to the [`Column`].
pub fn push(
mut self,
child: impl Into<Element<'a, Message, Renderer>>,

View file

@ -1,3 +1,4 @@
//! Display images in your user interface.
use crate::widget::{Tree, Widget};
use crate::Element;

View file

@ -6,7 +6,7 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
mod content;
mod title_bar;
@ -213,7 +213,7 @@ where
fn diff(&self, tree: &mut Tree) {
tree.diff_children_custom(
&self.elements,
|(_, content), state| content.diff(state),
|state, (_, content)| content.diff(state),
|(_, content)| content.state(),
)
}

View file

@ -57,7 +57,7 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
{
pub fn state(&self) -> Tree {
pub(super) fn state(&self) -> Tree {
let children = if let Some(title_bar) = self.title_bar.as_ref() {
vec![Tree::new(&self.body), title_bar.state()]
} else {
@ -70,7 +70,7 @@ where
}
}
pub fn diff(&self, tree: &mut Tree) {
pub(super) fn diff(&self, tree: &mut Tree) {
if tree.children.len() == 2 {
if let Some(title_bar) = self.title_bar.as_ref() {
title_bar.diff(&mut tree.children[1]);
@ -84,7 +84,7 @@ where
/// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].
///
/// [`Renderer`]: crate::widget::pane_grid::Renderer
/// [`Renderer`]: iced_native::Renderer
pub fn draw(
&self,
tree: &Tree,

View file

@ -81,7 +81,7 @@ impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer>
where
Renderer: iced_native::Renderer,
{
pub fn state(&self) -> Tree {
pub(super) fn state(&self) -> Tree {
let children = if let Some(controls) = self.controls.as_ref() {
vec![Tree::new(&self.content), Tree::new(controls)]
} else {
@ -94,7 +94,7 @@ where
}
}
pub fn diff(&self, tree: &mut Tree) {
pub(super) fn diff(&self, tree: &mut Tree) {
if tree.children.len() == 2 {
if let Some(controls) = self.controls.as_ref() {
tree.children[1].diff(controls);
@ -108,7 +108,7 @@ where
/// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].
///
/// [`Renderer`]: crate::widget::pane_grid::Renderer
/// [`Renderer`]: iced_native::Renderer
pub fn draw(
&self,
tree: &Tree,

View file

@ -43,9 +43,8 @@ where
/// The default padding of a [`PickList`].
pub const DEFAULT_PADDING: Padding = Padding::new(5);
/// Creates a new [`PickList`] with the given [`State`], a list of options,
/// the current selected value, and the message to produce when an option is
/// selected.
/// Creates a new [`PickList`] with the given list of options, the current
/// selected value, and the message to produce when an option is selected.
pub fn new(
options: impl Into<Cow<'a, [T]>>,
selected: Option<T>,

View file

@ -1,3 +1,4 @@
//! Provide progress feedback to your users.
use crate::widget::Tree;
use crate::{Element, Widget};

View file

@ -1,3 +1,4 @@
//! Create choices using radio buttons.
use crate::widget::Tree;
use crate::{Element, Widget};

View file

@ -11,6 +11,7 @@ use iced_native::{
Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell,
};
/// A container that distributes its contents horizontally.
pub struct Row<'a, Message, Renderer> {
spacing: u16,
padding: Padding,
@ -21,10 +22,12 @@ pub struct Row<'a, Message, Renderer> {
}
impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
/// Creates an empty [`Row`].
pub fn new() -> Self {
Self::with_children(Vec::new())
}
/// Creates a [`Row`] with the given elements.
pub fn with_children(
children: Vec<Element<'a, Message, Renderer>>,
) -> Self {
@ -38,31 +41,41 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
}
}
/// Sets the horizontal spacing _between_ elements.
///
/// Custom margins per element do not exist in iced. You should use this
/// method instead! While less flexible, it helps you keep spacing between
/// elements consistent.
pub fn spacing(mut self, units: u16) -> Self {
self.spacing = units;
self
}
/// Sets the [`Padding`] of the [`Row`].
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into();
self
}
/// Sets the width of the [`Row`].
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
/// Sets the height of the [`Row`].
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
/// Sets the vertical alignment of the contents of the [`Row`] .
pub fn align_items(mut self, align: Alignment) -> Self {
self.align_items = align;
self
}
/// Adds an [`Element`] to the [`Row`].
pub fn push(
mut self,
child: impl Into<Element<'a, Message, Renderer>>,

View file

@ -1,3 +1,4 @@
//! Display a horizontal or vertical rule for dividing content.
use crate::widget::Tree;
use crate::{Element, Widget};

View file

@ -1,3 +1,4 @@
//! Navigate an endless amount of content with a scrollbar.
use crate::overlay;
use crate::widget::tree::{self, Tree};
use crate::{Element, Widget};

View file

@ -1,6 +1,4 @@
//! Display an interactive selector of a single value from a range of values.
//!
//! A [`Slider`] has some local [`State`].
use crate::widget::tree::{self, Tree};
use crate::{Element, Widget};
@ -25,17 +23,16 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
///
/// # Example
/// ```
/// # use iced_native::widget::slider::{self, Slider};
/// # use iced_pure::widget::Slider;
/// #
/// #[derive(Clone)]
/// 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::new(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)

View file

@ -1,3 +1,4 @@
//! Display vector graphics in your application.
use crate::widget::{Tree, Widget};
use crate::Element;

View file

@ -1,3 +1,4 @@
//! Display fields that can be filled with text.
use crate::widget::tree::{self, Tree};
use crate::{Element, Widget};
@ -15,20 +16,15 @@ pub use iced_style::text_input::{Style, StyleSheet};
///
/// # Example
/// ```
/// # use iced_native::renderer::Null;
/// # use iced_native::widget::text_input;
/// #
/// # pub type TextInput<'a, Message> = iced_native::widget::TextInput<'a, Message, Null>;
/// # pub type TextInput<'a, Message> = iced_pure::widget::TextInput<'a, Message, iced_native::renderer::Null>;
/// #[derive(Debug, Clone)]
/// 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,
@ -58,10 +54,9 @@ where
/// Creates a new [`TextInput`].
///
/// It expects:
/// - some [`State`]
/// - a placeholder
/// - the current value
/// - a function that produces a message when the [`TextInput`] changes
/// - a placeholder,
/// - the current value, and
/// - a function that produces a message when the [`TextInput`] changes.
pub fn new<F>(placeholder: &str, value: &str, on_change: F) -> Self
where
F: 'a + Fn(String) -> Message,
@ -86,10 +81,9 @@ where
self
}
/// Sets the [`Font`] of the [`Text`].
/// Sets the [`Font`] of the [`TextInput`].
///
/// [`Font`]: crate::widget::text::Renderer::Font
/// [`Text`]: crate::widget::Text
/// [`Font`]: iced_native::text::Renderer::Font
pub fn font(mut self, font: Renderer::Font) -> Self {
self.font = font;
self

View file

@ -1,3 +1,4 @@
//! Show toggle controls using togglers.
use crate::widget::{Tree, Widget};
use crate::Element;

View file

@ -32,7 +32,7 @@ where
/// The default padding of a [`Tooltip`] drawn by this renderer.
const DEFAULT_PADDING: u16 = 5;
/// Creates an empty [`Tooltip`].
/// Creates a new [`Tooltip`].
///
/// [`Tooltip`]: struct.Tooltip.html
pub fn new(

View file

@ -1,14 +1,24 @@
//! Store internal widget state in a state tree to ensure continuity.
use crate::Element;
use std::any::{self, Any};
/// A persistent state widget tree.
///
/// A [`Tree`] is normally associated with a specific widget in the widget tree.
pub struct Tree {
/// The tag of the [`Tree`].
pub tag: Tag,
/// The [`State`] of the [`Tree`].
pub state: State,
/// The children of the root widget of the [`Tree`].
pub children: Vec<Tree>,
}
impl Tree {
/// Creates an empty, stateless [`Tree`] with no children.
pub fn empty() -> Self {
Self {
tag: Tag::stateless(),
@ -17,6 +27,7 @@ impl Tree {
}
}
/// Creates a new [`Tree`] for the provided [`Element`].
pub fn new<Message, Renderer>(
element: &Element<'_, Message, Renderer>,
) -> Self {
@ -27,6 +38,14 @@ impl Tree {
}
}
/// Reconciliates the current tree with the provided [`Element`].
///
/// If the tag of the [`Element`] matches the tag of the [`Tree`], then the
/// [`Element`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called).
///
/// Otherwise, the whole [`Tree`] is recreated.
///
/// [`Widget::diff`]: crate::Widget::diff
pub fn diff<Message, Renderer>(
&mut self,
new: &Element<'_, Message, Renderer>,
@ -38,21 +57,20 @@ impl Tree {
}
}
/// Reconciliates the children of the tree with the provided list of [`Element`].
pub fn diff_children<Message, Renderer>(
&mut self,
new_children: &[Element<'_, Message, Renderer>],
) {
self.diff_children_custom(
new_children,
|new, child_state| child_state.diff(new),
Self::new,
)
self.diff_children_custom(new_children, Self::diff, Self::new)
}
/// Reconciliates the children of the tree with the provided list of [`Element`] using custom
/// logic both for diffing and creating new widget state.
pub fn diff_children_custom<T>(
&mut self,
new_children: &[T],
diff: impl Fn(&T, &mut Tree),
diff: impl Fn(&mut Tree, &T),
new_state: impl Fn(&T) -> Self,
) {
if self.children.len() > new_children.len() {
@ -62,7 +80,7 @@ impl Tree {
for (child_state, new) in
self.children.iter_mut().zip(new_children.iter())
{
diff(new, child_state);
diff(child_state, new);
}
if self.children.len() < new_children.len() {
@ -73,10 +91,12 @@ impl Tree {
}
}
/// The identifier of some widget state.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Tag(any::TypeId);
impl Tag {
/// Creates a [`Tag`] for a state of type `T`.
pub fn of<T>() -> Self
where
T: 'static,
@ -84,17 +104,23 @@ impl Tag {
Self(any::TypeId::of::<T>())
}
/// Creates a [`Tag`] for a stateless widget.
pub fn stateless() -> Self {
Self::of::<()>()
}
}
/// The internal [`State`] of a widget.
pub enum State {
/// No meaningful internal state.
None,
/// Some meaningful internal state.
Some(Box<dyn Any>),
}
impl State {
/// Creates a new [`State`].
pub fn new<T>(state: T) -> Self
where
T: 'static,
@ -102,6 +128,10 @@ impl State {
State::Some(Box::new(state))
}
/// Downcasts the [`State`] to `T` and returns a reference to it.
///
/// # Panics
/// This method will panic if the downcast fails or the [`State`] is [`State::None`].
pub fn downcast_ref<T>(&self) -> &T
where
T: 'static,
@ -114,6 +144,10 @@ impl State {
}
}
/// Downcasts the [`State`] to `T` and returns a mutable reference to it.
///
/// # Panics
/// This method will panic if the downcast fails or the [`State`] is [`State::None`].
pub fn downcast_mut<T>(&mut self) -> &mut T
where
T: 'static,

View file

@ -37,15 +37,15 @@ use crate::{Color, Command, Element, Executor, Settings, Subscription};
/// to listen to time.
/// - [`todos`], a todos tracker inspired by [TodoMVC].
///
/// [The repository has a bunch of examples]: https://github.com/hecrj/iced/tree/0.3/examples
/// [`clock`]: https://github.com/hecrj/iced/tree/0.3/examples/clock
/// [`download_progress`]: https://github.com/hecrj/iced/tree/0.3/examples/download_progress
/// [`events`]: https://github.com/hecrj/iced/tree/0.3/examples/events
/// [`game_of_life`]: https://github.com/hecrj/iced/tree/0.3/examples/game_of_life
/// [`pokedex`]: https://github.com/hecrj/iced/tree/0.3/examples/pokedex
/// [`solar_system`]: https://github.com/hecrj/iced/tree/0.3/examples/solar_system
/// [`stopwatch`]: https://github.com/hecrj/iced/tree/0.3/examples/stopwatch
/// [`todos`]: https://github.com/hecrj/iced/tree/0.3/examples/todos
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.4/examples
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.4/examples/clock
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.4/examples/download_progress
/// [`events`]: https://github.com/iced-rs/iced/tree/0.4/examples/events
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.4/examples/game_of_life
/// [`pokedex`]: https://github.com/iced-rs/iced/tree/0.4/examples/pokedex
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.4/examples/solar_system
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.4/examples/stopwatch
/// [`todos`]: https://github.com/iced-rs/iced/tree/0.4/examples/todos
/// [`Sandbox`]: crate::Sandbox
/// [`Canvas`]: crate::widget::Canvas
/// [PokéAPI]: https://pokeapi.co/

View file

@ -19,19 +19,19 @@
//!
//! 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
//! [Cross-platform support]: https://github.com/iced-rs/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/incredibledarlingbee
//! [Modular ecosystem]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md
//! [renderer-agnostic native runtime]: https://github.com/hecrj/iced/tree/master/native
//! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
//! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/0.4/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
//! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.4/wgpu
//! [windowing shell]: https://github.com/iced-rs/iced/tree/0.4/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.3/examples
//! [repository]: https://github.com/hecrj/iced
//! [web runtime]: https://github.com/iced-rs/iced_web
//! [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
//! [repository]: https://github.com/iced-rs/iced
//!
//! # Overview
//! Inspired by [The Elm Architecture], Iced expects you to split user
@ -196,6 +196,7 @@ pub mod widget;
pub mod window;
#[cfg(feature = "pure")]
#[cfg_attr(docsrs, doc(cfg(feature = "pure")))]
pub mod pure;
#[cfg(all(not(feature = "glow"), feature = "wgpu"))]

View file

@ -14,6 +14,84 @@
//! offers an alternate [`Application`] trait with a completely pure `view`
//! method.
//!
//! # The Elm Architecture, purity, and continuity
//! As you may know, applications made with `iced` use [The Elm Architecture].
//!
//! In a nutshell, this architecture defines the initial state of the application, a way to `view` it, and a way to `update` it after a user interaction. The `update` logic is called after a meaningful user interaction, which in turn updates the state of the application. Then, the `view` logic is executed to redisplay the application.
//!
//! Since `view` logic is only run after an `update`, all of the mutations to the application state must only happen in the `update` logic. If the application state changes anywhere else, the `view` logic will not be rerun and, therefore, the previously generated `view` may stay outdated.
//!
//! However, the `Application` trait in `iced` defines `view` as:
//!
//! ```ignore
//! pub trait Application {
//! fn view(&mut self) -> Element<Self::Message>;
//! }
//! ```
//!
//! As a consequence, the application state can be mutated in `view` logic. The `view` logic in `iced` is __impure__.
//!
//! This impurity is necessary because `iced` puts the burden of widget __continuity__ on its users. In other words, it's up to you to provide `iced` with the internal state of each widget every time `view` is called.
//!
//! If we take a look at the classic `counter` example:
//!
//! ```ignore
//! struct Counter {
//! value: i32,
//! increment_button: button::State,
//! decrement_button: button::State,
//! }
//!
//! // ...
//!
//! impl Counter {
//! pub fn view(&mut self) -> Column<Message> {
//! Column::new()
//! .push(
//! Button::new(&mut self.increment_button, Text::new("+"))
//! .on_press(Message::IncrementPressed),
//! )
//! .push(Text::new(self.value.to_string()).size(50))
//! .push(
//! Button::new(&mut self.decrement_button, Text::new("-"))
//! .on_press(Message::DecrementPressed),
//! )
//! }
//! }
//! ```
//!
//! We can see how we need to keep track of the `button::State` of each `Button` in our `Counter` state and provide a mutable reference to the widgets in our `view` logic. The widgets produced by `view` are __stateful__.
//!
//! While this approach forces users to keep track of widget state and causes impurity, I originally chose it because it allows `iced` to directly consume the widget tree produced by `view`. Since there is no internal state decoupled from `view` maintained by the runtime, `iced` does not need to compare (e.g. reconciliate) widget trees in order to ensure continuity.
//!
//! # Stateless widgets
//! As the library matures, the need for some kind of persistent widget data (see #553) between `view` calls becomes more apparent (e.g. incremental rendering, animations, accessibility, etc.).
//!
//! If we are going to end up having persistent widget data anyways... There is no reason to have impure, stateful widgets anymore!
//!
//! With the help of this module, we can now write a pure `counter` example:
//!
//! ```ignore
//! struct Counter {
//! value: i32,
//! }
//!
//! // ...
//!
//! impl Counter {
//! fn view(&self) -> Column<Message> {
//! Column::new()
//! .push(Button::new("Increment").on_press(Message::IncrementPressed))
//! .push(Text::new(self.value.to_string()).size(50))
//! .push(Button::new("Decrement").on_press(Message::DecrementPressed))
//! }
//! }
//! ```
//!
//! Notice how we no longer need to keep track of the `button::State`! The widgets in `iced_pure` do not take any mutable application state in `view`. They are __stateless__ widgets. As a consequence, we do not need mutable access to `self` in `view` anymore. `view` becomes __pure__.
//!
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
//!
//! [the original widgets]: crate::widget
//! [`button::State`]: crate::widget::button::State
//! [impure `Application`]: crate::Application
@ -26,6 +104,7 @@ pub use application::Application;
pub use sandbox::Sandbox;
pub use iced_pure::helpers::*;
pub use iced_pure::Widget;
pub use iced_pure::{Pure, State};
/// A generic, pure [`Widget`].

View file

@ -47,7 +47,7 @@ pub mod pane_grid {
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
pub use iced_pure::widget::pane_grid::{
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
ResizeEvent, Split, State, StyleSheet,

View file

@ -35,19 +35,19 @@ use crate::{
/// - [`tour`], a simple UI tour that can run both on native platforms and the
/// web!
///
/// [The repository has a bunch of examples]: https://github.com/hecrj/iced/tree/0.3/examples
/// [`bezier_tool`]: https://github.com/hecrj/iced/tree/0.3/examples/bezier_tool
/// [`counter`]: https://github.com/hecrj/iced/tree/0.3/examples/counter
/// [`custom_widget`]: https://github.com/hecrj/iced/tree/0.3/examples/custom_widget
/// [`geometry`]: https://github.com/hecrj/iced/tree/0.3/examples/geometry
/// [`pane_grid`]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
/// [`progress_bar`]: https://github.com/hecrj/iced/tree/0.3/examples/progress_bar
/// [`styling`]: https://github.com/hecrj/iced/tree/0.3/examples/styling
/// [`svg`]: https://github.com/hecrj/iced/tree/0.3/examples/svg
/// [`tour`]: https://github.com/hecrj/iced/tree/0.3/examples/tour
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.4/examples
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.4/examples/bezier_tool
/// [`counter`]: https://github.com/iced-rs/iced/tree/0.4/examples/counter
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.4/examples/custom_widget
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.4/examples/geometry
/// [`pane_grid`]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
/// [`progress_bar`]: https://github.com/iced-rs/iced/tree/0.4/examples/progress_bar
/// [`styling`]: https://github.com/iced-rs/iced/tree/0.4/examples/styling
/// [`svg`]: https://github.com/iced-rs/iced/tree/0.4/examples/svg
/// [`tour`]: https://github.com/iced-rs/iced/tree/0.4/examples/tour
/// [`Canvas widget`]: crate::widget::Canvas
/// [the overview]: index.html#overview
/// [`iced_wgpu`]: https://github.com/hecrj/iced/tree/0.3/wgpu
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/wgpu
/// [`Svg` widget]: crate::widget::Svg
/// [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
///

View file

@ -63,7 +63,7 @@ pub mod pane_grid {
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support.
//!
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
pub use iced_native::widget::pane_grid::{
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
ResizeEvent, Split, State, StyleSheet,
@ -167,9 +167,11 @@ pub use toggler::Toggler;
pub use tooltip::Tooltip;
#[cfg(feature = "canvas")]
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
pub use iced_graphics::widget::canvas;
#[cfg(feature = "image")]
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
pub mod image {
//! Display images in your user interface.
pub use iced_native::image::Handle;
@ -182,9 +184,11 @@ pub mod image {
}
#[cfg(feature = "qr_code")]
#[cfg_attr(docsrs, doc(cfg(feature = "qr_code")))]
pub use iced_graphics::widget::qr_code;
#[cfg(feature = "svg")]
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
pub mod svg {
//! Display vector graphics in your application.
pub use iced_native::svg::Handle;
@ -192,13 +196,17 @@ pub mod svg {
}
#[cfg(feature = "canvas")]
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
pub use canvas::Canvas;
#[cfg(feature = "image")]
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
pub use image::Image;
#[cfg(feature = "qr_code")]
#[cfg_attr(docsrs, doc(cfg(feature = "qr_code")))]
pub use qr_code::QRCode;
#[cfg(feature = "svg")]
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
pub use svg::Svg;

View file

@ -16,7 +16,7 @@
//! - Meshes of triangles, useful to draw geometry freely.
//!
//! [Iced]: https://github.com/iced-rs/iced
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/master/native
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph

View file

@ -1,7 +1,7 @@
# `iced_winit`
[![Documentation](https://docs.rs/iced_winit/badge.svg)][documentation]
[![Crates.io](https://img.shields.io/crates/v/iced_winit.svg)](https://crates.io/crates/iced_winit)
[![License](https://img.shields.io/crates/l/iced_winit.svg)](https://github.com/hecrj/iced/blob/master/LICENSE)
[![License](https://img.shields.io/crates/l/iced_winit.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].

View file

@ -1,7 +1,7 @@
//! Convert [`winit`] types into [`iced_native`] types, and viceversa.
//!
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
use crate::keyboard;
use crate::mouse;
use crate::touch;
@ -208,7 +208,7 @@ pub fn visible(mode: Mode) -> bool {
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
pub fn mouse_interaction(
interaction: mouse::Interaction,
) -> winit::window::CursorIcon {
@ -232,7 +232,7 @@ pub fn mouse_interaction(
/// Converts a `MouseButton` from [`winit`] to an [`iced_native`] mouse button.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
match mouse_button {
winit::event::MouseButton::Left => mouse::Button::Left,
@ -248,7 +248,7 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
/// modifiers state.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
pub fn modifiers(
modifiers: winit::event::ModifiersState,
) -> keyboard::Modifiers {
@ -275,7 +275,7 @@ pub fn cursor_position(
/// Converts a `Touch` from [`winit`] to an [`iced_native`] touch event.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
pub fn touch_event(
touch: winit::event::Touch,
scale_factor: f64,
@ -306,7 +306,7 @@ pub fn touch_event(
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
///
/// [`winit`]: https://github.com/rust-windowing/winit
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
pub fn key_code(
virtual_keycode: winit::event::VirtualKeyCode,
) -> keyboard::KeyCode {

View file

@ -1,6 +1,6 @@
//! A windowing shell for Iced, on top of [`winit`].
//!
//! ![The native path of the Iced ecosystem](https://github.com/hecrj/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//! ![The native path of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/native.png?raw=true)
//!
//! `iced_winit` offers some convenient abstractions on top of [`iced_native`]
//! to quickstart development when using [`winit`].
@ -11,7 +11,7 @@
//! Additionally, a [`conversion`] module is available for users that decide to
//! implement a custom event loop.
//!
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
//! [`winit`]: https://github.com/rust-windowing/winit
//! [`conversion`]: crate::conversion
#![doc(

View file

@ -37,12 +37,16 @@ pub struct Settings<Flags> {
/// Whether the [`Application`] should exit when the user requests the
/// window to close (e.g. the user presses the close button).
///
/// [`Application`]: crate::Application
pub exit_on_close_request: bool,
/// Whether the [`Application`] should try to build the context
/// using OpenGL ES first then OpenGL.
///
/// NOTE: Only works for the `glow` backend.
///
/// [`Application`]: crate::Application
pub try_opengles_first: bool,
}