Merge branch 'master' into dev/system-information

This commit is contained in:
Héctor Ramón Jiménez 2022-05-04 17:19:28 +02:00
commit 27fdc70756
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
90 changed files with 1363 additions and 334 deletions

View file

@ -10,13 +10,19 @@ jobs:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
steps: steps:
- uses: hecrj/setup-rust-action@v1 - uses: hecrj/setup-rust-action@v1
with:
rust-version: nightly
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Generate documentation - name: Generate documentation
run: | run: |
cargo doc --no-deps --all-features \ RUSTDOCFLAGS="--cfg docsrs" \
cargo doc --no-deps --all-features \
-p iced_core \ -p iced_core \
-p iced_style \
-p iced_futures \
-p iced_native \ -p iced_native \
-p iced_lazy \ -p iced_lazy \
-p iced_pure \
-p iced_graphics \ -p iced_graphics \
-p iced_wgpu \ -p iced_wgpu \
-p iced_glow \ -p iced_glow \

View file

@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [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 ## [0.3.0] - 2021-03-31
### Added ### Added
- Touch support. [#57] [#650] (thanks to @simlay and @discordance!) - 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 ### Added
- First release! :tada: - 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.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.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 [0.1.1]: https://github.com/iced-rs/iced/compare/0.1.0...0.1.1

View file

@ -2,7 +2,7 @@
Thank you for considering contributing to Iced! Feel free to read [the ecosystem overview] and [the roadmap] to get an idea of the current state of the library. 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]! This is a very important step. It helps to coordinate work, get on the same page, and start building trust. Please, do not skip it! Remember that [Code is the Easy Part] and also [The Hard Parts of Open Source]!

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced" name = "iced"
version = "0.3.0" version = "0.4.2"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A cross-platform GUI library inspired by Elm" description = "A cross-platform GUI library inspired by Elm"
@ -96,26 +96,27 @@ members = [
"examples/pure/pane_grid", "examples/pure/pane_grid",
"examples/pure/pick_list", "examples/pure/pick_list",
"examples/pure/todos", "examples/pure/todos",
"examples/pure/tooltip",
"examples/pure/tour", "examples/pure/tour",
] ]
[dependencies] [dependencies]
iced_core = { version = "0.4", path = "core" } iced_core = { version = "0.5", path = "core" }
iced_futures = { version = "0.3", path = "futures" } iced_futures = { version = "0.4", path = "futures" }
iced_native = { version = "0.4", path = "native" } iced_native = { version = "0.5", path = "native" }
iced_graphics = { version = "0.2", path = "graphics" } iced_graphics = { version = "0.3", path = "graphics" }
iced_winit = { version = "0.3", path = "winit" } iced_winit = { version = "0.4", path = "winit" }
iced_glutin = { version = "0.2", path = "glutin", optional = true } iced_glutin = { version = "0.3", path = "glutin", optional = true }
iced_glow = { version = "0.2", path = "glow", optional = true } iced_glow = { version = "0.3", path = "glow", optional = true }
iced_pure = { version = "0.1", path = "pure", optional = true } iced_pure = { version = "0.2", path = "pure", optional = true }
thiserror = "1.0" thiserror = "1.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [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] [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] [package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
features = ["image", "svg", "canvas", "qr_code"] features = ["image", "svg", "canvas", "qr_code", "pure"]

View file

@ -2,13 +2,13 @@
<img src="docs/logo.svg" width="140px" /> <img src="docs/logo.svg" width="140px" />
# iced # Iced
[![Documentation](https://docs.rs/iced/badge.svg)][documentation] [![Documentation](https://docs.rs/iced/badge.svg)][documentation]
[![Crates.io](https://img.shields.io/crates/v/iced.svg)](https://crates.io/crates/iced) [![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) [![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) [![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. A cross-platform GUI library for Rust focused on simplicity and type-safety.
@ -40,11 +40,11 @@ Inspired by [Elm].
* A [windowing shell] * A [windowing shell]
* A [web runtime] leveraging the DOM * 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!] [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 [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 [text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
[scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
[Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee [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`: Add `iced` as a dependency in your `Cargo.toml`:
```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]. you want to learn about a specific release, check out [the release list].
[the release list]: https://github.com/iced-rs/iced/releases [the release list]: https://github.com/iced-rs/iced/releases
## Overview ## 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: into four different concepts:
* __State__ — the state of your application * __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: to:
1. Take the result of our __view logic__ and layout its widgets. 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! Browse the [documentation] and the [examples] to learn more!
## Implementation details ## 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 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]. 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"> <p align="center">
<a href="ECOSYSTEM.md"> <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> </a>
</p> </p>
@ -215,14 +215,14 @@ $ cargo run --features iced/glow --package game_of_life
and then use it in your project with and then use it in your project with
```toml ```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, **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 but if you don't, right now there's no software fallback, so it means your hardware
doesn't support Iced. 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 ## Contributing / Feedback
Contributions are greatly appreciated! If you want to contribute, please 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. the [Rust Community Discord]. I go by `lone_scientist#9554` there.
## Sponsors ## 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/ [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 [Coffee]: https://github.com/hecrj/coffee
[Elm]: https://elm-lang.org/ [Elm]: https://elm-lang.org/
[The Elm Architecture]: https://guide.elm-lang.org/architecture/ [The Elm Architecture]: https://guide.elm-lang.org/architecture/
[the current issues]: https://github.com/hecrj/iced/issues [the current issues]: https://github.com/iced-rs/iced/issues
[contributing guidelines]: https://github.com/hecrj/iced/blob/master/CONTRIBUTING.md [contributing guidelines]: https://github.com/iced-rs/iced/blob/master/CONTRIBUTING.md
[Discord server]: https://discord.gg/3xZJ65GAhd [Discord server]: https://discord.gg/3xZJ65GAhd
[Rust Community Discord]: https://bit.ly/rust-community [Rust Community Discord]: https://bit.ly/rust-community
[Cryptowatch]: https://cryptowat.ch/charts [Cryptowatch]: https://cryptowat.ch/charts

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_core" name = "iced_core"
version = "0.4.0" version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "The essential concepts of Iced" description = "The essential concepts of Iced"

View file

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

View file

@ -7,8 +7,11 @@
//! ![The foundations of the Iced ecosystem](https://github.com/iced-rs/iced/blob/0525d76ff94e828b7b21634fa94a747022001c83/docs/graphs/foundations.png?raw=true) //! ![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]: 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
//! [`iced_web`]: https://github.com/iced-rs/iced/tree/master/web //! [`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_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(unused_results)] #![deny(unused_results)]

View file

@ -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"] }

View file

@ -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()
}
}
}
}

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_futures" name = "iced_futures"
version = "0.3.0" version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "Commands, subscriptions, and runtimes for Iced" description = "Commands, subscriptions, and runtimes for Iced"

View file

@ -17,7 +17,7 @@ impl<T> Command<T> {
Self(Internal::None) 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 { pub const fn single(action: T) -> Self {
Self(Internal::Single(action)) Self(Internal::Single(action))
} }

View file

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

View file

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

View file

@ -1,11 +1,11 @@
[package] [package]
name = "iced_glow" name = "iced_glow"
version = "0.2.0" version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A glow renderer for iced" description = "A glow renderer for iced"
license = "MIT AND OFL-1.1" license = "MIT AND OFL-1.1"
repository = "https://github.com/hecrj/iced" repository = "https://github.com/iced-rs/iced"
[features] [features]
canvas = ["iced_graphics/canvas"] canvas = ["iced_graphics/canvas"]
@ -24,11 +24,11 @@ bytemuck = "1.4"
log = "0.4" log = "0.4"
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_graphics] [dependencies.iced_graphics]
version = "0.2" version = "0.3"
path = "../graphics" path = "../graphics"
features = ["font-fallback", "font-icons", "opengl"] features = ["font-fallback", "font-icons", "opengl"]

View file

@ -1,12 +1,12 @@
# `iced_glow` # `iced_glow`
[![Documentation](https://docs.rs/iced_glow/badge.svg)][documentation] [![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) [![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) [![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. `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: Currently, `iced_glow` supports the following primitives:
- Text, which is rendered using [`glow_glyph`]. No shaping at all. - 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 __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]. 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 ## Current limitations

View file

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

View file

@ -1,9 +1,9 @@
//! A [`glow`] renderer for [`iced_native`]. //! 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 //! [`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( #![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)] )]
@ -37,5 +37,5 @@ pub use iced_native::{Alignment, Background, Color, Command, Length, Vector};
/// A [`glow`] graphics renderer for [`iced`]. /// A [`glow`] graphics renderer for [`iced`].
/// ///
/// [`glow`]: https://github.com/grovesNL/glow /// [`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>; pub type Renderer = iced_graphics::Renderer<Backend>;

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_glutin" name = "iced_glutin"
version = "0.2.0" version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A glutin runtime for Iced" description = "A glutin runtime for Iced"
@ -23,14 +23,14 @@ git = "https://github.com/iced-rs/glutin"
rev = "7a0ee02782eb2bf059095e0c953c4bb53f1eef0e" rev = "7a0ee02782eb2bf059095e0c953c4bb53f1eef0e"
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_winit] [dependencies.iced_winit]
version = "0.3" version = "0.4"
path = "../winit" path = "../winit"
[dependencies.iced_graphics] [dependencies.iced_graphics]
version = "0.2" version = "0.3"
path = "../graphics" path = "../graphics"
features = ["opengl"] features = ["opengl"]

View file

@ -1,11 +1,11 @@
[package] [package]
name = "iced_graphics" name = "iced_graphics"
version = "0.2.0" version = "0.3.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced" description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
license = "MIT" license = "MIT"
repository = "https://github.com/hecrj/iced" repository = "https://github.com/iced-rs/iced"
documentation = "https://docs.rs/iced_graphics" documentation = "https://docs.rs/iced_graphics"
keywords = ["gui", "ui", "graphics", "interface", "widgets"] keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"] categories = ["gui"]
@ -29,15 +29,15 @@ version = "1.4"
features = ["derive"] features = ["derive"]
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_style] [dependencies.iced_style]
version = "0.3" version = "0.4"
path = "../style" path = "../style"
[dependencies.iced_pure] [dependencies.iced_pure]
version = "0.1" version = "0.2"
path = "../pure" path = "../pure"
optional = true optional = true

View file

@ -1,9 +1,9 @@
//! A bunch of backend-agnostic types that can be leveraged to build a renderer //! A bunch of backend-agnostic types that can be leveraged to build a renderer
//! for [`iced`]. //! 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( #![doc(
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
)] )]

View file

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

View file

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

View file

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

View file

@ -1,7 +1,14 @@
[package] [package]
name = "iced_lazy" name = "iced_lazy"
version = "0.1.0" version = "0.1.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" 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] [features]
pure = ["iced_pure"] pure = ["iced_pure"]
@ -10,10 +17,10 @@ pure = ["iced_pure"]
ouroboros = "0.13" ouroboros = "0.13"
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_pure] [dependencies.iced_pure]
version = "0.1" version = "0.2"
path = "../pure" path = "../pure"
optional = true optional = true

View file

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

View file

@ -67,12 +67,13 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> {
self.element = view(new_size); self.element = view(new_size);
self.size = new_size; self.size = new_size;
tree.diff(&self.element);
self.layout = self self.layout = self
.element .element
.as_widget() .as_widget()
.layout(renderer, &layout::Limits::new(Size::ZERO, self.size)); .layout(renderer, &layout::Limits::new(Size::ZERO, self.size));
tree.diff(&self.element);
} }
fn resolve<R, T>( fn resolve<R, T>(

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_native" name = "iced_native"
version = "0.4.0" version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A renderer-agnostic library for native GUIs" description = "A renderer-agnostic library for native GUIs"
@ -16,14 +16,14 @@ unicode-segmentation = "1.6"
num-traits = "0.2" num-traits = "0.2"
[dependencies.iced_core] [dependencies.iced_core]
version = "0.4" version = "0.5"
path = "../core" path = "../core"
[dependencies.iced_futures] [dependencies.iced_futures]
version = "0.3" version = "0.4"
path = "../futures" path = "../futures"
features = ["thread-pool"] features = ["thread-pool"]
[dependencies.iced_style] [dependencies.iced_style]
version = "0.3" version = "0.4"
path = "../style" path = "../style"

View file

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

View file

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

View file

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

View file

@ -63,7 +63,7 @@ where
event::Status::Ignored 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`]. /// By default, it returns [`mouse::Interaction::Idle`].
fn mouse_interaction( fn mouse_interaction(

View file

@ -1,24 +1,4 @@
//! Write your own renderer. //! 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)] #[cfg(debug_assertions)]
mod null; mod null;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -27,8 +7,7 @@ pub use null::Null;
use crate::layout; use crate::layout;
use crate::{Background, Color, Element, Rectangle, Vector}; use crate::{Background, Color, Element, Rectangle, Vector};
/// A component that can take the state of a user interface and produce an /// A component that can be used by widgets to draw themselves on a screen.
/// output for its users.
pub trait Renderer: Sized { pub trait Renderer: Sized {
/// Lays out the elements of a user interface. /// Lays out the elements of a user interface.
/// ///

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
/// Sets the vertical spacing _between_ elements. /// 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 /// method instead! While less flexible, it helps you keep spacing between
/// elements consistent. /// elements consistent.
pub fn spacing(mut self, units: u16) -> Self { pub fn spacing(mut self, units: u16) -> Self {

View file

@ -6,7 +6,7 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support. //! 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 axis;
mod configuration; mod configuration;
mod content; mod content;

View file

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

View file

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

View file

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

View file

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

View file

@ -402,21 +402,24 @@ pub fn draw<T, Renderer>(
if let Some(label) = if let Some(label) =
label.as_ref().map(String::as_str).or_else(|| placeholder) 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 { renderer.fill_text(Text {
content: label, content: label,
size: f32::from(text_size.unwrap_or(renderer.default_size())), size: text_size,
font: font.clone(), font: font.clone(),
color: is_selected color: is_selected
.then(|| style.text_color) .then(|| style.text_color)
.unwrap_or(style.placeholder_color), .unwrap_or(style.placeholder_color),
bounds: Rectangle { bounds: Rectangle {
x: bounds.x + f32::from(padding.left), x: bounds.x + f32::from(padding.left),
y: bounds.center_y(), y: bounds.center_y() - text_size / 2.0,
..bounds width: bounds.width - f32::from(padding.horizontal()),
height: text_size,
}, },
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Top,
}) });
} }
} }

View file

@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
/// Sets the horizontal spacing _between_ elements. /// 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 /// method instead! While less flexible, it helps you keep spacing between
/// elements consistent. /// elements consistent.
pub fn spacing(mut self, units: u16) -> Self { pub fn spacing(mut self, units: u16) -> Self {

View file

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

View file

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

View file

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

View file

@ -29,7 +29,7 @@ where
/// The default padding of a [`Tooltip`] drawn by this renderer. /// The default padding of a [`Tooltip`] drawn by this renderer.
const DEFAULT_PADDING: u16 = 5; const DEFAULT_PADDING: u16 = 5;
/// Creates an empty [`Tooltip`]. /// Creates a new [`Tooltip`].
/// ///
/// [`Tooltip`]: struct.Tooltip.html /// [`Tooltip`]: struct.Tooltip.html
pub fn new( pub fn new(
@ -98,6 +98,117 @@ pub enum Position {
Right, 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> impl<'a, Message, Renderer> Widget<Message, Renderer>
for Tooltip<'a, Message, Renderer> for Tooltip<'a, Message, Renderer>
where where
@ -169,100 +280,32 @@ where
viewport, viewport,
); );
let bounds = layout.bounds(); let tooltip = &self.tooltip;
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);
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( Widget::<(), Renderer>::draw(
&self.tooltip, tooltip,
renderer, renderer,
&defaults, defaults,
Layout::with_offset( layout,
Vector::new(
tooltip_bounds.x + padding,
tooltip_bounds.y + padding,
),
&text_layout,
),
cursor_position, cursor_position,
viewport, viewport,
); );
}); },
} )
} }
} }
@ -273,8 +316,8 @@ where
Message: 'a, Message: 'a,
{ {
fn from( fn from(
column: Tooltip<'a, Message, Renderer>, tooltip: Tooltip<'a, Message, Renderer>,
) -> Element<'a, Message, Renderer> { ) -> Element<'a, Message, Renderer> {
Element::new(column) Element::new(tooltip)
} }
} }

View file

@ -1,9 +1,15 @@
[package] [package]
name = "iced_pure" name = "iced_pure"
version = "0.1.0" version = "0.2.0"
edition = "2021" 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] [dependencies]
iced_native = { version = "0.4", path = "../native" } iced_native = { version = "0.5", path = "../native" }
iced_style = { version = "0.3", path = "../style" } iced_style = { version = "0.4", path = "../style" }
num-traits = "0.2" num-traits = "0.2"

View file

@ -8,25 +8,171 @@ use iced_native::mouse;
use iced_native::renderer; use iced_native::renderer;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; 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> { pub struct Element<'a, Message, Renderer> {
widget: Box<dyn Widget<Message, Renderer> + 'a>, widget: Box<dyn Widget<Message, Renderer> + 'a>,
} }
impl<'a, Message, Renderer> Element<'a, Message, Renderer> { 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 { pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self {
Self { Self {
widget: Box::new(widget), widget: Box::new(widget),
} }
} }
/// Returns a reference to the [`Widget`] of the [`Element`],
pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> { pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> {
self.widget.as_ref() 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> { pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Renderer> {
self.widget.as_mut() 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>( pub fn map<B>(
self, self,
f: impl Fn(Message) -> B + 'a, f: impl Fn(Message) -> B + 'a,

View file

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

View file

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

View file

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

View file

@ -1,9 +1,14 @@
//! Display interactive elements on top of other widgets.
use crate::widget::Tree; use crate::widget::Tree;
use iced_native::Layout; use iced_native::Layout;
pub use iced_native::overlay::*; 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>( pub fn from_children<'a, Message, Renderer>(
children: &'a [crate::Element<'_, Message, Renderer>], children: &'a [crate::Element<'_, Message, Renderer>],
tree: &'a mut Tree, tree: &'a mut Tree,

View file

@ -1,3 +1,4 @@
//! Use the built-in widgets or create your own.
pub mod button; pub mod button;
pub mod checkbox; pub mod checkbox;
pub mod container; pub mod container;
@ -12,6 +13,7 @@ pub mod slider;
pub mod svg; pub mod svg;
pub mod text_input; pub mod text_input;
pub mod toggler; pub mod toggler;
pub mod tooltip;
pub mod tree; pub mod tree;
mod column; mod column;
@ -37,6 +39,7 @@ pub use svg::Svg;
pub use text::Text; pub use text::Text;
pub use text_input::TextInput; pub use text_input::TextInput;
pub use toggler::Toggler; pub use toggler::Toggler;
pub use tooltip::{Position, Tooltip};
pub use tree::Tree; pub use tree::Tree;
use iced_native::event::{self, Event}; use iced_native::event::{self, Event};
@ -46,17 +49,28 @@ use iced_native::overlay;
use iced_native::renderer; use iced_native::renderer;
use iced_native::{Clipboard, Length, Point, Rectangle, Shell}; 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> { pub trait Widget<Message, Renderer> {
/// Returns the width of the [`Widget`].
fn width(&self) -> Length; fn width(&self) -> Length;
/// Returns the height of the [`Widget`].
fn height(&self) -> Length; 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( fn layout(
&self, &self,
renderer: &Renderer, renderer: &Renderer,
limits: &layout::Limits, limits: &layout::Limits,
) -> layout::Node; ) -> layout::Node;
/// Draws the [`Widget`] using the associated `Renderer`.
fn draw( fn draw(
&self, &self,
state: &Tree, state: &Tree,
@ -67,31 +81,31 @@ pub trait Widget<Message, Renderer> {
viewport: &Rectangle, viewport: &Rectangle,
); );
/// Returns the [`Tag`] of the [`Widget`].
///
/// [`Tag`]: tree::Tag
fn tag(&self) -> tree::Tag { fn tag(&self) -> tree::Tag {
tree::Tag::stateless() tree::Tag::stateless()
} }
/// Returns the [`State`] of the [`Widget`].
///
/// [`State`]: tree::State
fn state(&self) -> tree::State { fn state(&self) -> tree::State {
tree::State::None tree::State::None
} }
/// Returns the state [`Tree`] of the children of the [`Widget`].
fn children(&self) -> Vec<Tree> { fn children(&self) -> Vec<Tree> {
Vec::new() Vec::new()
} }
/// Reconciliates the [`Widget`] with the provided [`Tree`].
fn diff(&self, _tree: &mut Tree) {} fn diff(&self, _tree: &mut Tree) {}
fn mouse_interaction( /// Processes a runtime [`Event`].
&self, ///
_state: &Tree, /// By default, it does nothing.
_layout: Layout<'_>,
_cursor_position: Point,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse::Interaction::Idle
}
fn on_event( fn on_event(
&mut self, &mut self,
_state: &mut Tree, _state: &mut Tree,
@ -105,6 +119,21 @@ pub trait Widget<Message, Renderer> {
event::Status::Ignored 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>( fn overlay<'a>(
&'a self, &'a self,
_state: &'a mut Tree, _state: &'a mut Tree,

View file

@ -1,3 +1,4 @@
//! Allow your users to perform actions by pressing a button.
use crate::overlay; use crate::overlay;
use crate::widget::tree::{self, Tree}; use crate::widget::tree::{self, Tree};
use crate::{Element, Widget}; use crate::{Element, Widget};
@ -15,6 +16,40 @@ pub use iced_style::button::{Style, StyleSheet};
use button::State; 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> { pub struct Button<'a, Message, Renderer> {
content: Element<'a, Message, Renderer>, content: Element<'a, Message, Renderer>,
on_press: Option<Message>, on_press: Option<Message>,
@ -25,6 +60,7 @@ pub struct Button<'a, Message, Renderer> {
} }
impl<'a, Message, Renderer> 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 { pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self {
Button { Button {
content: content.into(), content: content.into(),

View file

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

View file

@ -13,6 +13,7 @@ use iced_native::{
use std::u32; use std::u32;
/// A container that distributes its contents vertically.
pub struct Column<'a, Message, Renderer> { pub struct Column<'a, Message, Renderer> {
spacing: u16, spacing: u16,
padding: Padding, padding: Padding,
@ -24,10 +25,12 @@ pub struct Column<'a, Message, Renderer> {
} }
impl<'a, Message, Renderer> Column<'a, Message, Renderer> { impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
/// Creates an empty [`Column`].
pub fn new() -> Self { pub fn new() -> Self {
Self::with_children(Vec::new()) Self::with_children(Vec::new())
} }
/// Creates a [`Column`] with the given elements.
pub fn with_children( pub fn with_children(
children: Vec<Element<'a, Message, Renderer>>, children: Vec<Element<'a, Message, Renderer>>,
) -> Self { ) -> 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 { pub fn spacing(mut self, units: u16) -> Self {
self.spacing = units; self.spacing = units;
self self
} }
/// Sets the [`Padding`] of the [`Column`].
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into(); self.padding = padding.into();
self self
} }
/// Sets the width of the [`Column`].
pub fn width(mut self, width: Length) -> Self { pub fn width(mut self, width: Length) -> Self {
self.width = width; self.width = width;
self self
} }
/// Sets the height of the [`Column`].
pub fn height(mut self, height: Length) -> Self { pub fn height(mut self, height: Length) -> Self {
self.height = height; self.height = height;
self self
@ -68,11 +79,13 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
self self
} }
/// Sets the horizontal alignment of the contents of the [`Column`] .
pub fn align_items(mut self, align: Alignment) -> Self { pub fn align_items(mut self, align: Alignment) -> Self {
self.align_items = align; self.align_items = align;
self self
} }
/// Adds an element to the [`Column`].
pub fn push( pub fn push(
mut self, mut self,
child: impl Into<Element<'a, Message, Renderer>>, child: impl Into<Element<'a, Message, Renderer>>,

View file

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

View file

@ -6,7 +6,7 @@
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support. //! 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 content;
mod title_bar; mod title_bar;
@ -213,7 +213,7 @@ where
fn diff(&self, tree: &mut Tree) { fn diff(&self, tree: &mut Tree) {
tree.diff_children_custom( tree.diff_children_custom(
&self.elements, &self.elements,
|(_, content), state| content.diff(state), |state, (_, content)| content.diff(state),
|(_, content)| content.state(), |(_, content)| content.state(),
) )
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,7 @@ use iced_native::{
Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell, Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell,
}; };
/// A container that distributes its contents horizontally.
pub struct Row<'a, Message, Renderer> { pub struct Row<'a, Message, Renderer> {
spacing: u16, spacing: u16,
padding: Padding, padding: Padding,
@ -21,10 +22,12 @@ pub struct Row<'a, Message, Renderer> {
} }
impl<'a, Message, Renderer> Row<'a, Message, Renderer> { impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
/// Creates an empty [`Row`].
pub fn new() -> Self { pub fn new() -> Self {
Self::with_children(Vec::new()) Self::with_children(Vec::new())
} }
/// Creates a [`Row`] with the given elements.
pub fn with_children( pub fn with_children(
children: Vec<Element<'a, Message, Renderer>>, children: Vec<Element<'a, Message, Renderer>>,
) -> Self { ) -> 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 { pub fn spacing(mut self, units: u16) -> Self {
self.spacing = units; self.spacing = units;
self self
} }
/// Sets the [`Padding`] of the [`Row`].
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
self.padding = padding.into(); self.padding = padding.into();
self self
} }
/// Sets the width of the [`Row`].
pub fn width(mut self, width: Length) -> Self { pub fn width(mut self, width: Length) -> Self {
self.width = width; self.width = width;
self self
} }
/// Sets the height of the [`Row`].
pub fn height(mut self, height: Length) -> Self { pub fn height(mut self, height: Length) -> Self {
self.height = height; self.height = height;
self self
} }
/// Sets the vertical alignment of the contents of the [`Row`] .
pub fn align_items(mut self, align: Alignment) -> Self { pub fn align_items(mut self, align: Alignment) -> Self {
self.align_items = align; self.align_items = align;
self self
} }
/// Adds an [`Element`] to the [`Row`].
pub fn push( pub fn push(
mut self, mut self,
child: impl Into<Element<'a, Message, Renderer>>, child: impl Into<Element<'a, Message, Renderer>>,

View file

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

View file

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

View file

@ -1,6 +1,4 @@
//! Display an interactive selector of a single value from a range of values. //! 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::widget::tree::{self, Tree};
use crate::{Element, Widget}; use crate::{Element, Widget};
@ -25,17 +23,16 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # use iced_native::widget::slider::{self, Slider}; /// # use iced_pure::widget::Slider;
/// # /// #
/// #[derive(Clone)] /// #[derive(Clone)]
/// pub enum Message { /// pub enum Message {
/// SliderChanged(f32), /// SliderChanged(f32),
/// } /// }
/// ///
/// let state = &mut slider::State::new();
/// let value = 50.0; /// 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) /// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true)

View file

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

View file

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

View file

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

228
pure/src/widget/tooltip.rs Normal file
View file

@ -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)
}
}

View file

@ -1,14 +1,24 @@
//! Store internal widget state in a state tree to ensure continuity.
use crate::Element; use crate::Element;
use std::any::{self, Any}; 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 { pub struct Tree {
/// The tag of the [`Tree`].
pub tag: Tag, pub tag: Tag,
/// The [`State`] of the [`Tree`].
pub state: State, pub state: State,
/// The children of the root widget of the [`Tree`].
pub children: Vec<Tree>, pub children: Vec<Tree>,
} }
impl Tree { impl Tree {
/// Creates an empty, stateless [`Tree`] with no children.
pub fn empty() -> Self { pub fn empty() -> Self {
Self { Self {
tag: Tag::stateless(), tag: Tag::stateless(),
@ -17,6 +27,7 @@ impl Tree {
} }
} }
/// Creates a new [`Tree`] for the provided [`Element`].
pub fn new<Message, Renderer>( pub fn new<Message, Renderer>(
element: &Element<'_, Message, Renderer>, element: &Element<'_, Message, Renderer>,
) -> Self { ) -> 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>( pub fn diff<Message, Renderer>(
&mut self, &mut self,
new: &Element<'_, Message, Renderer>, 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>( pub fn diff_children<Message, Renderer>(
&mut self, &mut self,
new_children: &[Element<'_, Message, Renderer>], new_children: &[Element<'_, Message, Renderer>],
) { ) {
self.diff_children_custom( self.diff_children_custom(new_children, Self::diff, Self::new)
new_children,
|new, child_state| child_state.diff(new),
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>( pub fn diff_children_custom<T>(
&mut self, &mut self,
new_children: &[T], new_children: &[T],
diff: impl Fn(&T, &mut Tree), diff: impl Fn(&mut Tree, &T),
new_state: impl Fn(&T) -> Self, new_state: impl Fn(&T) -> Self,
) { ) {
if self.children.len() > new_children.len() { if self.children.len() > new_children.len() {
@ -62,7 +80,7 @@ impl Tree {
for (child_state, new) in for (child_state, new) in
self.children.iter_mut().zip(new_children.iter()) self.children.iter_mut().zip(new_children.iter())
{ {
diff(new, child_state); diff(child_state, new);
} }
if self.children.len() < new_children.len() { 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)] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Tag(any::TypeId); pub struct Tag(any::TypeId);
impl Tag { impl Tag {
/// Creates a [`Tag`] for a state of type `T`.
pub fn of<T>() -> Self pub fn of<T>() -> Self
where where
T: 'static, T: 'static,
@ -84,17 +104,23 @@ impl Tag {
Self(any::TypeId::of::<T>()) Self(any::TypeId::of::<T>())
} }
/// Creates a [`Tag`] for a stateless widget.
pub fn stateless() -> Self { pub fn stateless() -> Self {
Self::of::<()>() Self::of::<()>()
} }
} }
/// The internal [`State`] of a widget.
pub enum State { pub enum State {
/// No meaningful internal state.
None, None,
/// Some meaningful internal state.
Some(Box<dyn Any>), Some(Box<dyn Any>),
} }
impl State { impl State {
/// Creates a new [`State`].
pub fn new<T>(state: T) -> Self pub fn new<T>(state: T) -> Self
where where
T: 'static, T: 'static,
@ -102,6 +128,10 @@ impl State {
State::Some(Box::new(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 pub fn downcast_ref<T>(&self) -> &T
where where
T: 'static, 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 pub fn downcast_mut<T>(&mut self) -> &mut T
where where
T: 'static, T: 'static,

View file

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

View file

@ -19,19 +19,19 @@
//! //!
//! Check out the [repository] and the [examples] for more details! //! 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 //! [text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
//! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui //! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
//! [Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee //! [Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
//! [Modular ecosystem]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md //! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
//! [renderer-agnostic native runtime]: https://github.com/hecrj/iced/tree/master/native //! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/0.4/master/native
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
//! [built-in renderer]: https://github.com/hecrj/iced/tree/master/wgpu //! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.4/wgpu
//! [windowing shell]: https://github.com/hecrj/iced/tree/master/winit //! [windowing shell]: https://github.com/iced-rs/iced/tree/0.4/winit
//! [`dodrio`]: https://github.com/fitzgen/dodrio //! [`dodrio`]: https://github.com/fitzgen/dodrio
//! [web runtime]: https://github.com/hecrj/iced/tree/master/web //! [web runtime]: https://github.com/iced-rs/iced_web
//! [examples]: https://github.com/hecrj/iced/tree/0.3/examples //! [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
//! [repository]: https://github.com/hecrj/iced //! [repository]: https://github.com/iced-rs/iced
//! //!
//! # Overview //! # Overview
//! Inspired by [The Elm Architecture], Iced expects you to split user //! Inspired by [The Elm Architecture], Iced expects you to split user
@ -196,6 +196,7 @@ pub mod widget;
pub mod window; pub mod window;
#[cfg(feature = "pure")] #[cfg(feature = "pure")]
#[cfg_attr(docsrs, doc(cfg(feature = "pure")))]
pub mod pure; pub mod pure;
#[cfg(all(not(feature = "glow"), feature = "wgpu"))] #[cfg(all(not(feature = "glow"), feature = "wgpu"))]
@ -225,8 +226,8 @@ pub use settings::Settings;
pub use runtime::alignment; pub use runtime::alignment;
pub use runtime::futures; pub use runtime::futures;
pub use runtime::{ pub use runtime::{
Alignment, Background, Color, Command, ContentFit, Font, Length, Point, Alignment, Background, Color, Command, ContentFit, Font, Length, Padding,
Rectangle, Size, Subscription, Vector, Point, Rectangle, Size, Subscription, Vector,
}; };
#[cfg(feature = "system")] #[cfg(feature = "system")]

View file

@ -14,6 +14,84 @@
//! offers an alternate [`Application`] trait with a completely pure `view` //! offers an alternate [`Application`] trait with a completely pure `view`
//! method. //! 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 //! [the original widgets]: crate::widget
//! [`button::State`]: crate::widget::button::State //! [`button::State`]: crate::widget::button::State
//! [impure `Application`]: crate::Application //! [impure `Application`]: crate::Application
@ -26,6 +104,7 @@ pub use application::Application;
pub use sandbox::Sandbox; pub use sandbox::Sandbox;
pub use iced_pure::helpers::*; pub use iced_pure::helpers::*;
pub use iced_pure::Widget;
pub use iced_pure::{Pure, State}; pub use iced_pure::{Pure, State};
/// A generic, pure [`Widget`]. /// A generic, pure [`Widget`].

View file

@ -47,7 +47,7 @@ pub mod pane_grid {
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
//! drag and drop, and hotkey support. //! 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::{ pub use iced_pure::widget::pane_grid::{
Axis, Configuration, Direction, DragEvent, Line, Node, Pane, Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
ResizeEvent, Split, State, StyleSheet, ResizeEvent, Split, State, StyleSheet,
@ -118,6 +118,15 @@ pub mod text_input {
iced_pure::widget::TextInput<'a, Message, Renderer>; 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::progress_bar;
pub use iced_pure::widget::rule; pub use iced_pure::widget::rule;
pub use iced_pure::widget::slider; pub use iced_pure::widget::slider;
@ -135,6 +144,7 @@ pub use scrollable::Scrollable;
pub use slider::Slider; pub use slider::Slider;
pub use text_input::TextInput; pub use text_input::TextInput;
pub use toggler::Toggler; pub use toggler::Toggler;
pub use tooltip::Tooltip;
#[cfg(feature = "canvas")] #[cfg(feature = "canvas")]
pub use iced_graphics::widget::pure::canvas; pub use iced_graphics::widget::pure::canvas;

View file

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

View file

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

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_style" name = "iced_style"
version = "0.3.0" version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "The default set of styles of Iced" description = "The default set of styles of Iced"
@ -11,5 +11,5 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"] categories = ["gui"]
[dependencies.iced_core] [dependencies.iced_core]
version = "0.4" version = "0.5"
path = "../core" path = "../core"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "iced_wgpu" name = "iced_wgpu"
version = "0.4.0" version = "0.5.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A wgpu renderer for Iced" description = "A wgpu renderer for Iced"
@ -43,11 +43,11 @@ version = "1.4"
features = ["derive"] features = ["derive"]
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_graphics] [dependencies.iced_graphics]
version = "0.2" version = "0.3"
path = "../graphics" path = "../graphics"
features = ["font-fallback", "font-icons"] features = ["font-fallback", "font-icons"]

View file

@ -16,7 +16,7 @@
//! - Meshes of triangles, useful to draw geometry freely. //! - Meshes of triangles, useful to draw geometry freely.
//! //!
//! [Iced]: https://github.com/iced-rs/iced //! [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 //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/ //! [WebGPU API]: https://gpuweb.github.io/gpuweb/
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph //! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph

View file

@ -1,11 +1,11 @@
[package] [package]
name = "iced_winit" name = "iced_winit"
version = "0.3.0" version = "0.4.0"
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
edition = "2021" edition = "2021"
description = "A winit runtime for Iced" description = "A winit runtime for Iced"
license = "MIT" license = "MIT"
repository = "https://github.com/hecrj/iced" repository = "https://github.com/iced-rs/iced"
documentation = "https://docs.rs/iced_winit" documentation = "https://docs.rs/iced_winit"
keywords = ["gui", "ui", "graphics", "interface", "widgets"] keywords = ["gui", "ui", "graphics", "interface", "widgets"]
categories = ["gui"] categories = ["gui"]
@ -25,15 +25,15 @@ git = "https://github.com/iced-rs/winit"
rev = "02a12380960cec2f351c09a33d6a7cc2789d96a6" rev = "02a12380960cec2f351c09a33d6a7cc2789d96a6"
[dependencies.iced_native] [dependencies.iced_native]
version = "0.4" version = "0.5"
path = "../native" path = "../native"
[dependencies.iced_graphics] [dependencies.iced_graphics]
version = "0.2" version = "0.3"
path = "../graphics" path = "../graphics"
[dependencies.iced_futures] [dependencies.iced_futures]
version = "0.3" version = "0.4"
path = "../futures" path = "../futures"
[target.'cfg(target_os = "windows")'.dependencies.winapi] [target.'cfg(target_os = "windows")'.dependencies.winapi]

View file

@ -1,7 +1,7 @@
# `iced_winit` # `iced_winit`
[![Documentation](https://docs.rs/iced_winit/badge.svg)][documentation] [![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) [![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) [![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`]. `iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].

View file

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

View file

@ -1,6 +1,6 @@
//! A windowing shell for Iced, on top of [`winit`]. //! 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`] //! `iced_winit` offers some convenient abstractions on top of [`iced_native`]
//! to quickstart development when using [`winit`]. //! to quickstart development when using [`winit`].
@ -11,7 +11,7 @@
//! Additionally, a [`conversion`] module is available for users that decide to //! Additionally, a [`conversion`] module is available for users that decide to
//! implement a custom event loop. //! 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 //! [`winit`]: https://github.com/rust-windowing/winit
//! [`conversion`]: crate::conversion //! [`conversion`]: crate::conversion
#![doc( #![doc(

View file

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