summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/document.yml8
-rw-r--r--CHANGELOG.md43
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Cargo.toml25
-rw-r--r--README.md34
-rw-r--r--core/Cargo.toml2
-rw-r--r--core/src/keyboard/modifiers.rs8
-rw-r--r--core/src/lib.rs7
-rw-r--r--examples/pure/tooltip/Cargo.toml9
-rw-r--r--examples/pure/tooltip/src/main.rs93
-rw-r--r--futures/Cargo.toml2
-rw-r--r--futures/src/command.rs2
-rw-r--r--futures/src/runtime.rs6
-rw-r--r--futures/src/subscription.rs6
-rw-r--r--glow/Cargo.toml8
-rw-r--r--glow/README.md6
-rw-r--r--glow/src/backend.rs2
-rw-r--r--glow/src/lib.rs6
-rw-r--r--glutin/Cargo.toml8
-rw-r--r--graphics/Cargo.toml10
-rw-r--r--graphics/src/lib.rs4
-rw-r--r--graphics/src/widget/canvas.rs8
-rw-r--r--graphics/src/widget/pure/canvas/program.rs4
-rw-r--r--graphics/src/window/compositor.rs5
-rw-r--r--lazy/Cargo.toml11
-rw-r--r--lazy/src/lib.rs5
-rw-r--r--lazy/src/pure/responsive.rs5
-rw-r--r--native/Cargo.toml8
-rw-r--r--native/src/command/action.rs4
-rw-r--r--native/src/image.rs4
-rw-r--r--native/src/lib.rs4
-rw-r--r--native/src/overlay.rs2
-rw-r--r--native/src/renderer.rs23
-rw-r--r--native/src/svg.rs4
-rw-r--r--native/src/text.rs2
-rw-r--r--native/src/user_interface.rs7
-rw-r--r--native/src/widget.rs10
-rw-r--r--native/src/widget/checkbox.rs2
-rw-r--r--native/src/widget/column.rs2
-rw-r--r--native/src/widget/pane_grid.rs2
-rw-r--r--native/src/widget/pane_grid/configuration.rs4
-rw-r--r--native/src/widget/pane_grid/content.rs2
-rw-r--r--native/src/widget/pane_grid/state.rs22
-rw-r--r--native/src/widget/pane_grid/title_bar.rs2
-rw-r--r--native/src/widget/pick_list.rs13
-rw-r--r--native/src/widget/row.rs2
-rw-r--r--native/src/widget/text.rs6
-rw-r--r--native/src/widget/text_input.rs9
-rw-r--r--native/src/widget/toggler.rs2
-rw-r--r--native/src/widget/tooltip.rs225
-rw-r--r--pure/Cargo.toml12
-rw-r--r--pure/src/element.rs146
-rw-r--r--pure/src/flex.rs2
-rw-r--r--pure/src/helpers.rs71
-rw-r--r--pure/src/lib.rs120
-rw-r--r--pure/src/overlay.rs5
-rw-r--r--pure/src/widget.rs51
-rw-r--r--pure/src/widget/button.rs36
-rw-r--r--pure/src/widget/checkbox.rs1
-rw-r--r--pure/src/widget/column.rs13
-rw-r--r--pure/src/widget/image.rs1
-rw-r--r--pure/src/widget/pane_grid.rs4
-rw-r--r--pure/src/widget/pane_grid/content.rs6
-rw-r--r--pure/src/widget/pane_grid/title_bar.rs6
-rw-r--r--pure/src/widget/pick_list.rs5
-rw-r--r--pure/src/widget/progress_bar.rs1
-rw-r--r--pure/src/widget/radio.rs1
-rw-r--r--pure/src/widget/row.rs13
-rw-r--r--pure/src/widget/rule.rs1
-rw-r--r--pure/src/widget/scrollable.rs1
-rw-r--r--pure/src/widget/slider.rs7
-rw-r--r--pure/src/widget/svg.rs1
-rw-r--r--pure/src/widget/text_input.rs20
-rw-r--r--pure/src/widget/toggler.rs1
-rw-r--r--pure/src/widget/tooltip.rs228
-rw-r--r--pure/src/widget/tree.rs48
-rw-r--r--src/application.rs18
-rw-r--r--src/lib.rs21
-rw-r--r--src/pure.rs79
-rw-r--r--src/pure/widget.rs12
-rw-r--r--src/sandbox.rs22
-rw-r--r--src/widget.rs10
-rw-r--r--style/Cargo.toml4
-rw-r--r--wgpu/Cargo.toml6
-rw-r--r--wgpu/src/lib.rs2
-rw-r--r--winit/Cargo.toml10
-rw-r--r--winit/README.md2
-rw-r--r--winit/src/conversion.rs12
-rw-r--r--winit/src/lib.rs4
-rw-r--r--winit/src/settings.rs4
90 files changed, 1363 insertions, 334 deletions
diff --git a/.github/workflows/document.yml b/.github/workflows/document.yml
index 3a8326b6..5a8cb252 100644
--- a/.github/workflows/document.yml
+++ b/.github/workflows/document.yml
@@ -10,13 +10,19 @@ jobs:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: hecrj/setup-rust-action@v1
+ with:
+ rust-version: nightly
- uses: actions/checkout@v2
- name: Generate documentation
run: |
- cargo doc --no-deps --all-features \
+ RUSTDOCFLAGS="--cfg docsrs" \
+ cargo doc --no-deps --all-features \
-p iced_core \
+ -p iced_style \
+ -p iced_futures \
-p iced_native \
-p iced_lazy \
+ -p iced_pure \
-p iced_graphics \
-p iced_wgpu \
-p iced_glow \
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a476631d..0f0fa47c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.4.2] - 2022-05-03
+### Fixed
+- `Padding` type not exposed in `iced`.
+
+## [0.4.1] - 2022-05-02
+### Fixed
+- Version number in `README`.
+
+## [0.4.0] - 2022-05-02
+### Added
+- __[Stateless widgets][stateless]__ (#1284)
+ A brand new widget API that removes the need to keep track of internal widget state. No more `button::State` in your application!
+
+- __[`Component` trait][component]__ (#1131)
+ A new trait to implement custom widgets with internal mutable state while using composition and [The Elm Architecture].
+
+- __[`Responsive` widget][responsive]__ (#1193)
+ A widget that is aware of its dimensions and can be used to easily build responsive user interfaces.
+
+- __[Experimental WebGL support][webgl]__ (#1096)
+ Applications can now be rendered into an HTML `canvas` when targeting Wasm by leveraging the WebGL support in [`wgpu`]. Thanks to @pacmancoder and @kaimast!
+
+- __[Support for Raspberry Pis and older devices][raspberry]__ (#1160)
+ The compatibility of our OpenGL renderer has been improved and should run on any hardware that supports OpenGL 3.0+ or OpenGL ES 2.0+. Additionally, we started maintaining [Docker images for `aarch64` and `armv7`](https://github.com/orgs/iced-rs/packages) to easily cross-compile `iced` applications and target Raspberry Pis. Thanks to @derezzedex!
+
+- __[Simpler `Renderer` APIs][renderer_apis]__ (#1110)
+ The surface of the `Renderer` APIs of the library has been considerably reduced. Instead of a `Renderer` trait per widget, now there are only 3 traits that are reused by all the widgets.
+
+[webgl]: https://github.com/iced-rs/iced/pull/1096
+[renderer_apis]: https://github.com/iced-rs/iced/pull/1110
+[component]: https://github.com/iced-rs/iced/pull/1131
+[raspberry]: https://github.com/iced-rs/iced/pull/1160
+[responsive]: https://github.com/iced-rs/iced/pull/1193
+[stateless]: https://github.com/iced-rs/iced/pull/1284
+[The Elm Architecture]: https://guide.elm-lang.org/architecture/
+[`wgpu`]: https://github.com/gfx-rs/wgpu
+
+
## [0.3.0] - 2021-03-31
### Added
- Touch support. [#57] [#650] (thanks to @simlay and @discordance!)
@@ -219,7 +257,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- First release! :tada:
-[Unreleased]: https://github.com/iced-rs/iced/compare/0.3.0...HEAD
+[Unreleased]: https://github.com/iced-rs/iced/compare/0.4.2...HEAD
+[0.4.2]: https://github.com/iced-rs/iced/compare/0.4.1...0.4.2
+[0.4.1]: https://github.com/iced-rs/iced/compare/0.4.0...0.4.1
+[0.4.0]: https://github.com/iced-rs/iced/compare/0.3.0...0.4.0
[0.3.0]: https://github.com/iced-rs/iced/compare/0.2.0...0.3.0
[0.2.0]: https://github.com/iced-rs/iced/compare/0.1.1...0.2.0
[0.1.1]: https://github.com/iced-rs/iced/compare/0.1.0...0.1.1
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cf6655f5..8782a2e3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -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]!
diff --git a/Cargo.toml b/Cargo.toml
index 632c66fc..0b886c4a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced"
-version = "0.3.0"
+version = "0.4.2"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A cross-platform GUI library inspired by Elm"
@@ -96,26 +96,27 @@ members = [
"examples/pure/pane_grid",
"examples/pure/pick_list",
"examples/pure/todos",
+ "examples/pure/tooltip",
"examples/pure/tour",
]
[dependencies]
-iced_core = { version = "0.4", path = "core" }
-iced_futures = { version = "0.3", path = "futures" }
-iced_native = { version = "0.4", path = "native" }
-iced_graphics = { version = "0.2", path = "graphics" }
-iced_winit = { version = "0.3", path = "winit" }
-iced_glutin = { version = "0.2", path = "glutin", optional = true }
-iced_glow = { version = "0.2", path = "glow", optional = true }
-iced_pure = { version = "0.1", path = "pure", optional = true }
+iced_core = { version = "0.5", path = "core" }
+iced_futures = { version = "0.4", path = "futures" }
+iced_native = { version = "0.5", path = "native" }
+iced_graphics = { version = "0.3", path = "graphics" }
+iced_winit = { version = "0.4", path = "winit" }
+iced_glutin = { version = "0.3", path = "glutin", optional = true }
+iced_glow = { version = "0.3", path = "glow", optional = true }
+iced_pure = { version = "0.2", path = "pure", optional = true }
thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
-iced_wgpu = { version = "0.4", path = "wgpu", optional = true }
+iced_wgpu = { version = "0.5", path = "wgpu", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
-iced_wgpu = { version = "0.4", path = "wgpu", features = ["webgl"], optional = true }
+iced_wgpu = { version = "0.5", path = "wgpu", features = ["webgl"], optional = true }
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
-features = ["image", "svg", "canvas", "qr_code"]
+features = ["image", "svg", "canvas", "qr_code", "pure"]
diff --git a/README.md b/README.md
index e73891ce..3d1e6e1e 100644
--- a/README.md
+++ b/README.md
@@ -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
@@ -66,16 +66,16 @@ __iced is currently experimental software.__ [Take a look at the roadmap],
Add `iced` as a dependency in your `Cargo.toml`:
```toml
-iced = "0.3"
+iced = "0.4"
```
-__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>
@@ -215,14 +215,14 @@ $ cargo run --features iced/glow --package game_of_life
and then use it in your project with
```toml
-iced = { version = "0.3", default-features = false, features = ["glow"] }
+iced = { version = "0.4", default-features = false, features = ["glow"] }
```
**NOTE:** Chances are you have hardware that supports at least OpenGL 2.1 or OpenGL ES 2.0,
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
diff --git a/core/Cargo.toml b/core/Cargo.toml
index a8d50801..c9c7686e 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_core"
-version = "0.4.0"
+version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "The essential concepts of Iced"
diff --git a/core/src/keyboard/modifiers.rs b/core/src/keyboard/modifiers.rs
index e61f145a..ff5b08f2 100644
--- a/core/src/keyboard/modifiers.rs
+++ b/core/src/keyboard/modifiers.rs
@@ -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)
}
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 3eb9f659..7b0dc57b 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -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)]
diff --git a/examples/pure/tooltip/Cargo.toml b/examples/pure/tooltip/Cargo.toml
new file mode 100644
index 00000000..d84dfb37
--- /dev/null
+++ b/examples/pure/tooltip/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "pure_tooltip"
+version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>", "Casper Rogild Storm"]
+edition = "2021"
+publish = false
+
+[dependencies]
+iced = { path = "../../..", features = ["pure"] }
diff --git a/examples/pure/tooltip/src/main.rs b/examples/pure/tooltip/src/main.rs
new file mode 100644
index 00000000..dbd83f5f
--- /dev/null
+++ b/examples/pure/tooltip/src/main.rs
@@ -0,0 +1,93 @@
+use iced::pure::{
+ button, container, tooltip, widget::tooltip::Position, Element, Sandbox,
+};
+use iced::{Length, Settings};
+
+pub fn main() -> iced::Result {
+ Example::run(Settings::default())
+}
+
+struct Example {
+ position: Position,
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ ChangePosition,
+}
+
+impl Sandbox for Example {
+ type Message = Message;
+
+ fn new() -> Self {
+ Self {
+ position: Position::Bottom,
+ }
+ }
+
+ fn title(&self) -> String {
+ String::from("Tooltip - Iced")
+ }
+
+ fn update(&mut self, message: Message) {
+ match message {
+ Message::ChangePosition => {
+ let position = match &self.position {
+ Position::FollowCursor => Position::Top,
+ Position::Top => Position::Bottom,
+ Position::Bottom => Position::Left,
+ Position::Left => Position::Right,
+ Position::Right => Position::FollowCursor,
+ };
+
+ self.position = position
+ }
+ }
+ }
+
+ fn view(&self) -> Element<Message> {
+ let tooltip = tooltip(
+ button("Press to change position")
+ .on_press(Message::ChangePosition),
+ position_to_text(self.position),
+ self.position,
+ )
+ .gap(10)
+ .style(style::Tooltip);
+
+ container(tooltip)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into()
+ }
+}
+
+fn position_to_text<'a>(position: Position) -> &'a str {
+ match position {
+ Position::FollowCursor => "Follow Cursor",
+ Position::Top => "Top",
+ Position::Bottom => "Bottom",
+ Position::Left => "Left",
+ Position::Right => "Right",
+ }
+}
+
+mod style {
+ use iced::container;
+ use iced::Color;
+
+ pub struct Tooltip;
+
+ impl container::StyleSheet for Tooltip {
+ fn style(&self) -> container::Style {
+ container::Style {
+ text_color: Some(Color::from_rgb8(0xEE, 0xEE, 0xEE)),
+ background: Some(Color::from_rgb(0.11, 0.42, 0.87).into()),
+ border_radius: 12.0,
+ ..container::Style::default()
+ }
+ }
+ }
+}
diff --git a/futures/Cargo.toml b/futures/Cargo.toml
index 78e673e0..ed99d79a 100644
--- a/futures/Cargo.toml
+++ b/futures/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_futures"
-version = "0.3.0"
+version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "Commands, subscriptions, and runtimes for Iced"
diff --git a/futures/src/command.rs b/futures/src/command.rs
index d8adfe49..05c3a1d0 100644
--- a/futures/src/command.rs
+++ b/futures/src/command.rs
@@ -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))
}
diff --git a/futures/src/runtime.rs b/futures/src/runtime.rs
index 2034ed6c..34f6b6dd 100644
--- a/futures/src/runtime.rs
+++ b/futures/src/runtime.rs
@@ -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};
diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs
index 6f261827..0085886d 100644
--- a/futures/src/subscription.rs
+++ b/futures/src/subscription.rs
@@ -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`].
diff --git a/glow/Cargo.toml b/glow/Cargo.toml
index e0907a66..18215e9b 100644
--- a/glow/Cargo.toml
+++ b/glow/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "iced_glow"
-version = "0.2.0"
+version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A glow renderer for iced"
license = "MIT AND OFL-1.1"
-repository = "https://github.com/hecrj/iced"
+repository = "https://github.com/iced-rs/iced"
[features]
canvas = ["iced_graphics/canvas"]
@@ -24,11 +24,11 @@ bytemuck = "1.4"
log = "0.4"
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_graphics]
-version = "0.2"
+version = "0.3"
path = "../graphics"
features = ["font-fallback", "font-icons", "opengl"]
diff --git a/glow/README.md b/glow/README.md
index 5e37b7a2..00f38f64 100644
--- a/glow/README.md
+++ b/glow/README.md
@@ -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
diff --git a/glow/src/backend.rs b/glow/src/backend.rs
index 89dc1aaa..f63135a4 100644
--- a/glow/src/backend.rs
+++ b/glow/src/backend.rs
@@ -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,
diff --git a/glow/src/lib.rs b/glow/src/lib.rs
index 05435b54..d7c0854d 100644
--- a/glow/src/lib.rs
+++ b/glow/src/lib.rs
@@ -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>;
diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml
index 2d4625da..5ad038c0 100644
--- a/glutin/Cargo.toml
+++ b/glutin/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_glutin"
-version = "0.2.0"
+version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A glutin runtime for Iced"
@@ -23,14 +23,14 @@ git = "https://github.com/iced-rs/glutin"
rev = "7a0ee02782eb2bf059095e0c953c4bb53f1eef0e"
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_winit]
-version = "0.3"
+version = "0.4"
path = "../winit"
[dependencies.iced_graphics]
-version = "0.2"
+version = "0.3"
path = "../graphics"
features = ["opengl"]
diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml
index a84acbd6..e916975d 100644
--- a/graphics/Cargo.toml
+++ b/graphics/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "iced_graphics"
-version = "0.2.0"
+version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
license = "MIT"
-repository = "https://github.com/hecrj/iced"
+repository = "https://github.com/iced-rs/iced"
documentation = "https://docs.rs/iced_graphics"
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"]
@@ -29,15 +29,15 @@ version = "1.4"
features = ["derive"]
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_style]
-version = "0.3"
+version = "0.4"
path = "../style"
[dependencies.iced_pure]
-version = "0.1"
+version = "0.2"
path = "../pure"
optional = true
diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs
index 4364695f..370f70d6 100644
--- a/graphics/src/lib.rs
+++ b/graphics/src/lib.rs
@@ -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"
)]
diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs
index 6c526e35..23444b2b 100644
--- a/graphics/src/widget/canvas.rs
+++ b/graphics/src/widget/canvas.rs
@@ -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:
diff --git a/graphics/src/widget/pure/canvas/program.rs b/graphics/src/widget/pure/canvas/program.rs
index ee74c27f..058b364b 100644
--- a/graphics/src/widget/pure/canvas/program.rs
+++ b/graphics/src/widget/pure/canvas/program.rs
@@ -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`].
diff --git a/graphics/src/window/compositor.rs b/graphics/src/window/compositor.rs
index 7525de1d..0c4cadcd 100644
--- a/graphics/src/window/compositor.rs
+++ b/graphics/src/window/compositor.rs
@@ -45,7 +45,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,
@@ -56,7 +57,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.
diff --git a/lazy/Cargo.toml b/lazy/Cargo.toml
index 2d7451f3..7d439e47 100644
--- a/lazy/Cargo.toml
+++ b/lazy/Cargo.toml
@@ -1,7 +1,14 @@
[package]
name = "iced_lazy"
version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
+description = "Lazy widgets for Iced"
+license = "MIT"
+repository = "https://github.com/iced-rs/iced"
+documentation = "https://docs.rs/iced_lazy"
+keywords = ["gui", "ui", "graphics", "interface", "widgets"]
+categories = ["gui"]
[features]
pure = ["iced_pure"]
@@ -10,10 +17,10 @@ pure = ["iced_pure"]
ouroboros = "0.13"
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_pure]
-version = "0.1"
+version = "0.2"
path = "../pure"
optional = true
diff --git a/lazy/src/lib.rs b/lazy/src/lib.rs
index 5d7d10e4..916f9458 100644
--- a/lazy/src/lib.rs
+++ b/lazy/src/lib.rs
@@ -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;
diff --git a/lazy/src/pure/responsive.rs b/lazy/src/pure/responsive.rs
index 2b62a047..e464d156 100644
--- a/lazy/src/pure/responsive.rs
+++ b/lazy/src/pure/responsive.rs
@@ -67,12 +67,13 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> {
self.element = view(new_size);
self.size = new_size;
+
+ tree.diff(&self.element);
+
self.layout = self
.element
.as_widget()
.layout(renderer, &layout::Limits::new(Size::ZERO, self.size));
-
- tree.diff(&self.element);
}
fn resolve<R, T>(
diff --git a/native/Cargo.toml b/native/Cargo.toml
index c4b363ae..a21385de 100644
--- a/native/Cargo.toml
+++ b/native/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_native"
-version = "0.4.0"
+version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A renderer-agnostic library for native GUIs"
@@ -16,14 +16,14 @@ unicode-segmentation = "1.6"
num-traits = "0.2"
[dependencies.iced_core]
-version = "0.4"
+version = "0.5"
path = "../core"
[dependencies.iced_futures]
-version = "0.3"
+version = "0.4"
path = "../futures"
features = ["thread-pool"]
[dependencies.iced_style]
-version = "0.3"
+version = "0.4"
path = "../style"
diff --git a/native/src/command/action.rs b/native/src/command/action.rs
index 342d0cfe..1bb03cef 100644
--- a/native/src/command/action.rs
+++ b/native/src/command/action.rs
@@ -11,6 +11,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.
@@ -25,6 +27,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,
diff --git a/native/src/image.rs b/native/src/image.rs
index 43bba4f1..516eb2db 100644
--- a/native/src/image.rs
+++ b/native/src/image.rs
@@ -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
diff --git a/native/src/lib.rs b/native/src/lib.rs
index b8054169..db60976f 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -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
diff --git a/native/src/overlay.rs b/native/src/overlay.rs
index 124bcac2..86878f6a 100644
--- a/native/src/overlay.rs
+++ b/native/src/overlay.rs
@@ -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(
diff --git a/native/src/renderer.rs b/native/src/renderer.rs
index ca7ad5a2..73d2f401 100644
--- a/native/src/renderer.rs
+++ b/native/src/renderer.rs
@@ -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.
///
diff --git a/native/src/svg.rs b/native/src/svg.rs
index 90eff87e..f86fec5b 100644
--- a/native/src/svg.rs
+++ b/native/src/svg.rs
@@ -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
diff --git a/native/src/text.rs b/native/src/text.rs
index 256a9c5a..6e28681d 100644
--- a/native/src/text.rs
+++ b/native/src/text.rs
@@ -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,
diff --git a/native/src/user_interface.rs b/native/src/user_interface.rs
index 6fc6a479..f80786aa 100644
--- a/native/src/user_interface.rs
+++ b/native/src/user_interface.rs
@@ -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
diff --git a/native/src/widget.rs b/native/src/widget.rs
index aacdc3d9..8417dad1 100644
--- a/native/src/widget.rs
+++ b/native/src/widget.rs
@@ -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,
diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs
index 122c5e52..b6d920df 100644
--- a/native/src/widget/checkbox.rs
+++ b/native/src/widget/checkbox.rs
@@ -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
diff --git a/native/src/widget/column.rs b/native/src/widget/column.rs
index f161d1f2..268218b1 100644
--- a/native/src/widget/column.rs
+++ b/native/src/widget/column.rs
@@ -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 {
diff --git a/native/src/widget/pane_grid.rs b/native/src/widget/pane_grid.rs
index 2093886e..0ceec83e 100644
--- a/native/src/widget/pane_grid.rs
+++ b/native/src/widget/pane_grid.rs
@@ -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;
diff --git a/native/src/widget/pane_grid/configuration.rs b/native/src/widget/pane_grid/configuration.rs
index 4c52bad4..7d68fb46 100644
--- a/native/src/widget/pane_grid/configuration.rs
+++ b/native/src/widget/pane_grid/configuration.rs
@@ -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),
}
diff --git a/native/src/widget/pane_grid/content.rs b/native/src/widget/pane_grid/content.rs
index f0ed0426..407f5458 100644
--- a/native/src/widget/pane_grid/content.rs
+++ b/native/src/widget/pane_grid/content.rs
@@ -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,
diff --git a/native/src/widget/pane_grid/state.rs b/native/src/widget/pane_grid/state.rs
index f9ea21f4..6a282d24 100644
--- a/native/src/widget/pane_grid/state.rs
+++ b/native/src/widget/pane_grid/state.rs
@@ -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,
diff --git a/native/src/widget/pane_grid/title_bar.rs b/native/src/widget/pane_grid/title_bar.rs
index d56972ec..a10181af 100644
--- a/native/src/widget/pane_grid/title_bar.rs
+++ b/native/src/widget/pane_grid/title_bar.rs
@@ -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,
diff --git a/native/src/widget/pick_list.rs b/native/src/widget/pick_list.rs
index e050ada5..0374aef7 100644
--- a/native/src/widget/pick_list.rs
+++ b/native/src/widget/pick_list.rs
@@ -402,21 +402,24 @@ pub fn draw<T, Renderer>(
if let Some(label) =
label.as_ref().map(String::as_str).or_else(|| placeholder)
{
+ let text_size = f32::from(text_size.unwrap_or(renderer.default_size()));
+
renderer.fill_text(Text {
content: label,
- size: f32::from(text_size.unwrap_or(renderer.default_size())),
+ size: text_size,
font: font.clone(),
color: is_selected
.then(|| style.text_color)
.unwrap_or(style.placeholder_color),
bounds: Rectangle {
x: bounds.x + f32::from(padding.left),
- y: bounds.center_y(),
- ..bounds
+ y: bounds.center_y() - text_size / 2.0,
+ width: bounds.width - f32::from(padding.horizontal()),
+ height: text_size,
},
horizontal_alignment: alignment::Horizontal::Left,
- vertical_alignment: alignment::Vertical::Center,
- })
+ vertical_alignment: alignment::Vertical::Top,
+ });
}
}
diff --git a/native/src/widget/row.rs b/native/src/widget/row.rs
index e34befb2..7a7c70c6 100644
--- a/native/src/widget/row.rs
+++ b/native/src/widget/row.rs
@@ -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 {
diff --git a/native/src/widget/text.rs b/native/src/widget/text.rs
index 6f00c9c8..a7855c30 100644
--- a/native/src/widget/text.rs
+++ b/native/src/widget/text.rs
@@ -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,
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index a206a0c7..5ecd68e9 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -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<'_>,
diff --git a/native/src/widget/toggler.rs b/native/src/widget/toggler.rs
index 536aef78..6d7592f3 100644
--- a/native/src/widget/toggler.rs
+++ b/native/src/widget/toggler.rs
@@ -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
diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs
index 7989c768..c929395f 100644
--- a/native/src/widget/tooltip.rs
+++ b/native/src/widget/tooltip.rs
@@ -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(
@@ -98,6 +98,117 @@ pub enum Position {
Right,
}
+/// Draws a [`Tooltip`].
+pub fn draw<Renderer: crate::Renderer>(
+ renderer: &mut Renderer,
+ inherited_style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ position: Position,
+ gap: u16,
+ padding: u16,
+ style_sheet: &dyn container::StyleSheet,
+ layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
+ draw_text: impl FnOnce(
+ &mut Renderer,
+ &renderer::Style,
+ Layout<'_>,
+ Point,
+ &Rectangle,
+ ),
+) {
+ let bounds = layout.bounds();
+
+ if bounds.contains(cursor_position) {
+ let gap = f32::from(gap);
+ let style = style_sheet.style();
+
+ let defaults = renderer::Style {
+ text_color: style.text_color.unwrap_or(inherited_style.text_color),
+ };
+
+ let text_layout = layout_text(
+ renderer,
+ &layout::Limits::new(Size::ZERO, viewport.size())
+ .pad(Padding::new(padding)),
+ );
+
+ let padding = f32::from(padding);
+ let text_bounds = text_layout.bounds();
+ let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
+ let y_center = bounds.y + (bounds.height - text_bounds.height) / 2.0;
+
+ let mut tooltip_bounds = {
+ let offset = match position {
+ Position::Top => Vector::new(
+ x_center,
+ bounds.y - text_bounds.height - gap - padding,
+ ),
+ Position::Bottom => Vector::new(
+ x_center,
+ bounds.y + bounds.height + gap + padding,
+ ),
+ Position::Left => Vector::new(
+ bounds.x - text_bounds.width - gap - padding,
+ y_center,
+ ),
+ Position::Right => Vector::new(
+ bounds.x + bounds.width + gap + padding,
+ y_center,
+ ),
+ Position::FollowCursor => Vector::new(
+ cursor_position.x,
+ cursor_position.y - text_bounds.height,
+ ),
+ };
+
+ Rectangle {
+ x: offset.x - padding,
+ y: offset.y - padding,
+ width: text_bounds.width + padding * 2.0,
+ height: text_bounds.height + padding * 2.0,
+ }
+ };
+
+ if tooltip_bounds.x < viewport.x {
+ tooltip_bounds.x = viewport.x;
+ } else if viewport.x + viewport.width
+ < tooltip_bounds.x + tooltip_bounds.width
+ {
+ tooltip_bounds.x =
+ viewport.x + viewport.width - tooltip_bounds.width;
+ }
+
+ if tooltip_bounds.y < viewport.y {
+ tooltip_bounds.y = viewport.y;
+ } else if viewport.y + viewport.height
+ < tooltip_bounds.y + tooltip_bounds.height
+ {
+ tooltip_bounds.y =
+ viewport.y + viewport.height - tooltip_bounds.height;
+ }
+
+ renderer.with_layer(*viewport, |renderer| {
+ container::draw_background(renderer, &style, tooltip_bounds);
+
+ draw_text(
+ renderer,
+ &defaults,
+ Layout::with_offset(
+ Vector::new(
+ tooltip_bounds.x + padding,
+ tooltip_bounds.y + padding,
+ ),
+ &text_layout,
+ ),
+ cursor_position,
+ viewport,
+ )
+ });
+ }
+}
+
impl<'a, Message, Renderer> Widget<Message, Renderer>
for Tooltip<'a, Message, Renderer>
where
@@ -169,100 +280,32 @@ where
viewport,
);
- let bounds = layout.bounds();
-
- if bounds.contains(cursor_position) {
- let gap = f32::from(self.gap);
- let style = self.style_sheet.style();
-
- let defaults = renderer::Style {
- text_color: style
- .text_color
- .unwrap_or(inherited_style.text_color),
- };
-
- let text_layout = Widget::<(), Renderer>::layout(
- &self.tooltip,
- renderer,
- &layout::Limits::new(Size::ZERO, viewport.size())
- .pad(Padding::new(self.padding)),
- );
-
- let padding = f32::from(self.padding);
- let text_bounds = text_layout.bounds();
- let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
- let y_center =
- bounds.y + (bounds.height - text_bounds.height) / 2.0;
-
- let mut tooltip_bounds = {
- let offset = match self.position {
- Position::Top => Vector::new(
- x_center,
- bounds.y - text_bounds.height - gap - padding,
- ),
- Position::Bottom => Vector::new(
- x_center,
- bounds.y + bounds.height + gap + padding,
- ),
- Position::Left => Vector::new(
- bounds.x - text_bounds.width - gap - padding,
- y_center,
- ),
- Position::Right => Vector::new(
- bounds.x + bounds.width + gap + padding,
- y_center,
- ),
- Position::FollowCursor => Vector::new(
- cursor_position.x,
- cursor_position.y - text_bounds.height,
- ),
- };
-
- Rectangle {
- x: offset.x - padding,
- y: offset.y - padding,
- width: text_bounds.width + padding * 2.0,
- height: text_bounds.height + padding * 2.0,
- }
- };
-
- if tooltip_bounds.x < viewport.x {
- tooltip_bounds.x = viewport.x;
- } else if viewport.x + viewport.width
- < tooltip_bounds.x + tooltip_bounds.width
- {
- tooltip_bounds.x =
- viewport.x + viewport.width - tooltip_bounds.width;
- }
-
- if tooltip_bounds.y < viewport.y {
- tooltip_bounds.y = viewport.y;
- } else if viewport.y + viewport.height
- < tooltip_bounds.y + tooltip_bounds.height
- {
- tooltip_bounds.y =
- viewport.y + viewport.height - tooltip_bounds.height;
- }
-
- renderer.with_layer(*viewport, |renderer| {
- container::draw_background(renderer, &style, tooltip_bounds);
+ let tooltip = &self.tooltip;
+ draw(
+ renderer,
+ inherited_style,
+ layout,
+ cursor_position,
+ viewport,
+ self.position,
+ self.gap,
+ self.padding,
+ self.style_sheet.as_ref(),
+ |renderer, limits| {
+ Widget::<(), Renderer>::layout(tooltip, renderer, limits)
+ },
+ |renderer, defaults, layout, cursor_position, viewport| {
Widget::<(), Renderer>::draw(
- &self.tooltip,
+ tooltip,
renderer,
- &defaults,
- Layout::with_offset(
- Vector::new(
- tooltip_bounds.x + padding,
- tooltip_bounds.y + padding,
- ),
- &text_layout,
- ),
+ defaults,
+ layout,
cursor_position,
viewport,
);
- });
- }
+ },
+ )
}
}
@@ -273,8 +316,8 @@ where
Message: 'a,
{
fn from(
- column: Tooltip<'a, Message, Renderer>,
+ tooltip: Tooltip<'a, Message, Renderer>,
) -> Element<'a, Message, Renderer> {
- Element::new(column)
+ Element::new(tooltip)
}
}
diff --git a/pure/Cargo.toml b/pure/Cargo.toml
index 317dccdf..8369a717 100644
--- a/pure/Cargo.toml
+++ b/pure/Cargo.toml
@@ -1,9 +1,15 @@
[package]
name = "iced_pure"
-version = "0.1.0"
+version = "0.2.0"
edition = "2021"
+description = "Pure widgets for Iced"
+license = "MIT"
+repository = "https://github.com/iced-rs/iced"
+documentation = "https://docs.rs/iced_pure"
+keywords = ["gui", "ui", "graphics", "interface", "widgets"]
+categories = ["gui"]
[dependencies]
-iced_native = { version = "0.4", path = "../native" }
-iced_style = { version = "0.3", path = "../style" }
+iced_native = { version = "0.5", path = "../native" }
+iced_style = { version = "0.4", path = "../style" }
num-traits = "0.2"
diff --git a/pure/src/element.rs b/pure/src/element.rs
index 08096103..704b3d0b 100644
--- a/pure/src/element.rs
+++ b/pure/src/element.rs
@@ -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,
diff --git a/pure/src/flex.rs b/pure/src/flex.rs
index 8d473f08..3f65a28b 100644
--- a/pure/src/flex.rs
+++ b/pure/src/flex.rs
@@ -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,
diff --git a/pure/src/helpers.rs b/pure/src/helpers.rs
index 24f6dbaa..2c4a37be 100644
--- a/pure/src/helpers.rs
+++ b/pure/src/helpers.rs
@@ -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,33 @@ 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,
+ position: widget::tooltip::Position,
+) -> widget::Tooltip<'a, Message, Renderer>
+where
+ Renderer: iced_native::text::Renderer,
+{
+ 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,
@@ -45,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,
@@ -56,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,
@@ -70,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,
@@ -81,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,
@@ -93,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,
@@ -105,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>,
@@ -118,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)
}
@@ -143,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,
diff --git a/pure/src/lib.rs b/pure/src/lib.rs
index f9f0ae2d..6af74771 100644
--- a/pure/src/lib.rs
+++ b/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);
}
diff --git a/pure/src/overlay.rs b/pure/src/overlay.rs
index c87dfce8..fecaa2ac 100644
--- a/pure/src/overlay.rs
+++ b/pure/src/overlay.rs
@@ -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,
diff --git a/pure/src/widget.rs b/pure/src/widget.rs
index 8200f9a7..cc04cc96 100644
--- a/pure/src/widget.rs
+++ b/pure/src/widget.rs
@@ -1,3 +1,4 @@
+//! Use the built-in widgets or create your own.
pub mod button;
pub mod checkbox;
pub mod container;
@@ -12,6 +13,7 @@ pub mod slider;
pub mod svg;
pub mod text_input;
pub mod toggler;
+pub mod tooltip;
pub mod tree;
mod column;
@@ -37,6 +39,7 @@ pub use svg::Svg;
pub use text::Text;
pub use text_input::TextInput;
pub use toggler::Toggler;
+pub use tooltip::{Position, Tooltip};
pub use tree::Tree;
use iced_native::event::{self, Event};
@@ -46,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,
@@ -67,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,
@@ -105,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,
diff --git a/pure/src/widget/button.rs b/pure/src/widget/button.rs
index e083ea73..456c2509 100644
--- a/pure/src/widget/button.rs
+++ b/pure/src/widget/button.rs
@@ -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(),
diff --git a/pure/src/widget/checkbox.rs b/pure/src/widget/checkbox.rs
index 971980e3..98f55a56 100644
--- a/pure/src/widget/checkbox.rs
+++ b/pure/src/widget/checkbox.rs
@@ -1,3 +1,4 @@
+//! Show toggle controls using checkboxes.
use crate::widget::Tree;
use crate::{Element, Widget};
diff --git a/pure/src/widget/column.rs b/pure/src/widget/column.rs
index a4c0987b..7256f474 100644
--- a/pure/src/widget/column.rs
+++ b/pure/src/widget/column.rs
@@ -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>>,
diff --git a/pure/src/widget/image.rs b/pure/src/widget/image.rs
index a5bca5a0..ef764ec2 100644
--- a/pure/src/widget/image.rs
+++ b/pure/src/widget/image.rs
@@ -1,3 +1,4 @@
+//! Display images in your user interface.
use crate::widget::{Tree, Widget};
use crate::Element;
diff --git a/pure/src/widget/pane_grid.rs b/pure/src/widget/pane_grid.rs
index 34a56bcc..c532a6de 100644
--- a/pure/src/widget/pane_grid.rs
+++ b/pure/src/widget/pane_grid.rs
@@ -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(),
)
}
diff --git a/pure/src/widget/pane_grid/content.rs b/pure/src/widget/pane_grid/content.rs
index a928b28c..e66ac40b 100644
--- a/pure/src/widget/pane_grid/content.rs
+++ b/pure/src/widget/pane_grid/content.rs
@@ -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,
diff --git a/pure/src/widget/pane_grid/title_bar.rs b/pure/src/widget/pane_grid/title_bar.rs
index dd68b073..4a7c8c17 100644
--- a/pure/src/widget/pane_grid/title_bar.rs
+++ b/pure/src/widget/pane_grid/title_bar.rs
@@ -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,
diff --git a/pure/src/widget/pick_list.rs b/pure/src/widget/pick_list.rs
index 45bb289e..255e3681 100644
--- a/pure/src/widget/pick_list.rs
+++ b/pure/src/widget/pick_list.rs
@@ -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>,
diff --git a/pure/src/widget/progress_bar.rs b/pure/src/widget/progress_bar.rs
index 3f4ffd55..3016a81a 100644
--- a/pure/src/widget/progress_bar.rs
+++ b/pure/src/widget/progress_bar.rs
@@ -1,3 +1,4 @@
+//! Provide progress feedback to your users.
use crate::widget::Tree;
use crate::{Element, Widget};
diff --git a/pure/src/widget/radio.rs b/pure/src/widget/radio.rs
index c20f8f3e..7c98c937 100644
--- a/pure/src/widget/radio.rs
+++ b/pure/src/widget/radio.rs
@@ -1,3 +1,4 @@
+//! Create choices using radio buttons.
use crate::widget::Tree;
use crate::{Element, Widget};
diff --git a/pure/src/widget/row.rs b/pure/src/widget/row.rs
index 92812d27..0385b8bd 100644
--- a/pure/src/widget/row.rs
+++ b/pure/src/widget/row.rs
@@ -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>>,
diff --git a/pure/src/widget/rule.rs b/pure/src/widget/rule.rs
index 40b1fc90..ab8537ae 100644
--- a/pure/src/widget/rule.rs
+++ b/pure/src/widget/rule.rs
@@ -1,3 +1,4 @@
+//! Display a horizontal or vertical rule for dividing content.
use crate::widget::Tree;
use crate::{Element, Widget};
diff --git a/pure/src/widget/scrollable.rs b/pure/src/widget/scrollable.rs
index 24263c95..70e951ef 100644
--- a/pure/src/widget/scrollable.rs
+++ b/pure/src/widget/scrollable.rs
@@ -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};
diff --git a/pure/src/widget/slider.rs b/pure/src/widget/slider.rs
index 1107bdc1..4d8bbce4 100644
--- a/pure/src/widget/slider.rs
+++ b/pure/src/widget/slider.rs
@@ -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)
diff --git a/pure/src/widget/svg.rs b/pure/src/widget/svg.rs
index 2758c5b1..14180097 100644
--- a/pure/src/widget/svg.rs
+++ b/pure/src/widget/svg.rs
@@ -1,3 +1,4 @@
+//! Display vector graphics in your application.
use crate::widget::{Tree, Widget};
use crate::Element;
diff --git a/pure/src/widget/text_input.rs b/pure/src/widget/text_input.rs
index d6041d7f..57ad26d9 100644
--- a/pure/src/widget/text_input.rs
+++ b/pure/src/widget/text_input.rs
@@ -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
diff --git a/pure/src/widget/toggler.rs b/pure/src/widget/toggler.rs
index 1b3367a4..b9c5ec02 100644
--- a/pure/src/widget/toggler.rs
+++ b/pure/src/widget/toggler.rs
@@ -1,3 +1,4 @@
+//! Show toggle controls using togglers.
use crate::widget::{Tree, Widget};
use crate::Element;
diff --git a/pure/src/widget/tooltip.rs b/pure/src/widget/tooltip.rs
new file mode 100644
index 00000000..3887732a
--- /dev/null
+++ b/pure/src/widget/tooltip.rs
@@ -0,0 +1,228 @@
+//! Display a widget over another.
+use crate::widget::Tree;
+use crate::{Element, Widget};
+use iced_native::event::{self, Event};
+use iced_native::layout;
+use iced_native::mouse;
+use iced_native::overlay;
+use iced_native::renderer;
+use iced_native::text;
+use iced_native::widget::tooltip;
+use iced_native::widget::Text;
+use iced_native::{Clipboard, Layout, Length, Point, Rectangle, Shell};
+
+pub use iced_style::container::{Style, StyleSheet};
+pub use tooltip::Position;
+
+/// An element to display a widget over another.
+#[allow(missing_debug_implementations)]
+pub struct Tooltip<'a, Message, Renderer: text::Renderer> {
+ content: Element<'a, Message, Renderer>,
+ tooltip: Text<Renderer>,
+ position: Position,
+ style_sheet: Box<dyn StyleSheet + 'a>,
+ gap: u16,
+ padding: u16,
+}
+
+impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer>
+where
+ Renderer: text::Renderer,
+{
+ /// The default padding of a [`Tooltip`] drawn by this renderer.
+ const DEFAULT_PADDING: u16 = 5;
+
+ /// Creates a new [`Tooltip`].
+ ///
+ /// [`Tooltip`]: struct.Tooltip.html
+ pub fn new(
+ content: impl Into<Element<'a, Message, Renderer>>,
+ tooltip: impl ToString,
+ position: Position,
+ ) -> Self {
+ Tooltip {
+ content: content.into(),
+ tooltip: Text::new(tooltip.to_string()),
+ position,
+ style_sheet: Default::default(),
+ gap: 0,
+ padding: Self::DEFAULT_PADDING,
+ }
+ }
+
+ /// Sets the size of the text of the [`Tooltip`].
+ pub fn size(mut self, size: u16) -> Self {
+ self.tooltip = self.tooltip.size(size);
+ self
+ }
+
+ /// Sets the font of the [`Tooltip`].
+ ///
+ /// [`Font`]: Renderer::Font
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.tooltip = self.tooltip.font(font);
+ self
+ }
+
+ /// Sets the gap between the content and its [`Tooltip`].
+ pub fn gap(mut self, gap: u16) -> Self {
+ self.gap = gap;
+ self
+ }
+
+ /// Sets the padding of the [`Tooltip`].
+ pub fn padding(mut self, padding: u16) -> Self {
+ self.padding = padding;
+ self
+ }
+
+ /// Sets the style of the [`Tooltip`].
+ pub fn style(
+ mut self,
+ style_sheet: impl Into<Box<dyn StyleSheet + 'a>>,
+ ) -> Self {
+ self.style_sheet = style_sheet.into();
+ self
+ }
+}
+
+impl<'a, Message, Renderer> Widget<Message, Renderer>
+ for Tooltip<'a, Message, Renderer>
+where
+ Renderer: text::Renderer,
+{
+ fn children(&self) -> Vec<Tree> {
+ vec![Tree::new(&self.content)]
+ }
+
+ fn diff(&self, tree: &mut Tree) {
+ tree.diff_children(std::slice::from_ref(&self.content))
+ }
+
+ fn width(&self) -> Length {
+ self.content.as_widget().width()
+ }
+
+ fn height(&self) -> Length {
+ self.content.as_widget().height()
+ }
+
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.content.as_widget().layout(renderer, limits)
+ }
+
+ fn on_event(
+ &mut self,
+ tree: &mut Tree,
+ event: Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ renderer: &Renderer,
+ clipboard: &mut dyn Clipboard,
+ shell: &mut Shell<'_, Message>,
+ ) -> event::Status {
+ self.content.as_widget_mut().on_event(
+ &mut tree.children[0],
+ event,
+ layout,
+ cursor_position,
+ renderer,
+ clipboard,
+ shell,
+ )
+ }
+
+ fn mouse_interaction(
+ &self,
+ tree: &Tree,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ renderer: &Renderer,
+ ) -> mouse::Interaction {
+ self.content.as_widget().mouse_interaction(
+ &tree.children[0],
+ layout.children().next().unwrap(),
+ cursor_position,
+ viewport,
+ renderer,
+ )
+ }
+
+ fn draw(
+ &self,
+ tree: &Tree,
+ renderer: &mut Renderer,
+ inherited_style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) {
+ self.content.as_widget().draw(
+ &tree.children[0],
+ renderer,
+ inherited_style,
+ layout,
+ cursor_position,
+ viewport,
+ );
+
+ let tooltip = &self.tooltip;
+
+ tooltip::draw(
+ renderer,
+ inherited_style,
+ layout,
+ cursor_position,
+ viewport,
+ self.position,
+ self.gap,
+ self.padding,
+ self.style_sheet.as_ref(),
+ |renderer, limits| {
+ Widget::<(), Renderer>::layout(tooltip, renderer, limits)
+ },
+ |renderer, defaults, layout, cursor_position, viewport| {
+ Widget::<(), Renderer>::draw(
+ tooltip,
+ &Tree::empty(),
+ renderer,
+ defaults,
+ layout,
+ cursor_position,
+ viewport,
+ );
+ },
+ );
+ }
+
+ fn overlay<'b>(
+ &'b self,
+ tree: &'b mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ ) -> Option<overlay::Element<'b, Message, Renderer>> {
+ self.content.as_widget().overlay(
+ &mut tree.children[0],
+ layout,
+ renderer,
+ )
+ }
+}
+
+impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>>
+ for Element<'a, Message, Renderer>
+where
+ Renderer: 'a + text::Renderer,
+ Message: 'a,
+{
+ fn from(
+ tooltip: Tooltip<'a, Message, Renderer>,
+ ) -> Element<'a, Message, Renderer> {
+ Element::new(tooltip)
+ }
+}
diff --git a/pure/src/widget/tree.rs b/pure/src/widget/tree.rs
index bd7c259c..d81dd02c 100644
--- a/pure/src/widget/tree.rs
+++ b/pure/src/widget/tree.rs
@@ -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,
diff --git a/src/application.rs b/src/application.rs
index 14a16d61..11735b93 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -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/
diff --git a/src/lib.rs b/src/lib.rs
index cbda3c87..298beae3 100644
--- a/src/lib.rs
+++ b/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"))]
@@ -225,8 +226,8 @@ pub use settings::Settings;
pub use runtime::alignment;
pub use runtime::futures;
pub use runtime::{
- Alignment, Background, Color, Command, ContentFit, Font, Length, Point,
- Rectangle, Size, Subscription, Vector,
+ Alignment, Background, Color, Command, ContentFit, Font, Length, Padding,
+ Point, Rectangle, Size, Subscription, Vector,
};
#[cfg(feature = "system")]
diff --git a/src/pure.rs b/src/pure.rs
index 948183f1..7785a104 100644
--- a/src/pure.rs
+++ b/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`].
diff --git a/src/pure/widget.rs b/src/pure/widget.rs
index 6628b1fb..c84edde3 100644
--- a/src/pure/widget.rs
+++ b/src/pure/widget.rs
@@ -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,
@@ -118,6 +118,15 @@ pub mod text_input {
iced_pure::widget::TextInput<'a, Message, Renderer>;
}
+pub mod tooltip {
+ //! Display a widget over another.
+ pub use iced_pure::widget::tooltip::Position;
+
+ /// A widget allowing the selection of a single value from a list of options.
+ pub type Tooltip<'a, Message> =
+ iced_pure::widget::Tooltip<'a, Message, crate::Renderer>;
+}
+
pub use iced_pure::widget::progress_bar;
pub use iced_pure::widget::rule;
pub use iced_pure::widget::slider;
@@ -135,6 +144,7 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
pub use text_input::TextInput;
pub use toggler::Toggler;
+pub use tooltip::Tooltip;
#[cfg(feature = "canvas")]
pub use iced_graphics::widget::pure::canvas;
diff --git a/src/sandbox.rs b/src/sandbox.rs
index 2306c650..e7e97920 100644
--- a/src/sandbox.rs
+++ b/src/sandbox.rs
@@ -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
///
diff --git a/src/widget.rs b/src/widget.rs
index 9cc0832f..5e2b63fc 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -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;
diff --git a/style/Cargo.toml b/style/Cargo.toml
index 047c905d..bb2a9645 100644
--- a/style/Cargo.toml
+++ b/style/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_style"
-version = "0.3.0"
+version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "The default set of styles of Iced"
@@ -11,5 +11,5 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"]
[dependencies.iced_core]
-version = "0.4"
+version = "0.5"
path = "../core"
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index b4173413..6911ff56 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "iced_wgpu"
-version = "0.4.0"
+version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A wgpu renderer for Iced"
@@ -43,11 +43,11 @@ version = "1.4"
features = ["derive"]
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_graphics]
-version = "0.2"
+version = "0.3"
path = "../graphics"
features = ["font-fallback", "font-icons"]
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index 5d4f5edd..ebe48510 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -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
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index 7758899c..3b9ae859 100644
--- a/winit/Cargo.toml
+++ b/winit/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "iced_winit"
-version = "0.3.0"
+version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021"
description = "A winit runtime for Iced"
license = "MIT"
-repository = "https://github.com/hecrj/iced"
+repository = "https://github.com/iced-rs/iced"
documentation = "https://docs.rs/iced_winit"
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"]
@@ -25,15 +25,15 @@ git = "https://github.com/iced-rs/winit"
rev = "02a12380960cec2f351c09a33d6a7cc2789d96a6"
[dependencies.iced_native]
-version = "0.4"
+version = "0.5"
path = "../native"
[dependencies.iced_graphics]
-version = "0.2"
+version = "0.3"
path = "../graphics"
[dependencies.iced_futures]
-version = "0.3"
+version = "0.4"
path = "../futures"
[target.'cfg(target_os = "windows")'.dependencies.winapi]
diff --git a/winit/README.md b/winit/README.md
index 5a94cd92..3ca46fff 100644
--- a/winit/README.md
+++ b/winit/README.md
@@ -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`].
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index b00a095d..8e6c0b37 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -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 {
diff --git a/winit/src/lib.rs b/winit/src/lib.rs
index 4e5cb637..22e7efdf 100644
--- a/winit/src/lib.rs
+++ b/winit/src/lib.rs
@@ -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(
diff --git a/winit/src/settings.rs b/winit/src/settings.rs
index 9a93824a..213ef47f 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings.rs
@@ -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,
}