commit
5acba65c11
73 changed files with 755 additions and 187 deletions
|
|
@ -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]!
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
30
README.md
30
README.md
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
<img src="docs/logo.svg" width="140px" />
|
||||
|
||||
# iced
|
||||
# Iced
|
||||
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](https://crates.io/crates/iced)
|
||||
[](https://github.com/hecrj/iced/actions)
|
||||
[](https://github.com/iced-rs/iced/actions)
|
||||
[](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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@
|
|||
//! 
|
||||
//!
|
||||
//! [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)]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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`].
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# `iced_glow`
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced_glow)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! A [`glow`] renderer for [`iced_native`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! [`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>;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! A bunch of backend-agnostic types that can be leveraged to build a renderer
|
||||
//! for [`iced`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! [`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"
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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`].
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<'_>,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
120
pure/src/lib.rs
120
pure/src/lib.rs
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Show toggle controls using checkboxes.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display images in your user interface.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Provide progress feedback to your users.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Create choices using radio buttons.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display a horizontal or vertical rule for dividing content.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/// ```
|
||||
///
|
||||
/// 
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display vector graphics in your application.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Show toggle controls using togglers.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
17
src/lib.rs
17
src/lib.rs
|
|
@ -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"))]
|
||||
|
|
|
|||
79
src/pure.rs
79
src/pure.rs
|
|
@ -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`].
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# `iced_winit`
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced_winit)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](https://discord.gg/3xZJ65GAhd)
|
||||
|
||||
`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! A windowing shell for Iced, on top of [`winit`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! `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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue