Merge branch 'master' into dev/system-information
This commit is contained in:
commit
27fdc70756
90 changed files with 1363 additions and 334 deletions
8
.github/workflows/document.yml
vendored
8
.github/workflows/document.yml
vendored
|
|
@ -10,13 +10,19 @@ jobs:
|
|||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
steps:
|
||||
- uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
rust-version: nightly
|
||||
- uses: actions/checkout@v2
|
||||
- name: Generate documentation
|
||||
run: |
|
||||
cargo doc --no-deps --all-features \
|
||||
RUSTDOCFLAGS="--cfg docsrs" \
|
||||
cargo doc --no-deps --all-features \
|
||||
-p iced_core \
|
||||
-p iced_style \
|
||||
-p iced_futures \
|
||||
-p iced_native \
|
||||
-p iced_lazy \
|
||||
-p iced_pure \
|
||||
-p iced_graphics \
|
||||
-p iced_wgpu \
|
||||
-p iced_glow \
|
||||
|
|
|
|||
43
CHANGELOG.md
43
CHANGELOG.md
|
|
@ -6,6 +6,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.4.2] - 2022-05-03
|
||||
### Fixed
|
||||
- `Padding` type not exposed in `iced`.
|
||||
|
||||
## [0.4.1] - 2022-05-02
|
||||
### Fixed
|
||||
- Version number in `README`.
|
||||
|
||||
## [0.4.0] - 2022-05-02
|
||||
### Added
|
||||
- __[Stateless widgets][stateless]__ (#1284)
|
||||
A brand new widget API that removes the need to keep track of internal widget state. No more `button::State` in your application!
|
||||
|
||||
- __[`Component` trait][component]__ (#1131)
|
||||
A new trait to implement custom widgets with internal mutable state while using composition and [The Elm Architecture].
|
||||
|
||||
- __[`Responsive` widget][responsive]__ (#1193)
|
||||
A widget that is aware of its dimensions and can be used to easily build responsive user interfaces.
|
||||
|
||||
- __[Experimental WebGL support][webgl]__ (#1096)
|
||||
Applications can now be rendered into an HTML `canvas` when targeting Wasm by leveraging the WebGL support in [`wgpu`]. Thanks to @pacmancoder and @kaimast!
|
||||
|
||||
- __[Support for Raspberry Pis and older devices][raspberry]__ (#1160)
|
||||
The compatibility of our OpenGL renderer has been improved and should run on any hardware that supports OpenGL 3.0+ or OpenGL ES 2.0+. Additionally, we started maintaining [Docker images for `aarch64` and `armv7`](https://github.com/orgs/iced-rs/packages) to easily cross-compile `iced` applications and target Raspberry Pis. Thanks to @derezzedex!
|
||||
|
||||
- __[Simpler `Renderer` APIs][renderer_apis]__ (#1110)
|
||||
The surface of the `Renderer` APIs of the library has been considerably reduced. Instead of a `Renderer` trait per widget, now there are only 3 traits that are reused by all the widgets.
|
||||
|
||||
[webgl]: https://github.com/iced-rs/iced/pull/1096
|
||||
[renderer_apis]: https://github.com/iced-rs/iced/pull/1110
|
||||
[component]: https://github.com/iced-rs/iced/pull/1131
|
||||
[raspberry]: https://github.com/iced-rs/iced/pull/1160
|
||||
[responsive]: https://github.com/iced-rs/iced/pull/1193
|
||||
[stateless]: https://github.com/iced-rs/iced/pull/1284
|
||||
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
[`wgpu`]: https://github.com/gfx-rs/wgpu
|
||||
|
||||
|
||||
## [0.3.0] - 2021-03-31
|
||||
### Added
|
||||
- Touch support. [#57] [#650] (thanks to @simlay and @discordance!)
|
||||
|
|
@ -219,7 +257,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
- First release! :tada:
|
||||
|
||||
[Unreleased]: https://github.com/iced-rs/iced/compare/0.3.0...HEAD
|
||||
[Unreleased]: https://github.com/iced-rs/iced/compare/0.4.2...HEAD
|
||||
[0.4.2]: https://github.com/iced-rs/iced/compare/0.4.1...0.4.2
|
||||
[0.4.1]: https://github.com/iced-rs/iced/compare/0.4.0...0.4.1
|
||||
[0.4.0]: https://github.com/iced-rs/iced/compare/0.3.0...0.4.0
|
||||
[0.3.0]: https://github.com/iced-rs/iced/compare/0.2.0...0.3.0
|
||||
[0.2.0]: https://github.com/iced-rs/iced/compare/0.1.1...0.2.0
|
||||
[0.1.1]: https://github.com/iced-rs/iced/compare/0.1.0...0.1.1
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Thank you for considering contributing to Iced! Feel free to read [the ecosystem overview] and [the roadmap] to get an idea of the current state of the library.
|
||||
|
||||
The main advice for new contributors is to share your ideas with the community. Introduce yourself over our [Discord server] or [start a discussion in an issue](https://github.com/hecrj/iced/issues) explaining what you have in mind (do not be afraid of duplicated issues!). If you want to talk directly to me (@hecrj), you can also find me on Discord (`lone_scientist#9554`).
|
||||
The main advice for new contributors is to share your ideas with the community. Introduce yourself over our [Discord server] or [start a discussion in an issue](https://github.com/iced-rs/iced/issues) explaining what you have in mind (do not be afraid of duplicated issues!). If you want to talk directly to me (@hecrj), you can also find me on Discord (`lone_scientist#9554`).
|
||||
|
||||
This is a very important step. It helps to coordinate work, get on the same page, and start building trust. Please, do not skip it! Remember that [Code is the Easy Part] and also [The Hard Parts of Open Source]!
|
||||
|
||||
|
|
|
|||
25
Cargo.toml
25
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced"
|
||||
version = "0.3.0"
|
||||
version = "0.4.2"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A cross-platform GUI library inspired by Elm"
|
||||
|
|
@ -96,26 +96,27 @@ members = [
|
|||
"examples/pure/pane_grid",
|
||||
"examples/pure/pick_list",
|
||||
"examples/pure/todos",
|
||||
"examples/pure/tooltip",
|
||||
"examples/pure/tour",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
iced_core = { version = "0.4", path = "core" }
|
||||
iced_futures = { version = "0.3", path = "futures" }
|
||||
iced_native = { version = "0.4", path = "native" }
|
||||
iced_graphics = { version = "0.2", path = "graphics" }
|
||||
iced_winit = { version = "0.3", path = "winit" }
|
||||
iced_glutin = { version = "0.2", path = "glutin", optional = true }
|
||||
iced_glow = { version = "0.2", path = "glow", optional = true }
|
||||
iced_pure = { version = "0.1", path = "pure", optional = true }
|
||||
iced_core = { version = "0.5", path = "core" }
|
||||
iced_futures = { version = "0.4", path = "futures" }
|
||||
iced_native = { version = "0.5", path = "native" }
|
||||
iced_graphics = { version = "0.3", path = "graphics" }
|
||||
iced_winit = { version = "0.4", path = "winit" }
|
||||
iced_glutin = { version = "0.3", path = "glutin", optional = true }
|
||||
iced_glow = { version = "0.3", path = "glow", optional = true }
|
||||
iced_pure = { version = "0.2", path = "pure", optional = true }
|
||||
thiserror = "1.0"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
iced_wgpu = { version = "0.4", path = "wgpu", optional = true }
|
||||
iced_wgpu = { version = "0.5", path = "wgpu", optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
iced_wgpu = { version = "0.4", path = "wgpu", features = ["webgl"], optional = true }
|
||||
iced_wgpu = { version = "0.5", path = "wgpu", features = ["webgl"], optional = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
features = ["image", "svg", "canvas", "qr_code"]
|
||||
features = ["image", "svg", "canvas", "qr_code", "pure"]
|
||||
|
|
|
|||
34
README.md
34
README.md
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
<img src="docs/logo.svg" width="140px" />
|
||||
|
||||
# iced
|
||||
# Iced
|
||||
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](https://crates.io/crates/iced)
|
||||
[](https://github.com/hecrj/iced/actions)
|
||||
[](https://github.com/iced-rs/iced/actions)
|
||||
[](https://discord.gg/3xZJ65GAhd)
|
||||
|
||||
A cross-platform GUI library for Rust focused on simplicity and type-safety.
|
||||
|
|
@ -40,11 +40,11 @@ Inspired by [Elm].
|
|||
* A [windowing shell]
|
||||
* A [web runtime] leveraging the DOM
|
||||
|
||||
__iced is currently experimental software.__ [Take a look at the roadmap],
|
||||
__Iced is currently experimental software.__ [Take a look at the roadmap],
|
||||
[check out the issues], and [feel free to contribute!]
|
||||
|
||||
[Cross-platform support]: https://raw.githubusercontent.com/iced-rs/iced/master/docs/images/todos_desktop.jpg
|
||||
[the Web]: https://iced.rs/
|
||||
[the Web]: https://github.com/iced-rs/iced_web
|
||||
[text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
|
||||
[scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
|
||||
[Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
|
||||
|
|
@ -66,16 +66,16 @@ __iced is currently experimental software.__ [Take a look at the roadmap],
|
|||
Add `iced` as a dependency in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
iced = "0.3"
|
||||
iced = "0.4"
|
||||
```
|
||||
|
||||
__iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||
you want to learn about a specific release, check out [the release list].
|
||||
|
||||
[the release list]: https://github.com/iced-rs/iced/releases
|
||||
|
||||
## Overview
|
||||
Inspired by [The Elm Architecture], iced expects you to split user interfaces
|
||||
Inspired by [The Elm Architecture], Iced expects you to split user interfaces
|
||||
into four different concepts:
|
||||
|
||||
* __State__ — the state of your application
|
||||
|
|
@ -165,7 +165,7 @@ impl Counter {
|
|||
}
|
||||
```
|
||||
|
||||
And that's everything! We just wrote a whole user interface. iced is now able
|
||||
And that's everything! We just wrote a whole user interface. Iced is now able
|
||||
to:
|
||||
|
||||
1. Take the result of our __view logic__ and layout its widgets.
|
||||
|
|
@ -176,7 +176,7 @@ to:
|
|||
Browse the [documentation] and the [examples] to learn more!
|
||||
|
||||
## Implementation details
|
||||
iced was originally born as an attempt at bringing the simplicity of [Elm] and
|
||||
Iced was originally born as an attempt at bringing the simplicity of [Elm] and
|
||||
[The Elm Architecture] into [Coffee], a 2D game engine I am working on.
|
||||
|
||||
The core of the library was implemented during May 2019 in [this pull request].
|
||||
|
|
@ -189,7 +189,7 @@ end-user-oriented GUI library, while keeping [the ecosystem] modular:
|
|||
|
||||
<p align="center">
|
||||
<a href="ECOSYSTEM.md">
|
||||
<img alt="iced ecosystem" src="docs/graphs/ecosystem.png" width="80%">
|
||||
<img alt="The Iced Ecosystem" src="docs/graphs/ecosystem.png" width="80%">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
|
@ -215,14 +215,14 @@ $ cargo run --features iced/glow --package game_of_life
|
|||
|
||||
and then use it in your project with
|
||||
```toml
|
||||
iced = { version = "0.3", default-features = false, features = ["glow"] }
|
||||
iced = { version = "0.4", default-features = false, features = ["glow"] }
|
||||
```
|
||||
|
||||
**NOTE:** Chances are you have hardware that supports at least OpenGL 2.1 or OpenGL ES 2.0,
|
||||
but if you don't, right now there's no software fallback, so it means your hardware
|
||||
doesn't support Iced.
|
||||
|
||||
[built-in renderer]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md#Renderers
|
||||
[built-in renderer]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md#Renderers
|
||||
|
||||
## Contributing / Feedback
|
||||
Contributions are greatly appreciated! If you want to contribute, please
|
||||
|
|
@ -234,15 +234,15 @@ awesome folks) over the `#games-and-graphics` and `#gui-and-ui` channels in
|
|||
the [Rust Community Discord]. I go by `lone_scientist#9554` there.
|
||||
|
||||
## Sponsors
|
||||
The development of iced is sponsored by the [Cryptowatch] team at [Kraken.com]
|
||||
The development of Iced is sponsored by the [Cryptowatch] team at [Kraken.com]
|
||||
|
||||
[documentation]: https://docs.rs/iced/
|
||||
[examples]: https://github.com/hecrj/iced/tree/master/examples
|
||||
[examples]: https://github.com/iced-rs/iced/tree/master/examples
|
||||
[Coffee]: https://github.com/hecrj/coffee
|
||||
[Elm]: https://elm-lang.org/
|
||||
[The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
[the current issues]: https://github.com/hecrj/iced/issues
|
||||
[contributing guidelines]: https://github.com/hecrj/iced/blob/master/CONTRIBUTING.md
|
||||
[the current issues]: https://github.com/iced-rs/iced/issues
|
||||
[contributing guidelines]: https://github.com/iced-rs/iced/blob/master/CONTRIBUTING.md
|
||||
[Discord server]: https://discord.gg/3xZJ65GAhd
|
||||
[Rust Community Discord]: https://bit.ly/rust-community
|
||||
[Cryptowatch]: https://cryptowat.ch/charts
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_core"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "The essential concepts of Iced"
|
||||
|
|
|
|||
|
|
@ -41,21 +41,29 @@ impl Modifiers {
|
|||
};
|
||||
|
||||
/// Returns true if the [`SHIFT`] key is pressed in the [`Modifiers`].
|
||||
///
|
||||
/// [`SHIFT`]: Self::SHIFT
|
||||
pub fn shift(self) -> bool {
|
||||
self.contains(Self::SHIFT)
|
||||
}
|
||||
|
||||
/// Returns true if the [`CTRL`] key is pressed in the [`Modifiers`].
|
||||
///
|
||||
/// [`CTRL`]: Self::CTRL
|
||||
pub fn control(self) -> bool {
|
||||
self.contains(Self::CTRL)
|
||||
}
|
||||
|
||||
/// Returns true if the [`ALT`] key is pressed in the [`Modifiers`].
|
||||
///
|
||||
/// [`ALT`]: Self::ALT
|
||||
pub fn alt(self) -> bool {
|
||||
self.contains(Self::ALT)
|
||||
}
|
||||
|
||||
/// Returns true if the [`LOGO`] key is pressed in the [`Modifiers`].
|
||||
///
|
||||
/// [`LOGO`]: Self::LOGO
|
||||
pub fn logo(self) -> bool {
|
||||
self.contains(Self::LOGO)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@
|
|||
//! 
|
||||
//!
|
||||
//! [Iced]: https://github.com/iced-rs/iced
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/master/native
|
||||
//! [`iced_web`]: https://github.com/iced-rs/iced/tree/master/web
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
//! [`iced_web`]: https://github.com/iced-rs/iced_web
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![deny(unused_results)]
|
||||
|
|
|
|||
9
examples/pure/tooltip/Cargo.toml
Normal file
9
examples/pure/tooltip/Cargo.toml
Normal 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"] }
|
||||
93
examples/pure/tooltip/src/main.rs
Normal file
93
examples/pure/tooltip/src/main.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_futures"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "Commands, subscriptions, and runtimes for Iced"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl<T> Command<T> {
|
|||
Self(Internal::None)
|
||||
}
|
||||
|
||||
/// Creates a [`Command`] that performs a single [`Action`].
|
||||
/// Creates a [`Command`] that performs a single action.
|
||||
pub const fn single(action: T) -> Self {
|
||||
Self(Internal::Single(action))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ use std::marker::PhantomData;
|
|||
///
|
||||
/// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any
|
||||
/// [`Command`] or [`Subscription`] and get notified of the results!
|
||||
///
|
||||
/// [`Command`]: crate::Command
|
||||
#[derive(Debug)]
|
||||
pub struct Runtime<Hasher, Event, Executor, Sender, Message> {
|
||||
executor: Executor,
|
||||
|
|
@ -51,10 +53,12 @@ where
|
|||
self.executor.enter(f)
|
||||
}
|
||||
|
||||
/// Spawns a [`Command`] in the [`Runtime`].
|
||||
/// Spawns a [`Future`] in the [`Runtime`].
|
||||
///
|
||||
/// The resulting `Message` will be forwarded to the `Sender` of the
|
||||
/// [`Runtime`].
|
||||
///
|
||||
/// [`Future`]: BoxFuture
|
||||
pub fn spawn(&mut self, future: BoxFuture<Message>) {
|
||||
use futures::{FutureExt, SinkExt};
|
||||
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ impl<I, O, H> std::fmt::Debug for Subscription<I, O, H> {
|
|||
/// - [`stopwatch`], a watch with start/stop and reset buttons showcasing how
|
||||
/// to listen to time.
|
||||
///
|
||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.3/examples
|
||||
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.3/examples/download_progress
|
||||
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.3/examples/stopwatch
|
||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.4/examples/download_progress
|
||||
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.4/examples/stopwatch
|
||||
pub trait Recipe<Hasher: std::hash::Hasher, Event> {
|
||||
/// The events that will be produced by a [`Subscription`] with this
|
||||
/// [`Recipe`].
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "iced_glow"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A glow renderer for iced"
|
||||
license = "MIT AND OFL-1.1"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
repository = "https://github.com/iced-rs/iced"
|
||||
|
||||
[features]
|
||||
canvas = ["iced_graphics/canvas"]
|
||||
|
|
@ -24,11 +24,11 @@ bytemuck = "1.4"
|
|||
log = "0.4"
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_graphics]
|
||||
version = "0.2"
|
||||
version = "0.3"
|
||||
path = "../graphics"
|
||||
features = ["font-fallback", "font-icons", "opengl"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# `iced_glow`
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced_glow)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](https://discord.gg/3xZJ65GAhd)
|
||||
|
||||
`iced_glow` is a [`glow`] renderer for [`iced_native`]. This renderer supports OpenGL 3.0+ and OpenGL ES 2.0.
|
||||
|
||||
This is renderer is mostly used as a fallback for hardware that doesn't support [`wgpu`] (Vulkan, Metal or DX12).
|
||||
This renderer is mostly used as a fallback for hardware that doesn't support [`wgpu`] (Vulkan, Metal or DX12).
|
||||
|
||||
Currently, `iced_glow` supports the following primitives:
|
||||
- Text, which is rendered using [`glow_glyph`]. No shaping at all.
|
||||
|
|
@ -34,7 +34,7 @@ iced_glow = "0.2"
|
|||
__Iced moves fast and the `master` branch can contain breaking changes!__ If
|
||||
you want to learn about a specific release, check out [the release list].
|
||||
|
||||
[the release list]: https://github.com/hecrj/iced/releases
|
||||
[the release list]: https://github.com/iced-rs/iced/releases
|
||||
|
||||
## Current limitations
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use iced_native::{Font, Size};
|
|||
/// A [`glow`] graphics backend for [`iced`].
|
||||
///
|
||||
/// [`glow`]: https://github.com/grovesNL/glow
|
||||
/// [`iced`]: https://github.com/hecrj/iced
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
#[derive(Debug)]
|
||||
pub struct Backend {
|
||||
quad_pipeline: quad::Pipeline,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! A [`glow`] renderer for [`iced_native`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! [`glow`]: https://github.com/grovesNL/glow
|
||||
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
|
|
@ -37,5 +37,5 @@ pub use iced_native::{Alignment, Background, Color, Command, Length, Vector};
|
|||
/// A [`glow`] graphics renderer for [`iced`].
|
||||
///
|
||||
/// [`glow`]: https://github.com/grovesNL/glow
|
||||
/// [`iced`]: https://github.com/hecrj/iced
|
||||
/// [`iced`]: https://github.com/iced-rs/iced
|
||||
pub type Renderer = iced_graphics::Renderer<Backend>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_glutin"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A glutin runtime for Iced"
|
||||
|
|
@ -23,14 +23,14 @@ git = "https://github.com/iced-rs/glutin"
|
|||
rev = "7a0ee02782eb2bf059095e0c953c4bb53f1eef0e"
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_winit]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
path = "../winit"
|
||||
|
||||
[dependencies.iced_graphics]
|
||||
version = "0.2"
|
||||
version = "0.3"
|
||||
path = "../graphics"
|
||||
features = ["opengl"]
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "iced_graphics"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
repository = "https://github.com/iced-rs/iced"
|
||||
documentation = "https://docs.rs/iced_graphics"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
|
@ -29,15 +29,15 @@ version = "1.4"
|
|||
features = ["derive"]
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_style]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
path = "../style"
|
||||
|
||||
[dependencies.iced_pure]
|
||||
version = "0.1"
|
||||
version = "0.2"
|
||||
path = "../pure"
|
||||
optional = true
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! A bunch of backend-agnostic types that can be leveraged to build a renderer
|
||||
//! for [`iced`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! [`iced`]: https://github.com/hecrj/iced
|
||||
//! [`iced`]: https://github.com/iced-rs/iced
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ use std::marker::PhantomData;
|
|||
/// - [`solar_system`], an animated solar system drawn using the [`Canvas`] widget
|
||||
/// and showcasing how to compose different transforms.
|
||||
///
|
||||
/// [examples]: https://github.com/hecrj/iced/tree/master/examples
|
||||
/// [`clock`]: https://github.com/hecrj/iced/tree/master/examples/clock
|
||||
/// [`game_of_life`]: https://github.com/hecrj/iced/tree/master/examples/game_of_life
|
||||
/// [`solar_system`]: https://github.com/hecrj/iced/tree/master/examples/solar_system
|
||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.4/examples/clock
|
||||
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.4/examples/game_of_life
|
||||
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.4/examples/solar_system
|
||||
///
|
||||
/// ## Drawing a simple circle
|
||||
/// If you want to get a quick overview, here's how we can draw a simple circle:
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ use crate::Rectangle;
|
|||
///
|
||||
/// [`Canvas`]: crate::widget::Canvas
|
||||
pub trait Program<Message> {
|
||||
/// The internal [`State`] mutated by the [`Program`].
|
||||
/// The internal state mutated by the [`Program`].
|
||||
type State: Default + 'static;
|
||||
|
||||
/// Updates the state of the [`Program`].
|
||||
/// Updates the [`State`](Self::State) of the [`Program`].
|
||||
///
|
||||
/// When a [`Program`] is used in a [`Canvas`], the runtime will call this
|
||||
/// method for each [`Event`].
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ pub trait Compositor: Sized {
|
|||
|
||||
/// Presents the [`Renderer`] primitives to the next frame of the given [`Surface`].
|
||||
///
|
||||
/// [`SwapChain`]: Self::SwapChain
|
||||
/// [`Renderer`]: Self::Renderer
|
||||
/// [`Surface`]: Self::Surface
|
||||
fn present<T: AsRef<str>>(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
|
|
@ -56,7 +57,7 @@ pub trait Compositor: Sized {
|
|||
) -> Result<(), SurfaceError>;
|
||||
}
|
||||
|
||||
/// Result of an unsuccessful call to [`Compositor::draw`].
|
||||
/// Result of an unsuccessful call to [`Compositor::present`].
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Error)]
|
||||
pub enum SurfaceError {
|
||||
/// A timeout was encountered while trying to acquire the next frame.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
[package]
|
||||
name = "iced_lazy"
|
||||
version = "0.1.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "Lazy widgets for Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/iced-rs/iced"
|
||||
documentation = "https://docs.rs/iced_lazy"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
||||
[features]
|
||||
pure = ["iced_pure"]
|
||||
|
|
@ -10,10 +17,10 @@ pure = ["iced_pure"]
|
|||
ouroboros = "0.13"
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_pure]
|
||||
version = "0.1"
|
||||
version = "0.2"
|
||||
path = "../pure"
|
||||
optional = true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
pub mod component;
|
||||
pub mod responsive;
|
||||
|
||||
#[cfg(feature = "pure")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "pure")))]
|
||||
pub mod pure;
|
||||
|
||||
pub use component::Component;
|
||||
|
|
|
|||
|
|
@ -67,12 +67,13 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer> {
|
|||
|
||||
self.element = view(new_size);
|
||||
self.size = new_size;
|
||||
|
||||
tree.diff(&self.element);
|
||||
|
||||
self.layout = self
|
||||
.element
|
||||
.as_widget()
|
||||
.layout(renderer, &layout::Limits::new(Size::ZERO, self.size));
|
||||
|
||||
tree.diff(&self.element);
|
||||
}
|
||||
|
||||
fn resolve<R, T>(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_native"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A renderer-agnostic library for native GUIs"
|
||||
|
|
@ -16,14 +16,14 @@ unicode-segmentation = "1.6"
|
|||
num-traits = "0.2"
|
||||
|
||||
[dependencies.iced_core]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../core"
|
||||
|
||||
[dependencies.iced_futures]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
path = "../futures"
|
||||
features = ["thread-pool"]
|
||||
|
||||
[dependencies.iced_style]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
path = "../style"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use std::fmt;
|
|||
/// [`Command`]: crate::Command
|
||||
pub enum Action<T> {
|
||||
/// Run a [`Future`] to completion.
|
||||
///
|
||||
/// [`Future`]: iced_futures::BoxFuture
|
||||
Future(iced_futures::BoxFuture<T>),
|
||||
|
||||
/// Run a clipboard action.
|
||||
|
|
@ -25,6 +27,8 @@ pub enum Action<T> {
|
|||
|
||||
impl<T> Action<T> {
|
||||
/// Applies a transformation to the result of a [`Command`].
|
||||
///
|
||||
/// [`Command`]: crate::Command
|
||||
pub fn map<A>(
|
||||
self,
|
||||
f: impl Fn(T) -> A + 'static + MaybeSend + Sync,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher as _};
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// An [`Image`] handle.
|
||||
/// A handle of some image data.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Handle {
|
||||
id: u64,
|
||||
|
|
@ -79,7 +79,7 @@ impl Hash for Handle {
|
|||
}
|
||||
}
|
||||
|
||||
/// The data of an [`Image`].
|
||||
/// The data of a raster image.
|
||||
#[derive(Clone, Hash)]
|
||||
pub enum Data {
|
||||
/// File data
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
//! - Build a new renderer, see the [renderer] module.
|
||||
//! - Build a custom widget, start at the [`Widget`] trait.
|
||||
//!
|
||||
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/master/core
|
||||
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/master/winit
|
||||
//! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.4/core
|
||||
//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.4/winit
|
||||
//! [`druid`]: https://github.com/xi-editor/druid
|
||||
//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle
|
||||
//! [renderer]: crate::renderer
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ where
|
|||
event::Status::Ignored
|
||||
}
|
||||
|
||||
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
|
||||
/// Returns the current [`mouse::Interaction`] of the [`Overlay`].
|
||||
///
|
||||
/// By default, it returns [`mouse::Interaction::Idle`].
|
||||
fn mouse_interaction(
|
||||
|
|
|
|||
|
|
@ -1,24 +1,4 @@
|
|||
//! Write your own renderer.
|
||||
//!
|
||||
//! You will need to implement the `Renderer` trait first. It simply contains
|
||||
//! an `Output` associated type.
|
||||
//!
|
||||
//! There is no common trait to draw all the widgets. Instead, every [`Widget`]
|
||||
//! constrains its generic `Renderer` type as necessary.
|
||||
//!
|
||||
//! This approach is flexible and composable. For instance, the
|
||||
//! [`Text`] widget only needs a [`text::Renderer`] while a [`Checkbox`] widget
|
||||
//! needs both a [`text::Renderer`] and a [`checkbox::Renderer`], reusing logic.
|
||||
//!
|
||||
//! In the end, a __renderer__ satisfying all the constraints is
|
||||
//! needed to build a [`UserInterface`].
|
||||
//!
|
||||
//! [`Widget`]: crate::Widget
|
||||
//! [`UserInterface`]: crate::UserInterface
|
||||
//! [`Text`]: crate::widget::Text
|
||||
//! [`text::Renderer`]: crate::widget::text::Renderer
|
||||
//! [`Checkbox`]: crate::widget::Checkbox
|
||||
//! [`checkbox::Renderer`]: crate::widget::checkbox::Renderer
|
||||
#[cfg(debug_assertions)]
|
||||
mod null;
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
@ -27,8 +7,7 @@ pub use null::Null;
|
|||
use crate::layout;
|
||||
use crate::{Background, Color, Element, Rectangle, Vector};
|
||||
|
||||
/// A component that can take the state of a user interface and produce an
|
||||
/// output for its users.
|
||||
/// A component that can be used by widgets to draw themselves on a screen.
|
||||
pub trait Renderer: Sized {
|
||||
/// Lays out the elements of a user interface.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::hash::{Hash, Hasher as _};
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// An [`Svg`] handle.
|
||||
/// A handle of Svg data.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Handle {
|
||||
id: u64,
|
||||
|
|
@ -55,7 +55,7 @@ impl Hash for Handle {
|
|||
}
|
||||
}
|
||||
|
||||
/// The data of an [`Svg`].
|
||||
/// The data of a vectorial image.
|
||||
#[derive(Clone, Hash)]
|
||||
pub enum Data {
|
||||
/// File data
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub enum Hit {
|
|||
}
|
||||
|
||||
impl Hit {
|
||||
/// Computes the cursor position corresponding to this [`HitTestResult`] .
|
||||
/// Computes the cursor position of the [`Hit`] .
|
||||
pub fn cursor(self) -> usize {
|
||||
match self {
|
||||
Self::CharOffset(i) => i,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::{Clipboard, Element, Layout, Point, Rectangle, Shell, Size};
|
|||
/// The [`integration` example] uses a [`UserInterface`] to integrate Iced in
|
||||
/// an existing graphical application.
|
||||
///
|
||||
/// [`integration` example]: https://github.com/iced-rs/iced/tree/0.3/examples/integration
|
||||
/// [`integration` example]: https://github.com/iced-rs/iced/tree/0.4/examples/integration
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct UserInterface<'a, Message, Renderer> {
|
||||
root: Element<'a, Message, Renderer>,
|
||||
|
|
@ -264,11 +264,10 @@ where
|
|||
|
||||
/// Draws the [`UserInterface`] with the provided [`Renderer`].
|
||||
///
|
||||
/// It returns the some [`Renderer::Output`]. You should update the icon of
|
||||
/// the mouse cursor accordingly in your system.
|
||||
/// It returns the current [`mouse::Interaction`]. You should update the
|
||||
/// icon of the mouse cursor accordingly in your system.
|
||||
///
|
||||
/// [`Renderer`]: crate::Renderer
|
||||
/// [`Renderer::Output`]: crate::Renderer::Output
|
||||
///
|
||||
/// # Example
|
||||
/// We can finally draw our [counter](index.html#usage) by
|
||||
|
|
|
|||
|
|
@ -93,12 +93,12 @@ use crate::{Clipboard, Layout, Length, Point, Rectangle, Shell};
|
|||
/// - [`geometry`], a custom widget showcasing how to draw geometry with the
|
||||
/// `Mesh2D` primitive in [`iced_wgpu`].
|
||||
///
|
||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.3/examples
|
||||
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.3/examples/bezier_tool
|
||||
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.3/examples/custom_widget
|
||||
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.3/examples/geometry
|
||||
/// [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.4/examples/bezier_tool
|
||||
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.4/examples/custom_widget
|
||||
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.4/examples/geometry
|
||||
/// [`lyon`]: https://github.com/nical/lyon
|
||||
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.3/wgpu
|
||||
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/wgpu
|
||||
pub trait Widget<Message, Renderer>
|
||||
where
|
||||
Renderer: crate::Renderer,
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> {
|
|||
|
||||
/// Sets the [`Font`] of the text of the [`Checkbox`].
|
||||
///
|
||||
/// [`Font`]: crate::widget::text::Renderer::Font
|
||||
/// [`Font`]: crate::text::Renderer::Font
|
||||
pub fn font(mut self, font: Renderer::Font) -> Self {
|
||||
self.font = font;
|
||||
self
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
|
|||
|
||||
/// Sets the vertical spacing _between_ elements.
|
||||
///
|
||||
/// Custom margins per element do not exist in Iced. You should use this
|
||||
/// Custom margins per element do not exist in iced. You should use this
|
||||
/// method instead! While less flexible, it helps you keep spacing between
|
||||
/// elements consistent.
|
||||
pub fn spacing(mut self, units: u16) -> Self {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||
//! drag and drop, and hotkey support.
|
||||
//!
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
|
||||
mod axis;
|
||||
mod configuration;
|
||||
mod content;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::widget::pane_grid::Axis;
|
|||
|
||||
/// The arrangement of a [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::pane_grid::PaneGrid
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Configuration<T> {
|
||||
/// A split of the available space.
|
||||
|
|
@ -21,6 +21,6 @@ pub enum Configuration<T> {
|
|||
},
|
||||
/// A [`Pane`].
|
||||
///
|
||||
/// [`Pane`]: crate::pane_grid::Pane
|
||||
/// [`Pane`]: crate::widget::pane_grid::Pane
|
||||
Pane(T),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ where
|
|||
{
|
||||
/// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].
|
||||
///
|
||||
/// [`Renderer`]: crate::widget::pane_grid::Renderer
|
||||
/// [`Renderer`]: crate::Renderer
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
//! The state of a [`PaneGrid`].
|
||||
//!
|
||||
//! [`PaneGrid`]: crate::widget::PaneGrid
|
||||
use crate::widget::pane_grid::{
|
||||
Axis, Configuration, Direction, Node, Pane, Split,
|
||||
};
|
||||
|
|
@ -21,9 +23,13 @@ use std::collections::{BTreeMap, HashMap};
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct State<T> {
|
||||
/// The panes of the [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub panes: HashMap<Pane, T>,
|
||||
|
||||
/// The internal state of the [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub internal: Internal,
|
||||
|
||||
pub(super) action: Action,
|
||||
|
|
@ -198,6 +204,8 @@ impl<T> State<T> {
|
|||
}
|
||||
|
||||
/// The internal state of a [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Internal {
|
||||
layout: Node,
|
||||
|
|
@ -207,6 +215,8 @@ pub struct Internal {
|
|||
impl Internal {
|
||||
/// Initializes the [`Internal`] state of a [`PaneGrid`] from a
|
||||
/// [`Configuration`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub fn from_configuration<T>(
|
||||
panes: &mut HashMap<Pane, T>,
|
||||
content: Configuration<T>,
|
||||
|
|
@ -248,11 +258,17 @@ impl Internal {
|
|||
}
|
||||
|
||||
/// The current action of a [`PaneGrid`].
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Action {
|
||||
/// The [`PaneGrid`] is idle.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
Idle,
|
||||
/// A [`Pane`] in the [`PaneGrid`] is being dragged.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
Dragging {
|
||||
/// The [`Pane`] being dragged.
|
||||
pane: Pane,
|
||||
|
|
@ -260,6 +276,8 @@ pub enum Action {
|
|||
origin: Point,
|
||||
},
|
||||
/// A [`Split`] in the [`PaneGrid`] is being dragged.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
Resizing {
|
||||
/// The [`Split`] being dragged.
|
||||
split: Split,
|
||||
|
|
@ -288,6 +306,8 @@ impl Action {
|
|||
|
||||
impl Internal {
|
||||
/// Calculates the current [`Pane`] regions from the [`PaneGrid`] layout.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub fn pane_regions(
|
||||
&self,
|
||||
spacing: f32,
|
||||
|
|
@ -297,6 +317,8 @@ impl Internal {
|
|||
}
|
||||
|
||||
/// Calculates the current [`Split`] regions from the [`PaneGrid`] layout.
|
||||
///
|
||||
/// [`PaneGrid`]: crate::widget::PaneGrid
|
||||
pub fn split_regions(
|
||||
&self,
|
||||
spacing: f32,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ where
|
|||
{
|
||||
/// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].
|
||||
///
|
||||
/// [`Renderer`]: crate::widget::pane_grid::Renderer
|
||||
/// [`Renderer`]: crate::Renderer
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
|
|
|
|||
|
|
@ -402,21 +402,24 @@ pub fn draw<T, Renderer>(
|
|||
if let Some(label) =
|
||||
label.as_ref().map(String::as_str).or_else(|| placeholder)
|
||||
{
|
||||
let text_size = f32::from(text_size.unwrap_or(renderer.default_size()));
|
||||
|
||||
renderer.fill_text(Text {
|
||||
content: label,
|
||||
size: f32::from(text_size.unwrap_or(renderer.default_size())),
|
||||
size: text_size,
|
||||
font: font.clone(),
|
||||
color: is_selected
|
||||
.then(|| style.text_color)
|
||||
.unwrap_or(style.placeholder_color),
|
||||
bounds: Rectangle {
|
||||
x: bounds.x + f32::from(padding.left),
|
||||
y: bounds.center_y(),
|
||||
..bounds
|
||||
y: bounds.center_y() - text_size / 2.0,
|
||||
width: bounds.width - f32::from(padding.horizontal()),
|
||||
height: text_size,
|
||||
},
|
||||
horizontal_alignment: alignment::Horizontal::Left,
|
||||
vertical_alignment: alignment::Vertical::Center,
|
||||
})
|
||||
vertical_alignment: alignment::Vertical::Top,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
|
|||
|
||||
/// Sets the horizontal spacing _between_ elements.
|
||||
///
|
||||
/// Custom margins per element do not exist in Iced. You should use this
|
||||
/// Custom margins per element do not exist in iced. You should use this
|
||||
/// method instead! While less flexible, it helps you keep spacing between
|
||||
/// elements consistent.
|
||||
pub fn spacing(mut self, units: u16) -> Self {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
|
|||
|
||||
/// Sets the [`Font`] of the [`Text`].
|
||||
///
|
||||
/// [`Font`]: Renderer::Font
|
||||
/// [`Font`]: crate::text::Renderer::Font
|
||||
pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
|
||||
self.font = font.into();
|
||||
self
|
||||
|
|
@ -77,7 +77,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`HorizontalAlignment`] of the [`Text`].
|
||||
/// Sets the [`alignment::Horizontal`] of the [`Text`].
|
||||
pub fn horizontal_alignment(
|
||||
mut self,
|
||||
alignment: alignment::Horizontal,
|
||||
|
|
@ -86,7 +86,7 @@ impl<Renderer: text::Renderer> Text<Renderer> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`VerticalAlignment`] of the [`Text`].
|
||||
/// Sets the [`alignment::Vertical`] of the [`Text`].
|
||||
pub fn vertical_alignment(
|
||||
mut self,
|
||||
alignment: alignment::Vertical,
|
||||
|
|
|
|||
|
|
@ -108,10 +108,9 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Font`] of the [`Text`].
|
||||
/// Sets the [`Font`] of the [`TextInput`].
|
||||
///
|
||||
/// [`Font`]: crate::widget::text::Renderer::Font
|
||||
/// [`Text`]: crate::widget::Text
|
||||
/// [`Font`]: crate::text::Renderer::Font
|
||||
pub fn font(mut self, font: Renderer::Font) -> Self {
|
||||
self.font = font;
|
||||
self
|
||||
|
|
@ -157,6 +156,8 @@ where
|
|||
|
||||
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
|
||||
/// [`Value`] if provided.
|
||||
///
|
||||
/// [`Renderer`]: text::Renderer
|
||||
pub fn draw(
|
||||
&self,
|
||||
renderer: &mut Renderer,
|
||||
|
|
@ -570,6 +571,8 @@ where
|
|||
|
||||
/// Draws the [`TextInput`] with the given [`Renderer`], overriding its
|
||||
/// [`Value`] if provided.
|
||||
///
|
||||
/// [`Renderer`]: text::Renderer
|
||||
pub fn draw<Renderer>(
|
||||
renderer: &mut Renderer,
|
||||
layout: Layout<'_>,
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ impl<'a, Message, Renderer: text::Renderer> Toggler<'a, Message, Renderer> {
|
|||
}
|
||||
|
||||
/// Sets the [`Font`] of the text of the [`Toggler`]
|
||||
///
|
||||
/// [`Font`]: crate::text::Renderer::Font
|
||||
pub fn font(mut self, font: Renderer::Font) -> Self {
|
||||
self.font = font;
|
||||
self
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ where
|
|||
/// The default padding of a [`Tooltip`] drawn by this renderer.
|
||||
const DEFAULT_PADDING: u16 = 5;
|
||||
|
||||
/// Creates an empty [`Tooltip`].
|
||||
/// Creates a new [`Tooltip`].
|
||||
///
|
||||
/// [`Tooltip`]: struct.Tooltip.html
|
||||
pub fn new(
|
||||
|
|
@ -98,6 +98,117 @@ pub enum Position {
|
|||
Right,
|
||||
}
|
||||
|
||||
/// Draws a [`Tooltip`].
|
||||
pub fn draw<Renderer: crate::Renderer>(
|
||||
renderer: &mut Renderer,
|
||||
inherited_style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
viewport: &Rectangle,
|
||||
position: Position,
|
||||
gap: u16,
|
||||
padding: u16,
|
||||
style_sheet: &dyn container::StyleSheet,
|
||||
layout_text: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
|
||||
draw_text: impl FnOnce(
|
||||
&mut Renderer,
|
||||
&renderer::Style,
|
||||
Layout<'_>,
|
||||
Point,
|
||||
&Rectangle,
|
||||
),
|
||||
) {
|
||||
let bounds = layout.bounds();
|
||||
|
||||
if bounds.contains(cursor_position) {
|
||||
let gap = f32::from(gap);
|
||||
let style = style_sheet.style();
|
||||
|
||||
let defaults = renderer::Style {
|
||||
text_color: style.text_color.unwrap_or(inherited_style.text_color),
|
||||
};
|
||||
|
||||
let text_layout = layout_text(
|
||||
renderer,
|
||||
&layout::Limits::new(Size::ZERO, viewport.size())
|
||||
.pad(Padding::new(padding)),
|
||||
);
|
||||
|
||||
let padding = f32::from(padding);
|
||||
let text_bounds = text_layout.bounds();
|
||||
let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
|
||||
let y_center = bounds.y + (bounds.height - text_bounds.height) / 2.0;
|
||||
|
||||
let mut tooltip_bounds = {
|
||||
let offset = match position {
|
||||
Position::Top => Vector::new(
|
||||
x_center,
|
||||
bounds.y - text_bounds.height - gap - padding,
|
||||
),
|
||||
Position::Bottom => Vector::new(
|
||||
x_center,
|
||||
bounds.y + bounds.height + gap + padding,
|
||||
),
|
||||
Position::Left => Vector::new(
|
||||
bounds.x - text_bounds.width - gap - padding,
|
||||
y_center,
|
||||
),
|
||||
Position::Right => Vector::new(
|
||||
bounds.x + bounds.width + gap + padding,
|
||||
y_center,
|
||||
),
|
||||
Position::FollowCursor => Vector::new(
|
||||
cursor_position.x,
|
||||
cursor_position.y - text_bounds.height,
|
||||
),
|
||||
};
|
||||
|
||||
Rectangle {
|
||||
x: offset.x - padding,
|
||||
y: offset.y - padding,
|
||||
width: text_bounds.width + padding * 2.0,
|
||||
height: text_bounds.height + padding * 2.0,
|
||||
}
|
||||
};
|
||||
|
||||
if tooltip_bounds.x < viewport.x {
|
||||
tooltip_bounds.x = viewport.x;
|
||||
} else if viewport.x + viewport.width
|
||||
< tooltip_bounds.x + tooltip_bounds.width
|
||||
{
|
||||
tooltip_bounds.x =
|
||||
viewport.x + viewport.width - tooltip_bounds.width;
|
||||
}
|
||||
|
||||
if tooltip_bounds.y < viewport.y {
|
||||
tooltip_bounds.y = viewport.y;
|
||||
} else if viewport.y + viewport.height
|
||||
< tooltip_bounds.y + tooltip_bounds.height
|
||||
{
|
||||
tooltip_bounds.y =
|
||||
viewport.y + viewport.height - tooltip_bounds.height;
|
||||
}
|
||||
|
||||
renderer.with_layer(*viewport, |renderer| {
|
||||
container::draw_background(renderer, &style, tooltip_bounds);
|
||||
|
||||
draw_text(
|
||||
renderer,
|
||||
&defaults,
|
||||
Layout::with_offset(
|
||||
Vector::new(
|
||||
tooltip_bounds.x + padding,
|
||||
tooltip_bounds.y + padding,
|
||||
),
|
||||
&text_layout,
|
||||
),
|
||||
cursor_position,
|
||||
viewport,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Widget<Message, Renderer>
|
||||
for Tooltip<'a, Message, Renderer>
|
||||
where
|
||||
|
|
@ -169,100 +280,32 @@ where
|
|||
viewport,
|
||||
);
|
||||
|
||||
let bounds = layout.bounds();
|
||||
|
||||
if bounds.contains(cursor_position) {
|
||||
let gap = f32::from(self.gap);
|
||||
let style = self.style_sheet.style();
|
||||
|
||||
let defaults = renderer::Style {
|
||||
text_color: style
|
||||
.text_color
|
||||
.unwrap_or(inherited_style.text_color),
|
||||
};
|
||||
|
||||
let text_layout = Widget::<(), Renderer>::layout(
|
||||
&self.tooltip,
|
||||
renderer,
|
||||
&layout::Limits::new(Size::ZERO, viewport.size())
|
||||
.pad(Padding::new(self.padding)),
|
||||
);
|
||||
|
||||
let padding = f32::from(self.padding);
|
||||
let text_bounds = text_layout.bounds();
|
||||
let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0;
|
||||
let y_center =
|
||||
bounds.y + (bounds.height - text_bounds.height) / 2.0;
|
||||
|
||||
let mut tooltip_bounds = {
|
||||
let offset = match self.position {
|
||||
Position::Top => Vector::new(
|
||||
x_center,
|
||||
bounds.y - text_bounds.height - gap - padding,
|
||||
),
|
||||
Position::Bottom => Vector::new(
|
||||
x_center,
|
||||
bounds.y + bounds.height + gap + padding,
|
||||
),
|
||||
Position::Left => Vector::new(
|
||||
bounds.x - text_bounds.width - gap - padding,
|
||||
y_center,
|
||||
),
|
||||
Position::Right => Vector::new(
|
||||
bounds.x + bounds.width + gap + padding,
|
||||
y_center,
|
||||
),
|
||||
Position::FollowCursor => Vector::new(
|
||||
cursor_position.x,
|
||||
cursor_position.y - text_bounds.height,
|
||||
),
|
||||
};
|
||||
|
||||
Rectangle {
|
||||
x: offset.x - padding,
|
||||
y: offset.y - padding,
|
||||
width: text_bounds.width + padding * 2.0,
|
||||
height: text_bounds.height + padding * 2.0,
|
||||
}
|
||||
};
|
||||
|
||||
if tooltip_bounds.x < viewport.x {
|
||||
tooltip_bounds.x = viewport.x;
|
||||
} else if viewport.x + viewport.width
|
||||
< tooltip_bounds.x + tooltip_bounds.width
|
||||
{
|
||||
tooltip_bounds.x =
|
||||
viewport.x + viewport.width - tooltip_bounds.width;
|
||||
}
|
||||
|
||||
if tooltip_bounds.y < viewport.y {
|
||||
tooltip_bounds.y = viewport.y;
|
||||
} else if viewport.y + viewport.height
|
||||
< tooltip_bounds.y + tooltip_bounds.height
|
||||
{
|
||||
tooltip_bounds.y =
|
||||
viewport.y + viewport.height - tooltip_bounds.height;
|
||||
}
|
||||
|
||||
renderer.with_layer(*viewport, |renderer| {
|
||||
container::draw_background(renderer, &style, tooltip_bounds);
|
||||
let tooltip = &self.tooltip;
|
||||
|
||||
draw(
|
||||
renderer,
|
||||
inherited_style,
|
||||
layout,
|
||||
cursor_position,
|
||||
viewport,
|
||||
self.position,
|
||||
self.gap,
|
||||
self.padding,
|
||||
self.style_sheet.as_ref(),
|
||||
|renderer, limits| {
|
||||
Widget::<(), Renderer>::layout(tooltip, renderer, limits)
|
||||
},
|
||||
|renderer, defaults, layout, cursor_position, viewport| {
|
||||
Widget::<(), Renderer>::draw(
|
||||
&self.tooltip,
|
||||
tooltip,
|
||||
renderer,
|
||||
&defaults,
|
||||
Layout::with_offset(
|
||||
Vector::new(
|
||||
tooltip_bounds.x + padding,
|
||||
tooltip_bounds.y + padding,
|
||||
),
|
||||
&text_layout,
|
||||
),
|
||||
defaults,
|
||||
layout,
|
||||
cursor_position,
|
||||
viewport,
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,8 +316,8 @@ where
|
|||
Message: 'a,
|
||||
{
|
||||
fn from(
|
||||
column: Tooltip<'a, Message, Renderer>,
|
||||
tooltip: Tooltip<'a, Message, Renderer>,
|
||||
) -> Element<'a, Message, Renderer> {
|
||||
Element::new(column)
|
||||
Element::new(tooltip)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
[package]
|
||||
name = "iced_pure"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
description = "Pure widgets for Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/iced-rs/iced"
|
||||
documentation = "https://docs.rs/iced_pure"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
||||
[dependencies]
|
||||
iced_native = { version = "0.4", path = "../native" }
|
||||
iced_style = { version = "0.3", path = "../style" }
|
||||
iced_native = { version = "0.5", path = "../native" }
|
||||
iced_style = { version = "0.4", path = "../style" }
|
||||
num-traits = "0.2"
|
||||
|
|
|
|||
|
|
@ -8,25 +8,171 @@ use iced_native::mouse;
|
|||
use iced_native::renderer;
|
||||
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
|
||||
|
||||
/// A generic [`Widget`].
|
||||
///
|
||||
/// It is useful to build composable user interfaces that do not leak
|
||||
/// implementation details in their __view logic__.
|
||||
///
|
||||
/// If you have a [built-in widget], you should be able to use `Into<Element>`
|
||||
/// to turn it into an [`Element`].
|
||||
///
|
||||
/// [built-in widget]: crate::widget
|
||||
pub struct Element<'a, Message, Renderer> {
|
||||
widget: Box<dyn Widget<Message, Renderer> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a, Message, Renderer> Element<'a, Message, Renderer> {
|
||||
/// Creates a new [`Element`] containing the given [`Widget`].
|
||||
pub fn new(widget: impl Widget<Message, Renderer> + 'a) -> Self {
|
||||
Self {
|
||||
widget: Box::new(widget),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the [`Widget`] of the [`Element`],
|
||||
pub fn as_widget(&self) -> &dyn Widget<Message, Renderer> {
|
||||
self.widget.as_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the [`Widget`] of the [`Element`],
|
||||
pub fn as_widget_mut(&mut self) -> &mut dyn Widget<Message, Renderer> {
|
||||
self.widget.as_mut()
|
||||
}
|
||||
|
||||
/// Applies a transformation to the produced message of the [`Element`].
|
||||
///
|
||||
/// This method is useful when you want to decouple different parts of your
|
||||
/// UI and make them __composable__.
|
||||
///
|
||||
/// # Example
|
||||
/// Imagine we want to use [our counter](index.html#usage). But instead of
|
||||
/// showing a single counter, we want to display many of them. We can reuse
|
||||
/// the `Counter` type as it is!
|
||||
///
|
||||
/// We use composition to model the __state__ of our new application:
|
||||
///
|
||||
/// ```
|
||||
/// # mod counter {
|
||||
/// # pub struct Counter;
|
||||
/// # }
|
||||
/// use counter::Counter;
|
||||
///
|
||||
/// struct ManyCounters {
|
||||
/// counters: Vec<Counter>,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We can store the state of multiple counters now. However, the
|
||||
/// __messages__ we implemented before describe the user interactions
|
||||
/// of a __single__ counter. Right now, we need to also identify which
|
||||
/// counter is receiving user interactions. Can we use composition again?
|
||||
/// Yes.
|
||||
///
|
||||
/// ```
|
||||
/// # mod counter {
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {}
|
||||
/// # }
|
||||
/// #[derive(Debug, Clone, Copy)]
|
||||
/// pub enum Message {
|
||||
/// Counter(usize, counter::Message)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// We compose the previous __messages__ with the index of the counter
|
||||
/// producing them. Let's implement our __view logic__ now:
|
||||
///
|
||||
/// ```
|
||||
/// # mod counter {
|
||||
/// # type Text = iced_pure::widget::Text<iced_native::renderer::Null>;
|
||||
/// #
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {}
|
||||
/// # pub struct Counter;
|
||||
/// #
|
||||
/// # impl Counter {
|
||||
/// # pub fn view(&mut self) -> Text {
|
||||
/// # Text::new("")
|
||||
/// # }
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # mod iced_wgpu {
|
||||
/// # pub use iced_native::renderer::Null as Renderer;
|
||||
/// # }
|
||||
/// #
|
||||
/// # use counter::Counter;
|
||||
/// #
|
||||
/// # struct ManyCounters {
|
||||
/// # counters: Vec<Counter>,
|
||||
/// # }
|
||||
/// #
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {
|
||||
/// # Counter(usize, counter::Message)
|
||||
/// # }
|
||||
/// use iced_pure::Element;
|
||||
/// use iced_pure::widget::Row;
|
||||
/// use iced_wgpu::Renderer;
|
||||
///
|
||||
/// impl ManyCounters {
|
||||
/// pub fn view(&mut self) -> Row<Message, Renderer> {
|
||||
/// // We can quickly populate a `Row` by folding over our counters
|
||||
/// self.counters.iter_mut().enumerate().fold(
|
||||
/// Row::new().spacing(20),
|
||||
/// |row, (index, counter)| {
|
||||
/// // We display the counter
|
||||
/// let element: Element<counter::Message, Renderer> =
|
||||
/// counter.view().into();
|
||||
///
|
||||
/// row.push(
|
||||
/// // Here we turn our `Element<counter::Message>` into
|
||||
/// // an `Element<Message>` by combining the `index` and the
|
||||
/// // message of the `element`.
|
||||
/// element.map(move |message| Message::Counter(index, message))
|
||||
/// )
|
||||
/// }
|
||||
/// )
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Finally, our __update logic__ is pretty straightforward: simple
|
||||
/// delegation.
|
||||
///
|
||||
/// ```
|
||||
/// # mod counter {
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {}
|
||||
/// # pub struct Counter;
|
||||
/// #
|
||||
/// # impl Counter {
|
||||
/// # pub fn update(&mut self, _message: Message) {}
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # use counter::Counter;
|
||||
/// #
|
||||
/// # struct ManyCounters {
|
||||
/// # counters: Vec<Counter>,
|
||||
/// # }
|
||||
/// #
|
||||
/// # #[derive(Debug, Clone, Copy)]
|
||||
/// # pub enum Message {
|
||||
/// # Counter(usize, counter::Message)
|
||||
/// # }
|
||||
/// impl ManyCounters {
|
||||
/// pub fn update(&mut self, message: Message) {
|
||||
/// match message {
|
||||
/// Message::Counter(index, counter_msg) => {
|
||||
/// if let Some(counter) = self.counters.get_mut(index) {
|
||||
/// counter.update(counter_msg);
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub fn map<B>(
|
||||
self,
|
||||
f: impl Fn(Message) -> B + 'a,
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ pub fn resolve<Message, Renderer>(
|
|||
padding: Padding,
|
||||
spacing: f32,
|
||||
align_items: Alignment,
|
||||
items: &[Element<Message, Renderer>],
|
||||
items: &[Element<'_, Message, Renderer>],
|
||||
) -> Node
|
||||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Helper functions to create pure widgets.
|
||||
use crate::widget;
|
||||
use crate::Element;
|
||||
|
||||
|
|
@ -5,6 +6,9 @@ use iced_native::Length;
|
|||
use std::borrow::Cow;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
/// Creates a new [`Container`] with the provided content.
|
||||
///
|
||||
/// [`Container`]: widget::Container
|
||||
pub fn container<'a, Message, Renderer>(
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
) -> widget::Container<'a, Message, Renderer>
|
||||
|
|
@ -14,15 +18,24 @@ where
|
|||
widget::Container::new(content)
|
||||
}
|
||||
|
||||
/// Creates a new [`Column`].
|
||||
///
|
||||
/// [`Column`]: widget::Column
|
||||
pub fn column<'a, Message, Renderer>() -> widget::Column<'a, Message, Renderer>
|
||||
{
|
||||
widget::Column::new()
|
||||
}
|
||||
|
||||
/// Creates a new [`Row`].
|
||||
///
|
||||
/// [`Row`]: widget::Row
|
||||
pub fn row<'a, Message, Renderer>() -> widget::Row<'a, Message, Renderer> {
|
||||
widget::Row::new()
|
||||
}
|
||||
|
||||
/// Creates a new [`Scrollable`] with the provided content.
|
||||
///
|
||||
/// [`Scrollable`]: widget::Scrollable
|
||||
pub fn scrollable<'a, Message, Renderer>(
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
) -> widget::Scrollable<'a, Message, Renderer>
|
||||
|
|
@ -32,12 +45,33 @@ where
|
|||
widget::Scrollable::new(content)
|
||||
}
|
||||
|
||||
/// Creates a new [`Button`] with the provided content.
|
||||
///
|
||||
/// [`Button`]: widget::Button
|
||||
pub fn button<'a, Message, Renderer>(
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
) -> widget::Button<'a, Message, Renderer> {
|
||||
widget::Button::new(content)
|
||||
}
|
||||
|
||||
/// Creates a new [`Tooltip`] with the provided content, tooltip text, and [`tooltip::Position`].
|
||||
///
|
||||
/// [`Tooltip`]: widget::Tooltip
|
||||
/// [`tooltip::Position`]: widget::tooltip::Position
|
||||
pub fn tooltip<'a, Message, Renderer>(
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
tooltip: impl ToString,
|
||||
position: widget::tooltip::Position,
|
||||
) -> widget::Tooltip<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::text::Renderer,
|
||||
{
|
||||
widget::Tooltip::new(content, tooltip, position)
|
||||
}
|
||||
|
||||
/// Creates a new [`Text`] widget with the provided content.
|
||||
///
|
||||
/// [`Text`]: widget::Text
|
||||
pub fn text<Renderer>(text: impl Into<String>) -> widget::Text<Renderer>
|
||||
where
|
||||
Renderer: iced_native::text::Renderer,
|
||||
|
|
@ -45,6 +79,9 @@ where
|
|||
widget::Text::new(text)
|
||||
}
|
||||
|
||||
/// Creates a new [`Checkbox`].
|
||||
///
|
||||
/// [`Checkbox`]: widget::Checkbox
|
||||
pub fn checkbox<'a, Message, Renderer>(
|
||||
label: impl Into<String>,
|
||||
is_checked: bool,
|
||||
|
|
@ -56,6 +93,9 @@ where
|
|||
widget::Checkbox::new(is_checked, label, f)
|
||||
}
|
||||
|
||||
/// Creates a new [`Radio`].
|
||||
///
|
||||
/// [`Radio`]: widget::Radio
|
||||
pub fn radio<'a, Message, Renderer, V>(
|
||||
label: impl Into<String>,
|
||||
value: V,
|
||||
|
|
@ -70,6 +110,9 @@ where
|
|||
widget::Radio::new(value, label, selected, on_click)
|
||||
}
|
||||
|
||||
/// Creates a new [`Toggler`].
|
||||
///
|
||||
/// [`Toggler`]: widget::Toggler
|
||||
pub fn toggler<'a, Message, Renderer>(
|
||||
label: impl Into<Option<String>>,
|
||||
is_checked: bool,
|
||||
|
|
@ -81,6 +124,9 @@ where
|
|||
widget::Toggler::new(is_checked, label, f)
|
||||
}
|
||||
|
||||
/// Creates a new [`TextInput`].
|
||||
///
|
||||
/// [`TextInput`]: widget::TextInput
|
||||
pub fn text_input<'a, Message, Renderer>(
|
||||
placeholder: &str,
|
||||
value: &str,
|
||||
|
|
@ -93,6 +139,9 @@ where
|
|||
widget::TextInput::new(placeholder, value, on_change)
|
||||
}
|
||||
|
||||
/// Creates a new [`Slider`].
|
||||
///
|
||||
/// [`Slider`]: widget::Slider
|
||||
pub fn slider<'a, Message, T>(
|
||||
range: std::ops::RangeInclusive<T>,
|
||||
value: T,
|
||||
|
|
@ -105,6 +154,9 @@ where
|
|||
widget::Slider::new(range, value, on_change)
|
||||
}
|
||||
|
||||
/// Creates a new [`PickList`].
|
||||
///
|
||||
/// [`PickList`]: widget::PickList
|
||||
pub fn pick_list<'a, Message, Renderer, T>(
|
||||
options: impl Into<Cow<'a, [T]>>,
|
||||
selected: Option<T>,
|
||||
|
|
@ -118,24 +170,37 @@ where
|
|||
widget::PickList::new(options, selected, on_selected)
|
||||
}
|
||||
|
||||
/// Creates a new [`Image`].
|
||||
///
|
||||
/// [`Image`]: widget::Image
|
||||
pub fn image<Handle>(handle: impl Into<Handle>) -> widget::Image<Handle> {
|
||||
widget::Image::new(handle.into())
|
||||
}
|
||||
|
||||
/// Creates a new horizontal [`Space`] with the given [`Length`].
|
||||
///
|
||||
/// [`Space`]: widget::Space
|
||||
pub fn horizontal_space(width: Length) -> widget::Space {
|
||||
widget::Space::with_width(width)
|
||||
}
|
||||
|
||||
/// Creates a new vertical [`Space`] with the given [`Length`].
|
||||
///
|
||||
/// [`Space`]: widget::Space
|
||||
pub fn vertical_space(height: Length) -> widget::Space {
|
||||
widget::Space::with_height(height)
|
||||
}
|
||||
|
||||
/// Creates a horizontal [`Rule`] with the given height.
|
||||
///
|
||||
/// [`Rule`]: widget::Rule
|
||||
pub fn horizontal_rule<'a>(height: u16) -> widget::Rule<'a> {
|
||||
widget::Rule::horizontal(height)
|
||||
}
|
||||
|
||||
/// Creates a vertical [`Rule`] with the given width.
|
||||
///
|
||||
/// [`Rule`]: widget::Rule
|
||||
pub fn vertical_rule<'a>(width: u16) -> widget::Rule<'a> {
|
||||
widget::Rule::horizontal(width)
|
||||
}
|
||||
|
|
@ -143,8 +208,10 @@ pub fn vertical_rule<'a>(width: u16) -> widget::Rule<'a> {
|
|||
/// Creates a new [`ProgressBar`].
|
||||
///
|
||||
/// It expects:
|
||||
/// * an inclusive range of possible values
|
||||
/// * the current value of the [`ProgressBar`]
|
||||
/// * an inclusive range of possible values, and
|
||||
/// * the current value of the [`ProgressBar`].
|
||||
///
|
||||
/// [`ProgressBar`]: widget::ProgressBar
|
||||
pub fn progress_bar<'a>(
|
||||
range: RangeInclusive<f32>,
|
||||
value: f32,
|
||||
|
|
|
|||
120
pure/src/lib.rs
120
pure/src/lib.rs
|
|
@ -1,3 +1,92 @@
|
|||
//! Stateless, pure widgets for iced.
|
||||
//!
|
||||
//! # The Elm Architecture, purity, and continuity
|
||||
//! As you may know, applications made with `iced` use [The Elm Architecture].
|
||||
//!
|
||||
//! In a nutshell, this architecture defines the initial state of the application, a way to `view` it, and a way to `update` it after a user interaction. The `update` logic is called after a meaningful user interaction, which in turn updates the state of the application. Then, the `view` logic is executed to redisplay the application.
|
||||
//!
|
||||
//! Since `view` logic is only run after an `update`, all of the mutations to the application state must only happen in the `update` logic. If the application state changes anywhere else, the `view` logic will not be rerun and, therefore, the previously generated `view` may stay outdated.
|
||||
//!
|
||||
//! However, the `Application` trait in `iced` defines `view` as:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! pub trait Application {
|
||||
//! fn view(&mut self) -> Element<Self::Message>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! As a consequence, the application state can be mutated in `view` logic. The `view` logic in `iced` is __impure__.
|
||||
//!
|
||||
//! This impurity is necessary because `iced` puts the burden of widget __continuity__ on its users. In other words, it's up to you to provide `iced` with the internal state of each widget every time `view` is called.
|
||||
//!
|
||||
//! If we take a look at the classic `counter` example:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! struct Counter {
|
||||
//! value: i32,
|
||||
//! increment_button: button::State,
|
||||
//! decrement_button: button::State,
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! pub fn view(&mut self) -> Column<Message> {
|
||||
//! Column::new()
|
||||
//! .push(
|
||||
//! Button::new(&mut self.increment_button, Text::new("+"))
|
||||
//! .on_press(Message::IncrementPressed),
|
||||
//! )
|
||||
//! .push(Text::new(self.value.to_string()).size(50))
|
||||
//! .push(
|
||||
//! Button::new(&mut self.decrement_button, Text::new("-"))
|
||||
//! .on_press(Message::DecrementPressed),
|
||||
//! )
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! We can see how we need to keep track of the `button::State` of each `Button` in our `Counter` state and provide a mutable reference to the widgets in our `view` logic. The widgets produced by `view` are __stateful__.
|
||||
//!
|
||||
//! While this approach forces users to keep track of widget state and causes impurity, I originally chose it because it allows `iced` to directly consume the widget tree produced by `view`. Since there is no internal state decoupled from `view` maintained by the runtime, `iced` does not need to compare (e.g. reconciliate) widget trees in order to ensure continuity.
|
||||
//!
|
||||
//! # Stateless widgets
|
||||
//! As the library matures, the need for some kind of persistent widget data (see #553) between `view` calls becomes more apparent (e.g. incremental rendering, animations, accessibility, etc.).
|
||||
//!
|
||||
//! If we are going to end up having persistent widget data anyways... There is no reason to have impure, stateful widgets anymore!
|
||||
//!
|
||||
//! And so I started exploring and ended up creating a new subcrate called `iced_pure`, which introduces a completely stateless implementation for every widget in `iced`.
|
||||
//!
|
||||
//! With the help of this crate, we can now write a pure `counter` example:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! struct Counter {
|
||||
//! value: i32,
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! fn view(&self) -> Column<Message> {
|
||||
//! Column::new()
|
||||
//! .push(Button::new("Increment").on_press(Message::IncrementPressed))
|
||||
//! .push(Text::new(self.value.to_string()).size(50))
|
||||
//! .push(Button::new("Decrement").on_press(Message::DecrementPressed))
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Notice how we no longer need to keep track of the `button::State`! The widgets in `iced_pure` do not take any mutable application state in `view`. They are __stateless__ widgets. As a consequence, we do not need mutable access to `self` in `view` anymore. `view` becomes __pure__.
|
||||
//!
|
||||
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg"
|
||||
)]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(unused_results)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![forbid(rust_2018_idioms)]
|
||||
|
||||
pub mod helpers;
|
||||
pub mod overlay;
|
||||
pub mod widget;
|
||||
|
|
@ -16,6 +105,32 @@ use iced_native::mouse;
|
|||
use iced_native::renderer;
|
||||
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
|
||||
|
||||
/// A bridge between impure and pure widgets.
|
||||
///
|
||||
/// If you already have an existing `iced` application, you do not need to switch completely to the new traits in order to benefit from the `pure` module. Instead, you can leverage the new `Pure` widget to include `pure` widgets in your impure `Application`.
|
||||
///
|
||||
/// For instance, let's say we want to use our pure `Counter` in an impure application:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use iced_pure::{self, Pure};
|
||||
///
|
||||
/// struct Impure {
|
||||
/// state: pure::State,
|
||||
/// counter: Counter,
|
||||
/// }
|
||||
///
|
||||
/// impl Sandbox for Impure {
|
||||
/// // ...
|
||||
///
|
||||
/// pub fn view(&mut self) -> Element<Self::Message> {
|
||||
/// Pure::new(&mut self.state, self.counter.view()).into()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [`Pure`] acts as a bridge between pure and impure widgets. It is completely opt-in and can be used to slowly migrate your application to the new architecture.
|
||||
///
|
||||
/// The purification of your application may trigger a bunch of important refactors, since it's far easier to keep your data decoupled from the GUI state with stateless widgets. For this reason, I recommend starting small in the most nested views of your application and slowly expand the purity upwards.
|
||||
pub struct Pure<'a, Message, Renderer> {
|
||||
state: &'a mut State,
|
||||
element: Element<'a, Message, Renderer>,
|
||||
|
|
@ -26,6 +141,7 @@ where
|
|||
Message: 'a,
|
||||
Renderer: iced_native::Renderer + 'a,
|
||||
{
|
||||
/// Creates a new [`Pure`] widget with the given [`State`] and impure [`Element`].
|
||||
pub fn new(
|
||||
state: &'a mut State,
|
||||
content: impl Into<Element<'a, Message, Renderer>>,
|
||||
|
|
@ -37,6 +153,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The internal state of a [`Pure`] widget.
|
||||
pub struct State {
|
||||
state_tree: widget::Tree,
|
||||
}
|
||||
|
|
@ -48,6 +165,7 @@ impl Default for State {
|
|||
}
|
||||
|
||||
impl State {
|
||||
/// Creates a new [`State`] for a [`Pure`] widget.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state_tree: widget::Tree::empty(),
|
||||
|
|
@ -56,7 +174,7 @@ impl State {
|
|||
|
||||
fn diff<Message, Renderer>(
|
||||
&mut self,
|
||||
new_element: &Element<Message, Renderer>,
|
||||
new_element: &Element<'_, Message, Renderer>,
|
||||
) {
|
||||
self.state_tree.diff(new_element);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
//! Display interactive elements on top of other widgets.
|
||||
use crate::widget::Tree;
|
||||
|
||||
use iced_native::Layout;
|
||||
|
||||
pub use iced_native::overlay::*;
|
||||
|
||||
/// Obtains the first overlay [`Element`] found in the given children.
|
||||
///
|
||||
/// This method will generally only be used by advanced users that are
|
||||
/// implementing the [`Widget`](crate::Widget) trait.
|
||||
pub fn from_children<'a, Message, Renderer>(
|
||||
children: &'a [crate::Element<'_, Message, Renderer>],
|
||||
tree: &'a mut Tree,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Use the built-in widgets or create your own.
|
||||
pub mod button;
|
||||
pub mod checkbox;
|
||||
pub mod container;
|
||||
|
|
@ -12,6 +13,7 @@ pub mod slider;
|
|||
pub mod svg;
|
||||
pub mod text_input;
|
||||
pub mod toggler;
|
||||
pub mod tooltip;
|
||||
pub mod tree;
|
||||
|
||||
mod column;
|
||||
|
|
@ -37,6 +39,7 @@ pub use svg::Svg;
|
|||
pub use text::Text;
|
||||
pub use text_input::TextInput;
|
||||
pub use toggler::Toggler;
|
||||
pub use tooltip::{Position, Tooltip};
|
||||
pub use tree::Tree;
|
||||
|
||||
use iced_native::event::{self, Event};
|
||||
|
|
@ -46,17 +49,28 @@ use iced_native::overlay;
|
|||
use iced_native::renderer;
|
||||
use iced_native::{Clipboard, Length, Point, Rectangle, Shell};
|
||||
|
||||
/// A component that displays information and allows interaction.
|
||||
///
|
||||
/// If you want to build your own widgets, you will need to implement this
|
||||
/// trait.
|
||||
pub trait Widget<Message, Renderer> {
|
||||
/// Returns the width of the [`Widget`].
|
||||
fn width(&self) -> Length;
|
||||
|
||||
/// Returns the height of the [`Widget`].
|
||||
fn height(&self) -> Length;
|
||||
|
||||
/// Returns the [`layout::Node`] of the [`Widget`].
|
||||
///
|
||||
/// This [`layout::Node`] is used by the runtime to compute the [`Layout`] of the
|
||||
/// user interface.
|
||||
fn layout(
|
||||
&self,
|
||||
renderer: &Renderer,
|
||||
limits: &layout::Limits,
|
||||
) -> layout::Node;
|
||||
|
||||
/// Draws the [`Widget`] using the associated `Renderer`.
|
||||
fn draw(
|
||||
&self,
|
||||
state: &Tree,
|
||||
|
|
@ -67,31 +81,31 @@ pub trait Widget<Message, Renderer> {
|
|||
viewport: &Rectangle,
|
||||
);
|
||||
|
||||
/// Returns the [`Tag`] of the [`Widget`].
|
||||
///
|
||||
/// [`Tag`]: tree::Tag
|
||||
fn tag(&self) -> tree::Tag {
|
||||
tree::Tag::stateless()
|
||||
}
|
||||
|
||||
/// Returns the [`State`] of the [`Widget`].
|
||||
///
|
||||
/// [`State`]: tree::State
|
||||
fn state(&self) -> tree::State {
|
||||
tree::State::None
|
||||
}
|
||||
|
||||
/// Returns the state [`Tree`] of the children of the [`Widget`].
|
||||
fn children(&self) -> Vec<Tree> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Reconciliates the [`Widget`] with the provided [`Tree`].
|
||||
fn diff(&self, _tree: &mut Tree) {}
|
||||
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
_state: &Tree,
|
||||
_layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
_viewport: &Rectangle,
|
||||
_renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
mouse::Interaction::Idle
|
||||
}
|
||||
|
||||
/// Processes a runtime [`Event`].
|
||||
///
|
||||
/// By default, it does nothing.
|
||||
fn on_event(
|
||||
&mut self,
|
||||
_state: &mut Tree,
|
||||
|
|
@ -105,6 +119,21 @@ pub trait Widget<Message, Renderer> {
|
|||
event::Status::Ignored
|
||||
}
|
||||
|
||||
/// Returns the current [`mouse::Interaction`] of the [`Widget`].
|
||||
///
|
||||
/// By default, it returns [`mouse::Interaction::Idle`].
|
||||
fn mouse_interaction(
|
||||
&self,
|
||||
_state: &Tree,
|
||||
_layout: Layout<'_>,
|
||||
_cursor_position: Point,
|
||||
_viewport: &Rectangle,
|
||||
_renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
mouse::Interaction::Idle
|
||||
}
|
||||
|
||||
/// Returns the overlay of the [`Widget`], if there is any.
|
||||
fn overlay<'a>(
|
||||
&'a self,
|
||||
_state: &'a mut Tree,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Allow your users to perform actions by pressing a button.
|
||||
use crate::overlay;
|
||||
use crate::widget::tree::{self, Tree};
|
||||
use crate::{Element, Widget};
|
||||
|
|
@ -15,6 +16,40 @@ pub use iced_style::button::{Style, StyleSheet};
|
|||
|
||||
use button::State;
|
||||
|
||||
/// A generic widget that produces a message when pressed.
|
||||
///
|
||||
/// ```
|
||||
/// # type Button<'a, Message> =
|
||||
/// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>;
|
||||
/// #
|
||||
/// #[derive(Clone)]
|
||||
/// enum Message {
|
||||
/// ButtonPressed,
|
||||
/// }
|
||||
///
|
||||
/// let button = Button::new("Press me!").on_press(Message::ButtonPressed);
|
||||
/// ```
|
||||
///
|
||||
/// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will
|
||||
/// be disabled:
|
||||
///
|
||||
/// ```
|
||||
/// # type Button<'a, Message> =
|
||||
/// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>;
|
||||
/// #
|
||||
/// #[derive(Clone)]
|
||||
/// enum Message {
|
||||
/// ButtonPressed,
|
||||
/// }
|
||||
///
|
||||
/// fn disabled_button<'a>() -> Button<'a, Message> {
|
||||
/// Button::new("I'm disabled!")
|
||||
/// }
|
||||
///
|
||||
/// fn enabled_button<'a>() -> Button<'a, Message> {
|
||||
/// disabled_button().on_press(Message::ButtonPressed)
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Button<'a, Message, Renderer> {
|
||||
content: Element<'a, Message, Renderer>,
|
||||
on_press: Option<Message>,
|
||||
|
|
@ -25,6 +60,7 @@ pub struct Button<'a, Message, Renderer> {
|
|||
}
|
||||
|
||||
impl<'a, Message, Renderer> Button<'a, Message, Renderer> {
|
||||
/// Creates a new [`Button`] with the given content.
|
||||
pub fn new(content: impl Into<Element<'a, Message, Renderer>>) -> Self {
|
||||
Button {
|
||||
content: content.into(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Show toggle controls using checkboxes.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use iced_native::{
|
|||
|
||||
use std::u32;
|
||||
|
||||
/// A container that distributes its contents vertically.
|
||||
pub struct Column<'a, Message, Renderer> {
|
||||
spacing: u16,
|
||||
padding: Padding,
|
||||
|
|
@ -24,10 +25,12 @@ pub struct Column<'a, Message, Renderer> {
|
|||
}
|
||||
|
||||
impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
|
||||
/// Creates an empty [`Column`].
|
||||
pub fn new() -> Self {
|
||||
Self::with_children(Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a [`Column`] with the given elements.
|
||||
pub fn with_children(
|
||||
children: Vec<Element<'a, Message, Renderer>>,
|
||||
) -> Self {
|
||||
|
|
@ -42,21 +45,29 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the vertical spacing _between_ elements.
|
||||
///
|
||||
/// Custom margins per element do not exist in iced. You should use this
|
||||
/// method instead! While less flexible, it helps you keep spacing between
|
||||
/// elements consistent.
|
||||
pub fn spacing(mut self, units: u16) -> Self {
|
||||
self.spacing = units;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Padding`] of the [`Column`].
|
||||
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
|
||||
self.padding = padding.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the width of the [`Column`].
|
||||
pub fn width(mut self, width: Length) -> Self {
|
||||
self.width = width;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the height of the [`Column`].
|
||||
pub fn height(mut self, height: Length) -> Self {
|
||||
self.height = height;
|
||||
self
|
||||
|
|
@ -68,11 +79,13 @@ impl<'a, Message, Renderer> Column<'a, Message, Renderer> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the horizontal alignment of the contents of the [`Column`] .
|
||||
pub fn align_items(mut self, align: Alignment) -> Self {
|
||||
self.align_items = align;
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an element to the [`Column`].
|
||||
pub fn push(
|
||||
mut self,
|
||||
child: impl Into<Element<'a, Message, Renderer>>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display images in your user interface.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||
//! drag and drop, and hotkey support.
|
||||
//!
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
|
||||
mod content;
|
||||
mod title_bar;
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ where
|
|||
fn diff(&self, tree: &mut Tree) {
|
||||
tree.diff_children_custom(
|
||||
&self.elements,
|
||||
|(_, content), state| content.diff(state),
|
||||
|state, (_, content)| content.diff(state),
|
||||
|(_, content)| content.state(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl<'a, Message, Renderer> Content<'a, Message, Renderer>
|
|||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
{
|
||||
pub fn state(&self) -> Tree {
|
||||
pub(super) fn state(&self) -> Tree {
|
||||
let children = if let Some(title_bar) = self.title_bar.as_ref() {
|
||||
vec![Tree::new(&self.body), title_bar.state()]
|
||||
} else {
|
||||
|
|
@ -70,7 +70,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn diff(&self, tree: &mut Tree) {
|
||||
pub(super) fn diff(&self, tree: &mut Tree) {
|
||||
if tree.children.len() == 2 {
|
||||
if let Some(title_bar) = self.title_bar.as_ref() {
|
||||
title_bar.diff(&mut tree.children[1]);
|
||||
|
|
@ -84,7 +84,7 @@ where
|
|||
|
||||
/// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`].
|
||||
///
|
||||
/// [`Renderer`]: crate::widget::pane_grid::Renderer
|
||||
/// [`Renderer`]: iced_native::Renderer
|
||||
pub fn draw(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl<'a, Message, Renderer> TitleBar<'a, Message, Renderer>
|
|||
where
|
||||
Renderer: iced_native::Renderer,
|
||||
{
|
||||
pub fn state(&self) -> Tree {
|
||||
pub(super) fn state(&self) -> Tree {
|
||||
let children = if let Some(controls) = self.controls.as_ref() {
|
||||
vec![Tree::new(&self.content), Tree::new(controls)]
|
||||
} else {
|
||||
|
|
@ -94,7 +94,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn diff(&self, tree: &mut Tree) {
|
||||
pub(super) fn diff(&self, tree: &mut Tree) {
|
||||
if tree.children.len() == 2 {
|
||||
if let Some(controls) = self.controls.as_ref() {
|
||||
tree.children[1].diff(controls);
|
||||
|
|
@ -108,7 +108,7 @@ where
|
|||
|
||||
/// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`].
|
||||
///
|
||||
/// [`Renderer`]: crate::widget::pane_grid::Renderer
|
||||
/// [`Renderer`]: iced_native::Renderer
|
||||
pub fn draw(
|
||||
&self,
|
||||
tree: &Tree,
|
||||
|
|
|
|||
|
|
@ -43,9 +43,8 @@ where
|
|||
/// The default padding of a [`PickList`].
|
||||
pub const DEFAULT_PADDING: Padding = Padding::new(5);
|
||||
|
||||
/// Creates a new [`PickList`] with the given [`State`], a list of options,
|
||||
/// the current selected value, and the message to produce when an option is
|
||||
/// selected.
|
||||
/// Creates a new [`PickList`] with the given list of options, the current
|
||||
/// selected value, and the message to produce when an option is selected.
|
||||
pub fn new(
|
||||
options: impl Into<Cow<'a, [T]>>,
|
||||
selected: Option<T>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Provide progress feedback to your users.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Create choices using radio buttons.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use iced_native::{
|
|||
Alignment, Clipboard, Length, Padding, Point, Rectangle, Shell,
|
||||
};
|
||||
|
||||
/// A container that distributes its contents horizontally.
|
||||
pub struct Row<'a, Message, Renderer> {
|
||||
spacing: u16,
|
||||
padding: Padding,
|
||||
|
|
@ -21,10 +22,12 @@ pub struct Row<'a, Message, Renderer> {
|
|||
}
|
||||
|
||||
impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
|
||||
/// Creates an empty [`Row`].
|
||||
pub fn new() -> Self {
|
||||
Self::with_children(Vec::new())
|
||||
}
|
||||
|
||||
/// Creates a [`Row`] with the given elements.
|
||||
pub fn with_children(
|
||||
children: Vec<Element<'a, Message, Renderer>>,
|
||||
) -> Self {
|
||||
|
|
@ -38,31 +41,41 @@ impl<'a, Message, Renderer> Row<'a, Message, Renderer> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Sets the horizontal spacing _between_ elements.
|
||||
///
|
||||
/// Custom margins per element do not exist in iced. You should use this
|
||||
/// method instead! While less flexible, it helps you keep spacing between
|
||||
/// elements consistent.
|
||||
pub fn spacing(mut self, units: u16) -> Self {
|
||||
self.spacing = units;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Padding`] of the [`Row`].
|
||||
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
|
||||
self.padding = padding.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the width of the [`Row`].
|
||||
pub fn width(mut self, width: Length) -> Self {
|
||||
self.width = width;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the height of the [`Row`].
|
||||
pub fn height(mut self, height: Length) -> Self {
|
||||
self.height = height;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the vertical alignment of the contents of the [`Row`] .
|
||||
pub fn align_items(mut self, align: Alignment) -> Self {
|
||||
self.align_items = align;
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an [`Element`] to the [`Row`].
|
||||
pub fn push(
|
||||
mut self,
|
||||
child: impl Into<Element<'a, Message, Renderer>>,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display a horizontal or vertical rule for dividing content.
|
||||
use crate::widget::Tree;
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Navigate an endless amount of content with a scrollbar.
|
||||
use crate::overlay;
|
||||
use crate::widget::tree::{self, Tree};
|
||||
use crate::{Element, Widget};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
//! Display an interactive selector of a single value from a range of values.
|
||||
//!
|
||||
//! A [`Slider`] has some local [`State`].
|
||||
use crate::widget::tree::{self, Tree};
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
@ -25,17 +23,16 @@ pub use iced_style::slider::{Handle, HandleShape, Style, StyleSheet};
|
|||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::widget::slider::{self, Slider};
|
||||
/// # use iced_pure::widget::Slider;
|
||||
/// #
|
||||
/// #[derive(Clone)]
|
||||
/// pub enum Message {
|
||||
/// SliderChanged(f32),
|
||||
/// }
|
||||
///
|
||||
/// let state = &mut slider::State::new();
|
||||
/// let value = 50.0;
|
||||
///
|
||||
/// Slider::new(state, 0.0..=100.0, value, Message::SliderChanged);
|
||||
/// Slider::new(0.0..=100.0, value, Message::SliderChanged);
|
||||
/// ```
|
||||
///
|
||||
/// 
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display vector graphics in your application.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Display fields that can be filled with text.
|
||||
use crate::widget::tree::{self, Tree};
|
||||
use crate::{Element, Widget};
|
||||
|
||||
|
|
@ -15,20 +16,15 @@ pub use iced_style::text_input::{Style, StyleSheet};
|
|||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use iced_native::renderer::Null;
|
||||
/// # use iced_native::widget::text_input;
|
||||
/// #
|
||||
/// # pub type TextInput<'a, Message> = iced_native::widget::TextInput<'a, Message, Null>;
|
||||
/// # pub type TextInput<'a, Message> = iced_pure::widget::TextInput<'a, Message, iced_native::renderer::Null>;
|
||||
/// #[derive(Debug, Clone)]
|
||||
/// enum Message {
|
||||
/// TextInputChanged(String),
|
||||
/// }
|
||||
///
|
||||
/// let mut state = text_input::State::new();
|
||||
/// let value = "Some text";
|
||||
///
|
||||
/// let input = TextInput::new(
|
||||
/// &mut state,
|
||||
/// "This is the placeholder...",
|
||||
/// value,
|
||||
/// Message::TextInputChanged,
|
||||
|
|
@ -58,10 +54,9 @@ where
|
|||
/// Creates a new [`TextInput`].
|
||||
///
|
||||
/// It expects:
|
||||
/// - some [`State`]
|
||||
/// - a placeholder
|
||||
/// - the current value
|
||||
/// - a function that produces a message when the [`TextInput`] changes
|
||||
/// - a placeholder,
|
||||
/// - the current value, and
|
||||
/// - a function that produces a message when the [`TextInput`] changes.
|
||||
pub fn new<F>(placeholder: &str, value: &str, on_change: F) -> Self
|
||||
where
|
||||
F: 'a + Fn(String) -> Message,
|
||||
|
|
@ -86,10 +81,9 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Font`] of the [`Text`].
|
||||
/// Sets the [`Font`] of the [`TextInput`].
|
||||
///
|
||||
/// [`Font`]: crate::widget::text::Renderer::Font
|
||||
/// [`Text`]: crate::widget::Text
|
||||
/// [`Font`]: iced_native::text::Renderer::Font
|
||||
pub fn font(mut self, font: Renderer::Font) -> Self {
|
||||
self.font = font;
|
||||
self
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//! Show toggle controls using togglers.
|
||||
use crate::widget::{Tree, Widget};
|
||||
use crate::Element;
|
||||
|
||||
|
|
|
|||
228
pure/src/widget/tooltip.rs
Normal file
228
pure/src/widget/tooltip.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,24 @@
|
|||
//! Store internal widget state in a state tree to ensure continuity.
|
||||
use crate::Element;
|
||||
|
||||
use std::any::{self, Any};
|
||||
|
||||
/// A persistent state widget tree.
|
||||
///
|
||||
/// A [`Tree`] is normally associated with a specific widget in the widget tree.
|
||||
pub struct Tree {
|
||||
/// The tag of the [`Tree`].
|
||||
pub tag: Tag,
|
||||
|
||||
/// The [`State`] of the [`Tree`].
|
||||
pub state: State,
|
||||
|
||||
/// The children of the root widget of the [`Tree`].
|
||||
pub children: Vec<Tree>,
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
/// Creates an empty, stateless [`Tree`] with no children.
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
tag: Tag::stateless(),
|
||||
|
|
@ -17,6 +27,7 @@ impl Tree {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`Tree`] for the provided [`Element`].
|
||||
pub fn new<Message, Renderer>(
|
||||
element: &Element<'_, Message, Renderer>,
|
||||
) -> Self {
|
||||
|
|
@ -27,6 +38,14 @@ impl Tree {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reconciliates the current tree with the provided [`Element`].
|
||||
///
|
||||
/// If the tag of the [`Element`] matches the tag of the [`Tree`], then the
|
||||
/// [`Element`] proceeds with the reconciliation (i.e. [`Widget::diff`] is called).
|
||||
///
|
||||
/// Otherwise, the whole [`Tree`] is recreated.
|
||||
///
|
||||
/// [`Widget::diff`]: crate::Widget::diff
|
||||
pub fn diff<Message, Renderer>(
|
||||
&mut self,
|
||||
new: &Element<'_, Message, Renderer>,
|
||||
|
|
@ -38,21 +57,20 @@ impl Tree {
|
|||
}
|
||||
}
|
||||
|
||||
/// Reconciliates the children of the tree with the provided list of [`Element`].
|
||||
pub fn diff_children<Message, Renderer>(
|
||||
&mut self,
|
||||
new_children: &[Element<'_, Message, Renderer>],
|
||||
) {
|
||||
self.diff_children_custom(
|
||||
new_children,
|
||||
|new, child_state| child_state.diff(new),
|
||||
Self::new,
|
||||
)
|
||||
self.diff_children_custom(new_children, Self::diff, Self::new)
|
||||
}
|
||||
|
||||
/// Reconciliates the children of the tree with the provided list of [`Element`] using custom
|
||||
/// logic both for diffing and creating new widget state.
|
||||
pub fn diff_children_custom<T>(
|
||||
&mut self,
|
||||
new_children: &[T],
|
||||
diff: impl Fn(&T, &mut Tree),
|
||||
diff: impl Fn(&mut Tree, &T),
|
||||
new_state: impl Fn(&T) -> Self,
|
||||
) {
|
||||
if self.children.len() > new_children.len() {
|
||||
|
|
@ -62,7 +80,7 @@ impl Tree {
|
|||
for (child_state, new) in
|
||||
self.children.iter_mut().zip(new_children.iter())
|
||||
{
|
||||
diff(new, child_state);
|
||||
diff(child_state, new);
|
||||
}
|
||||
|
||||
if self.children.len() < new_children.len() {
|
||||
|
|
@ -73,10 +91,12 @@ impl Tree {
|
|||
}
|
||||
}
|
||||
|
||||
/// The identifier of some widget state.
|
||||
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
pub struct Tag(any::TypeId);
|
||||
|
||||
impl Tag {
|
||||
/// Creates a [`Tag`] for a state of type `T`.
|
||||
pub fn of<T>() -> Self
|
||||
where
|
||||
T: 'static,
|
||||
|
|
@ -84,17 +104,23 @@ impl Tag {
|
|||
Self(any::TypeId::of::<T>())
|
||||
}
|
||||
|
||||
/// Creates a [`Tag`] for a stateless widget.
|
||||
pub fn stateless() -> Self {
|
||||
Self::of::<()>()
|
||||
}
|
||||
}
|
||||
|
||||
/// The internal [`State`] of a widget.
|
||||
pub enum State {
|
||||
/// No meaningful internal state.
|
||||
None,
|
||||
|
||||
/// Some meaningful internal state.
|
||||
Some(Box<dyn Any>),
|
||||
}
|
||||
|
||||
impl State {
|
||||
/// Creates a new [`State`].
|
||||
pub fn new<T>(state: T) -> Self
|
||||
where
|
||||
T: 'static,
|
||||
|
|
@ -102,6 +128,10 @@ impl State {
|
|||
State::Some(Box::new(state))
|
||||
}
|
||||
|
||||
/// Downcasts the [`State`] to `T` and returns a reference to it.
|
||||
///
|
||||
/// # Panics
|
||||
/// This method will panic if the downcast fails or the [`State`] is [`State::None`].
|
||||
pub fn downcast_ref<T>(&self) -> &T
|
||||
where
|
||||
T: 'static,
|
||||
|
|
@ -114,6 +144,10 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
/// Downcasts the [`State`] to `T` and returns a mutable reference to it.
|
||||
///
|
||||
/// # Panics
|
||||
/// This method will panic if the downcast fails or the [`State`] is [`State::None`].
|
||||
pub fn downcast_mut<T>(&mut self) -> &mut T
|
||||
where
|
||||
T: 'static,
|
||||
|
|
|
|||
|
|
@ -37,15 +37,15 @@ use crate::{Color, Command, Element, Executor, Settings, Subscription};
|
|||
/// to listen to time.
|
||||
/// - [`todos`], a todos tracker inspired by [TodoMVC].
|
||||
///
|
||||
/// [The repository has a bunch of examples]: https://github.com/hecrj/iced/tree/0.3/examples
|
||||
/// [`clock`]: https://github.com/hecrj/iced/tree/0.3/examples/clock
|
||||
/// [`download_progress`]: https://github.com/hecrj/iced/tree/0.3/examples/download_progress
|
||||
/// [`events`]: https://github.com/hecrj/iced/tree/0.3/examples/events
|
||||
/// [`game_of_life`]: https://github.com/hecrj/iced/tree/0.3/examples/game_of_life
|
||||
/// [`pokedex`]: https://github.com/hecrj/iced/tree/0.3/examples/pokedex
|
||||
/// [`solar_system`]: https://github.com/hecrj/iced/tree/0.3/examples/solar_system
|
||||
/// [`stopwatch`]: https://github.com/hecrj/iced/tree/0.3/examples/stopwatch
|
||||
/// [`todos`]: https://github.com/hecrj/iced/tree/0.3/examples/todos
|
||||
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
/// [`clock`]: https://github.com/iced-rs/iced/tree/0.4/examples/clock
|
||||
/// [`download_progress`]: https://github.com/iced-rs/iced/tree/0.4/examples/download_progress
|
||||
/// [`events`]: https://github.com/iced-rs/iced/tree/0.4/examples/events
|
||||
/// [`game_of_life`]: https://github.com/iced-rs/iced/tree/0.4/examples/game_of_life
|
||||
/// [`pokedex`]: https://github.com/iced-rs/iced/tree/0.4/examples/pokedex
|
||||
/// [`solar_system`]: https://github.com/iced-rs/iced/tree/0.4/examples/solar_system
|
||||
/// [`stopwatch`]: https://github.com/iced-rs/iced/tree/0.4/examples/stopwatch
|
||||
/// [`todos`]: https://github.com/iced-rs/iced/tree/0.4/examples/todos
|
||||
/// [`Sandbox`]: crate::Sandbox
|
||||
/// [`Canvas`]: crate::widget::Canvas
|
||||
/// [PokéAPI]: https://pokeapi.co/
|
||||
|
|
|
|||
21
src/lib.rs
21
src/lib.rs
|
|
@ -19,19 +19,19 @@
|
|||
//!
|
||||
//! Check out the [repository] and the [examples] for more details!
|
||||
//!
|
||||
//! [Cross-platform support]: https://github.com/hecrj/iced/blob/master/docs/images/todos_desktop.jpg?raw=true
|
||||
//! [Cross-platform support]: https://github.com/iced-rs/iced/blob/master/docs/images/todos_desktop.jpg?raw=true
|
||||
//! [text inputs]: https://gfycat.com/alertcalmcrow-rust-gui
|
||||
//! [scrollables]: https://gfycat.com/perkybaggybaboon-rust-gui
|
||||
//! [Debug overlay with performance metrics]: https://gfycat.com/incredibledarlingbee
|
||||
//! [Modular ecosystem]: https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md
|
||||
//! [renderer-agnostic native runtime]: https://github.com/hecrj/iced/tree/master/native
|
||||
//! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md
|
||||
//! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/0.4/master/native
|
||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||
//! [built-in renderer]: https://github.com/hecrj/iced/tree/master/wgpu
|
||||
//! [windowing shell]: https://github.com/hecrj/iced/tree/master/winit
|
||||
//! [built-in renderer]: https://github.com/iced-rs/iced/tree/0.4/wgpu
|
||||
//! [windowing shell]: https://github.com/iced-rs/iced/tree/0.4/winit
|
||||
//! [`dodrio`]: https://github.com/fitzgen/dodrio
|
||||
//! [web runtime]: https://github.com/hecrj/iced/tree/master/web
|
||||
//! [examples]: https://github.com/hecrj/iced/tree/0.3/examples
|
||||
//! [repository]: https://github.com/hecrj/iced
|
||||
//! [web runtime]: https://github.com/iced-rs/iced_web
|
||||
//! [examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
//! [repository]: https://github.com/iced-rs/iced
|
||||
//!
|
||||
//! # Overview
|
||||
//! Inspired by [The Elm Architecture], Iced expects you to split user
|
||||
|
|
@ -196,6 +196,7 @@ pub mod widget;
|
|||
pub mod window;
|
||||
|
||||
#[cfg(feature = "pure")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "pure")))]
|
||||
pub mod pure;
|
||||
|
||||
#[cfg(all(not(feature = "glow"), feature = "wgpu"))]
|
||||
|
|
@ -225,8 +226,8 @@ pub use settings::Settings;
|
|||
pub use runtime::alignment;
|
||||
pub use runtime::futures;
|
||||
pub use runtime::{
|
||||
Alignment, Background, Color, Command, ContentFit, Font, Length, Point,
|
||||
Rectangle, Size, Subscription, Vector,
|
||||
Alignment, Background, Color, Command, ContentFit, Font, Length, Padding,
|
||||
Point, Rectangle, Size, Subscription, Vector,
|
||||
};
|
||||
|
||||
#[cfg(feature = "system")]
|
||||
|
|
|
|||
79
src/pure.rs
79
src/pure.rs
|
|
@ -14,6 +14,84 @@
|
|||
//! offers an alternate [`Application`] trait with a completely pure `view`
|
||||
//! method.
|
||||
//!
|
||||
//! # The Elm Architecture, purity, and continuity
|
||||
//! As you may know, applications made with `iced` use [The Elm Architecture].
|
||||
//!
|
||||
//! In a nutshell, this architecture defines the initial state of the application, a way to `view` it, and a way to `update` it after a user interaction. The `update` logic is called after a meaningful user interaction, which in turn updates the state of the application. Then, the `view` logic is executed to redisplay the application.
|
||||
//!
|
||||
//! Since `view` logic is only run after an `update`, all of the mutations to the application state must only happen in the `update` logic. If the application state changes anywhere else, the `view` logic will not be rerun and, therefore, the previously generated `view` may stay outdated.
|
||||
//!
|
||||
//! However, the `Application` trait in `iced` defines `view` as:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! pub trait Application {
|
||||
//! fn view(&mut self) -> Element<Self::Message>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! As a consequence, the application state can be mutated in `view` logic. The `view` logic in `iced` is __impure__.
|
||||
//!
|
||||
//! This impurity is necessary because `iced` puts the burden of widget __continuity__ on its users. In other words, it's up to you to provide `iced` with the internal state of each widget every time `view` is called.
|
||||
//!
|
||||
//! If we take a look at the classic `counter` example:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! struct Counter {
|
||||
//! value: i32,
|
||||
//! increment_button: button::State,
|
||||
//! decrement_button: button::State,
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! pub fn view(&mut self) -> Column<Message> {
|
||||
//! Column::new()
|
||||
//! .push(
|
||||
//! Button::new(&mut self.increment_button, Text::new("+"))
|
||||
//! .on_press(Message::IncrementPressed),
|
||||
//! )
|
||||
//! .push(Text::new(self.value.to_string()).size(50))
|
||||
//! .push(
|
||||
//! Button::new(&mut self.decrement_button, Text::new("-"))
|
||||
//! .on_press(Message::DecrementPressed),
|
||||
//! )
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! We can see how we need to keep track of the `button::State` of each `Button` in our `Counter` state and provide a mutable reference to the widgets in our `view` logic. The widgets produced by `view` are __stateful__.
|
||||
//!
|
||||
//! While this approach forces users to keep track of widget state and causes impurity, I originally chose it because it allows `iced` to directly consume the widget tree produced by `view`. Since there is no internal state decoupled from `view` maintained by the runtime, `iced` does not need to compare (e.g. reconciliate) widget trees in order to ensure continuity.
|
||||
//!
|
||||
//! # Stateless widgets
|
||||
//! As the library matures, the need for some kind of persistent widget data (see #553) between `view` calls becomes more apparent (e.g. incremental rendering, animations, accessibility, etc.).
|
||||
//!
|
||||
//! If we are going to end up having persistent widget data anyways... There is no reason to have impure, stateful widgets anymore!
|
||||
//!
|
||||
//! With the help of this module, we can now write a pure `counter` example:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! struct Counter {
|
||||
//! value: i32,
|
||||
//! }
|
||||
//!
|
||||
//! // ...
|
||||
//!
|
||||
//! impl Counter {
|
||||
//! fn view(&self) -> Column<Message> {
|
||||
//! Column::new()
|
||||
//! .push(Button::new("Increment").on_press(Message::IncrementPressed))
|
||||
//! .push(Text::new(self.value.to_string()).size(50))
|
||||
//! .push(Button::new("Decrement").on_press(Message::DecrementPressed))
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Notice how we no longer need to keep track of the `button::State`! The widgets in `iced_pure` do not take any mutable application state in `view`. They are __stateless__ widgets. As a consequence, we do not need mutable access to `self` in `view` anymore. `view` becomes __pure__.
|
||||
//!
|
||||
//! [The Elm Architecture]: https://guide.elm-lang.org/architecture/
|
||||
//!
|
||||
//! [the original widgets]: crate::widget
|
||||
//! [`button::State`]: crate::widget::button::State
|
||||
//! [impure `Application`]: crate::Application
|
||||
|
|
@ -26,6 +104,7 @@ pub use application::Application;
|
|||
pub use sandbox::Sandbox;
|
||||
|
||||
pub use iced_pure::helpers::*;
|
||||
pub use iced_pure::Widget;
|
||||
pub use iced_pure::{Pure, State};
|
||||
|
||||
/// A generic, pure [`Widget`].
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub mod pane_grid {
|
|||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||
//! drag and drop, and hotkey support.
|
||||
//!
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
|
||||
pub use iced_pure::widget::pane_grid::{
|
||||
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
|
||||
ResizeEvent, Split, State, StyleSheet,
|
||||
|
|
@ -118,6 +118,15 @@ pub mod text_input {
|
|||
iced_pure::widget::TextInput<'a, Message, Renderer>;
|
||||
}
|
||||
|
||||
pub mod tooltip {
|
||||
//! Display a widget over another.
|
||||
pub use iced_pure::widget::tooltip::Position;
|
||||
|
||||
/// A widget allowing the selection of a single value from a list of options.
|
||||
pub type Tooltip<'a, Message> =
|
||||
iced_pure::widget::Tooltip<'a, Message, crate::Renderer>;
|
||||
}
|
||||
|
||||
pub use iced_pure::widget::progress_bar;
|
||||
pub use iced_pure::widget::rule;
|
||||
pub use iced_pure::widget::slider;
|
||||
|
|
@ -135,6 +144,7 @@ pub use scrollable::Scrollable;
|
|||
pub use slider::Slider;
|
||||
pub use text_input::TextInput;
|
||||
pub use toggler::Toggler;
|
||||
pub use tooltip::Tooltip;
|
||||
|
||||
#[cfg(feature = "canvas")]
|
||||
pub use iced_graphics::widget::pure::canvas;
|
||||
|
|
|
|||
|
|
@ -35,19 +35,19 @@ use crate::{
|
|||
/// - [`tour`], a simple UI tour that can run both on native platforms and the
|
||||
/// web!
|
||||
///
|
||||
/// [The repository has a bunch of examples]: https://github.com/hecrj/iced/tree/0.3/examples
|
||||
/// [`bezier_tool`]: https://github.com/hecrj/iced/tree/0.3/examples/bezier_tool
|
||||
/// [`counter`]: https://github.com/hecrj/iced/tree/0.3/examples/counter
|
||||
/// [`custom_widget`]: https://github.com/hecrj/iced/tree/0.3/examples/custom_widget
|
||||
/// [`geometry`]: https://github.com/hecrj/iced/tree/0.3/examples/geometry
|
||||
/// [`pane_grid`]: https://github.com/hecrj/iced/tree/0.3/examples/pane_grid
|
||||
/// [`progress_bar`]: https://github.com/hecrj/iced/tree/0.3/examples/progress_bar
|
||||
/// [`styling`]: https://github.com/hecrj/iced/tree/0.3/examples/styling
|
||||
/// [`svg`]: https://github.com/hecrj/iced/tree/0.3/examples/svg
|
||||
/// [`tour`]: https://github.com/hecrj/iced/tree/0.3/examples/tour
|
||||
/// [The repository has a bunch of examples]: https://github.com/iced-rs/iced/tree/0.4/examples
|
||||
/// [`bezier_tool`]: https://github.com/iced-rs/iced/tree/0.4/examples/bezier_tool
|
||||
/// [`counter`]: https://github.com/iced-rs/iced/tree/0.4/examples/counter
|
||||
/// [`custom_widget`]: https://github.com/iced-rs/iced/tree/0.4/examples/custom_widget
|
||||
/// [`geometry`]: https://github.com/iced-rs/iced/tree/0.4/examples/geometry
|
||||
/// [`pane_grid`]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
|
||||
/// [`progress_bar`]: https://github.com/iced-rs/iced/tree/0.4/examples/progress_bar
|
||||
/// [`styling`]: https://github.com/iced-rs/iced/tree/0.4/examples/styling
|
||||
/// [`svg`]: https://github.com/iced-rs/iced/tree/0.4/examples/svg
|
||||
/// [`tour`]: https://github.com/iced-rs/iced/tree/0.4/examples/tour
|
||||
/// [`Canvas widget`]: crate::widget::Canvas
|
||||
/// [the overview]: index.html#overview
|
||||
/// [`iced_wgpu`]: https://github.com/hecrj/iced/tree/0.3/wgpu
|
||||
/// [`iced_wgpu`]: https://github.com/iced-rs/iced/tree/0.4/wgpu
|
||||
/// [`Svg` widget]: crate::widget::Svg
|
||||
/// [Ghostscript Tiger]: https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg
|
||||
///
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ pub mod pane_grid {
|
|||
//! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing,
|
||||
//! drag and drop, and hotkey support.
|
||||
//!
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.3/examples/pane_grid
|
||||
//! [`pane_grid` example]: https://github.com/iced-rs/iced/tree/0.4/examples/pane_grid
|
||||
pub use iced_native::widget::pane_grid::{
|
||||
Axis, Configuration, Direction, DragEvent, Line, Node, Pane,
|
||||
ResizeEvent, Split, State, StyleSheet,
|
||||
|
|
@ -167,9 +167,11 @@ pub use toggler::Toggler;
|
|||
pub use tooltip::Tooltip;
|
||||
|
||||
#[cfg(feature = "canvas")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
|
||||
pub use iced_graphics::widget::canvas;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
|
||||
pub mod image {
|
||||
//! Display images in your user interface.
|
||||
pub use iced_native::image::Handle;
|
||||
|
|
@ -182,9 +184,11 @@ pub mod image {
|
|||
}
|
||||
|
||||
#[cfg(feature = "qr_code")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "qr_code")))]
|
||||
pub use iced_graphics::widget::qr_code;
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
|
||||
pub mod svg {
|
||||
//! Display vector graphics in your application.
|
||||
pub use iced_native::svg::Handle;
|
||||
|
|
@ -192,13 +196,17 @@ pub mod svg {
|
|||
}
|
||||
|
||||
#[cfg(feature = "canvas")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
|
||||
pub use canvas::Canvas;
|
||||
|
||||
#[cfg(feature = "image")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "image")))]
|
||||
pub use image::Image;
|
||||
|
||||
#[cfg(feature = "qr_code")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "qr_code")))]
|
||||
pub use qr_code::QRCode;
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
|
||||
pub use svg::Svg;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_style"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "The default set of styles of Iced"
|
||||
|
|
@ -11,5 +11,5 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
|||
categories = ["gui"]
|
||||
|
||||
[dependencies.iced_core]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../core"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "iced_wgpu"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A wgpu renderer for Iced"
|
||||
|
|
@ -43,11 +43,11 @@ version = "1.4"
|
|||
features = ["derive"]
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_graphics]
|
||||
version = "0.2"
|
||||
version = "0.3"
|
||||
path = "../graphics"
|
||||
features = ["font-fallback", "font-icons"]
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
//! - Meshes of triangles, useful to draw geometry freely.
|
||||
//!
|
||||
//! [Iced]: https://github.com/iced-rs/iced
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/master/native
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
//! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
|
||||
//! [WebGPU API]: https://gpuweb.github.io/gpuweb/
|
||||
//! [`wgpu_glyph`]: https://github.com/hecrj/wgpu_glyph
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[package]
|
||||
name = "iced_winit"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
|
||||
edition = "2021"
|
||||
description = "A winit runtime for Iced"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/hecrj/iced"
|
||||
repository = "https://github.com/iced-rs/iced"
|
||||
documentation = "https://docs.rs/iced_winit"
|
||||
keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
||||
categories = ["gui"]
|
||||
|
|
@ -25,15 +25,15 @@ git = "https://github.com/iced-rs/winit"
|
|||
rev = "02a12380960cec2f351c09a33d6a7cc2789d96a6"
|
||||
|
||||
[dependencies.iced_native]
|
||||
version = "0.4"
|
||||
version = "0.5"
|
||||
path = "../native"
|
||||
|
||||
[dependencies.iced_graphics]
|
||||
version = "0.2"
|
||||
version = "0.3"
|
||||
path = "../graphics"
|
||||
|
||||
[dependencies.iced_futures]
|
||||
version = "0.3"
|
||||
version = "0.4"
|
||||
path = "../futures"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# `iced_winit`
|
||||
[][documentation]
|
||||
[](https://crates.io/crates/iced_winit)
|
||||
[](https://github.com/hecrj/iced/blob/master/LICENSE)
|
||||
[](https://github.com/iced-rs/iced/blob/master/LICENSE)
|
||||
[](https://discord.gg/3xZJ65GAhd)
|
||||
|
||||
`iced_winit` offers some convenient abstractions on top of [`iced_native`] to quickstart development when using [`winit`].
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Convert [`winit`] types into [`iced_native`] types, and viceversa.
|
||||
//!
|
||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
use crate::keyboard;
|
||||
use crate::mouse;
|
||||
use crate::touch;
|
||||
|
|
@ -208,7 +208,7 @@ pub fn visible(mode: Mode) -> bool {
|
|||
/// Converts a `MouseCursor` from [`iced_native`] to a [`winit`] cursor icon.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
pub fn mouse_interaction(
|
||||
interaction: mouse::Interaction,
|
||||
) -> winit::window::CursorIcon {
|
||||
|
|
@ -232,7 +232,7 @@ pub fn mouse_interaction(
|
|||
/// Converts a `MouseButton` from [`winit`] to an [`iced_native`] mouse button.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
|
||||
match mouse_button {
|
||||
winit::event::MouseButton::Left => mouse::Button::Left,
|
||||
|
|
@ -248,7 +248,7 @@ pub fn mouse_button(mouse_button: winit::event::MouseButton) -> mouse::Button {
|
|||
/// modifiers state.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
pub fn modifiers(
|
||||
modifiers: winit::event::ModifiersState,
|
||||
) -> keyboard::Modifiers {
|
||||
|
|
@ -275,7 +275,7 @@ pub fn cursor_position(
|
|||
/// Converts a `Touch` from [`winit`] to an [`iced_native`] touch event.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
pub fn touch_event(
|
||||
touch: winit::event::Touch,
|
||||
scale_factor: f64,
|
||||
|
|
@ -306,7 +306,7 @@ pub fn touch_event(
|
|||
/// Converts a `VirtualKeyCode` from [`winit`] to an [`iced_native`] key code.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
/// [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
/// [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
pub fn key_code(
|
||||
virtual_keycode: winit::event::VirtualKeyCode,
|
||||
) -> keyboard::KeyCode {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! A windowing shell for Iced, on top of [`winit`].
|
||||
//!
|
||||
//! 
|
||||
//! 
|
||||
//!
|
||||
//! `iced_winit` offers some convenient abstractions on top of [`iced_native`]
|
||||
//! to quickstart development when using [`winit`].
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
//! Additionally, a [`conversion`] module is available for users that decide to
|
||||
//! implement a custom event loop.
|
||||
//!
|
||||
//! [`iced_native`]: https://github.com/hecrj/iced/tree/master/native
|
||||
//! [`iced_native`]: https://github.com/iced-rs/iced/tree/0.4/native
|
||||
//! [`winit`]: https://github.com/rust-windowing/winit
|
||||
//! [`conversion`]: crate::conversion
|
||||
#![doc(
|
||||
|
|
|
|||
|
|
@ -37,12 +37,16 @@ pub struct Settings<Flags> {
|
|||
|
||||
/// Whether the [`Application`] should exit when the user requests the
|
||||
/// window to close (e.g. the user presses the close button).
|
||||
///
|
||||
/// [`Application`]: crate::Application
|
||||
pub exit_on_close_request: bool,
|
||||
|
||||
/// Whether the [`Application`] should try to build the context
|
||||
/// using OpenGL ES first then OpenGL.
|
||||
///
|
||||
/// NOTE: Only works for the `glow` backend.
|
||||
///
|
||||
/// [`Application`]: crate::Application
|
||||
pub try_opengles_first: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue