diff options
178 files changed, 1781 insertions, 1401 deletions
diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index ba5dc190..e9f4b0c5 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,12 +1,26 @@ name: Audit -on: [push] +on: + push: {} + pull_request: {} + schedule: + - cron: '0 0 * * *' jobs: - dependencies: + vulnerabilities: runs-on: ubuntu-latest steps: - uses: hecrj/setup-rust-action@v1 - name: Install cargo-audit run: cargo install cargo-audit - uses: actions/checkout@master - - name: Audit dependencies + - name: Audit vulnerabilities run: cargo audit + + artifacts: + runs-on: ubuntu-latest + steps: + - uses: hecrj/setup-rust-action@v1 + - name: Install cargo-outdated + run: cargo install cargo-outdated + - uses: actions/checkout@master + - name: Find outdated dependencies + run: cargo outdated --workspace --exit-code 1 diff --git a/.github/workflows/document.yml b/.github/workflows/document.yml index 09a7a4d5..230c5cb0 100644 --- a/.github/workflows/document.yml +++ b/.github/workflows/document.yml @@ -1,8 +1,5 @@ name: Document -on: - push: - branches: - - master +on: [push, pull_request] jobs: all: runs-on: ubuntu-20.04 @@ -31,6 +28,7 @@ jobs: - name: Write CNAME file run: echo 'docs.iced.rs' > ./target/doc/CNAME - name: Publish documentation + if: github.ref == 'refs/heads/master' uses: peaceiris/actions-gh-pages@v3 with: deploy_key: ${{ secrets.DOCS_DEPLOY_KEY }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9a9b3f9..ac8d27f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,6 +25,8 @@ jobs: web: runs-on: ubuntu-latest + env: + RUSTFLAGS: --cfg=web_sys_unstable_apis steps: - uses: hecrj/setup-rust-action@v1 with: diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml deleted file mode 100644 index 089dd5c9..00000000 --- a/.github/workflows/verify.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Verify -on: - pull_request: - branches: - - master -jobs: - changelog: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Check `CHANGELOG.md` has changes - run: | - ! git diff --exit-code origin/master HEAD -- CHANGELOG.md - - name: Check `CHANGELOG.md` thanks the PR author - if: ${{ github.event.pull_request.user.login != 'hecrj' }} - run: | - sed -n '/## \[Unreleased\]/,/^## /p' CHANGELOG.md | sed -n '/Many thanks to.../,//p' | grep '@${{ github.event.pull_request.user.login }}' diff --git a/CHANGELOG.md b/CHANGELOG.md index d80dc5e0..ed02baf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `Theme::Custom::with_fn` for custom extended palette generation. [#2067](https://github.com/iced-rs/iced/pull/2067) + +### Changed +- Updated `wgpu` to `0.17`. [#2065](https://github.com/iced-rs/iced/pull/2065) +- Changed `Button::style` to take an `impl Into<...>` for consistency. [#2046](https://github.com/iced-rs/iced/pull/2046) + +### Fixed +- Missing `width` attribute in `styling` example. [#2062](https://github.com/iced-rs/iced/pull/2062) + +Many thanks to... + +- @akshayr-mecha +- @dtzxporter ### Added - Explicit text caching. [#2058](https://github.com/iced-rs/iced/pull/2058) @@ -1,22 +1,28 @@ [package] name = "iced" -version = "0.10.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" description = "A cross-platform GUI library inspired by Elm" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced" -readme = "README.md" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] +all-features = true + +[badges] +maintenance = { status = "actively-developed" } [features] default = ["wgpu"] # Enable the `wgpu` GPU-accelerated renderer backend wgpu = ["iced_renderer/wgpu"] # Enables the `Image` widget -image = ["iced_widget/image", "image_rs"] +image = ["iced_widget/image", "dep:image"] # Enables the `Svg` widget svg = ["iced_widget/svg"] # Enables the `Canvas` widget @@ -39,11 +45,33 @@ palette = ["iced_core/palette"] system = ["iced_winit/system"] # Enables broken "sRGB linear" blending to reproduce color management of the Web web-colors = ["iced_renderer/web-colors"] +# Enables the WebGL backend, replacing WebGPU +webgl = ["iced_renderer/webgl"] # Enables the advanced module advanced = [] -[badges] -maintenance = { status = "actively-developed" } +[dependencies] +iced_core.workspace = true +iced_futures.workspace = true +iced_renderer.workspace = true +iced_widget.workspace = true +iced_winit.features = ["application"] +iced_winit.workspace = true + +thiserror.workspace = true + +image.workspace = true +image.optional = true + +[profile.release-opt] +inherits = "release" +codegen-units = 1 +debug = false +lto = true +incremental = false +opt-level = 3 +overflow-checks = false +strip = "debuginfo" [workspace] members = [ @@ -60,29 +88,66 @@ members = [ "examples/*", ] -[dependencies] -iced_core = { version = "0.10", path = "core" } -iced_futures = { version = "0.7", path = "futures" } -iced_renderer = { version = "0.1", path = "renderer" } -iced_widget = { version = "0.1", path = "widget" } -iced_winit = { version = "0.10", path = "winit", features = ["application"] } -thiserror = "1" +[workspace.package] +version = "0.12.0" +authors = ["Héctor Ramón Jiménez <hector@hecrj.dev>"] +edition = "2021" +license = "MIT" +repository = "https://github.com/iced-rs/iced" +homepage = "https://iced.rs" +categories = ["gui"] +keywords = ["gui", "ui", "graphics", "interface", "widgets"] -[dependencies.image_rs] -version = "0.24" -package = "image" -optional = true +[workspace.dependencies] +iced = { version = "0.12", path = "." } +iced_core = { version = "0.12", path = "core" } +iced_futures = { version = "0.12", path = "futures" } +iced_graphics = { version = "0.12", path = "graphics" } +iced_renderer = { version = "0.12", path = "renderer" } +iced_runtime = { version = "0.12", path = "runtime" } +iced_style = { version = "0.12", path = "style" } +iced_tiny_skia = { version = "0.12", path = "tiny_skia" } +iced_wgpu = { version = "0.12", path = "wgpu" } +iced_widget = { version = "0.12", path = "widget" } +iced_winit = { version = "0.12", path = "winit" } -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true - -[profile.release-opt] -inherits = "release" -codegen-units = 1 -debug = false -lto = true -incremental = false -opt-level = 3 -overflow-checks = false -strip = "debuginfo" +async-std = "1.0" +bitflags = "1.0" +bytemuck = { version = "1.0", features = ["derive"] } +cosmic-text = "0.9" +futures = "0.3" +glam = "0.24" +glyphon = { git = "https://github.com/grovesNL/glyphon.git", rev = "20f0f8fa80e0d0df4c63634ce9176fa489546ca9" } +guillotiere = "0.6" +half = "2.2" +image = "0.24" +instant = "0.1" +kamadak-exif = "0.5" +kurbo = "0.9" +log = "0.4" +lyon = "1.0" +lyon_path = "1.0" +num-traits = "0.2" +once_cell = "1.0" +ouroboros = "0.17" +palette = "0.7" +qrcode = { version = "0.12", default-features = false } +raw-window-handle = "0.5" +resvg = "0.35" +rustc-hash = "1.0" +smol = "1.0" +softbuffer = "0.2" +sysinfo = "0.28" +thiserror = "1.0" +tiny-skia = "0.10" +tokio = "1.0" +tracing = "0.1" +twox-hash = { version = "1.0", default-features = false } +unicode-segmentation = "1.0" +wasm-bindgen-futures = "0.4" +wasm-timer = "0.2" +web-sys = "0.3" +wgpu = "0.17" +winapi = "0.3" +window_clipboard = "0.3" +winit = { git = "https://github.com/iced-rs/winit.git", rev = "c52db2045d0a2f1b8d9923870de1d4ab1994146e", default-features = false } @@ -15,11 +15,11 @@ A cross-platform GUI library for Rust focused on simplicity and type-safety. Inspired by [Elm]. -<a href="https://gfycat.com/littlesanehalicore"> - <img src="https://thumbs.gfycat.com/LittleSaneHalicore-small.gif" width="275px"> +<a href="https://iced.rs/examples/todos.mp4"> + <img src="https://iced.rs/examples/todos.gif" width="275px"> </a> -<a href="https://gfycat.com/politeadorableiberianmole"> - <img src="https://thumbs.gfycat.com/PoliteAdorableIberianmole-small.gif" width="273px"> +<a href="https://iced.rs/examples/tour.mp4"> + <img src="https://iced.rs/examples/tour.gif" width="273px"> </a> </div> @@ -47,9 +47,9 @@ __Iced is currently experimental software.__ [Take a look at the roadmap], [Cross-platform support]: https://raw.githubusercontent.com/iced-rs/iced/master/docs/images/todos_desktop.jpg [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 +[text inputs]: https://iced.rs/examples/text_input.mp4 +[scrollables]: https://iced.rs/examples/scrollable.mp4 +[Debug overlay with performance metrics]: https://iced.rs/examples/debug.mp4 [Modular ecosystem]: ECOSYSTEM.md [renderer-agnostic native runtime]: runtime/ [`wgpu`]: https://github.com/gfx-rs/wgpu diff --git a/clippy.toml b/clippy.toml index 0d4e02f0..02f00a06 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1 +1,2 @@ too-many-arguments-threshold = 20 +enum-variant-name-threshold = 10 diff --git a/core/Cargo.toml b/core/Cargo.toml index 8bb37309..7acb7511 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,24 +1,27 @@ [package] name = "iced_core" -version = "0.10.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "The essential concepts of Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" +description = "The essential ideas of iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [dependencies] -bitflags = "1.2" -thiserror = "1" -log = "0.4.17" -twox-hash = { version = "1.5", default-features = false } +bitflags.workspace = true +log.workspace = true +thiserror.workspace = true +twox-hash.workspace = true +num-traits.workspace = true -[dependencies.palette] -version = "0.7" -optional = true +palette.workspace = true +palette.optional = true [target.'cfg(target_arch = "wasm32")'.dependencies] -instant = "0.1" +instant.workspace = true [dev-dependencies] approx = "0.5" diff --git a/core/src/angle.rs b/core/src/angle.rs index 75a57c76..102b69cf 100644 --- a/core/src/angle.rs +++ b/core/src/angle.rs @@ -1,32 +1,72 @@ use crate::{Point, Rectangle, Vector}; -use std::f32::consts::PI; -#[derive(Debug, Copy, Clone, PartialEq)] +use std::f32::consts::{FRAC_PI_2, PI}; +use std::ops::RangeInclusive; + /// Degrees +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub struct Degrees(pub f32); -#[derive(Debug, Copy, Clone, PartialEq)] /// Radians +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub struct Radians(pub f32); +impl Radians { + /// The range of radians of a circle. + pub const RANGE: RangeInclusive<Radians> = Radians(0.0)..=Radians(2.0 * PI); +} + impl From<Degrees> for Radians { fn from(degrees: Degrees) -> Self { - Radians(degrees.0 * PI / 180.0) + Self(degrees.0 * PI / 180.0) + } +} + +impl From<f32> for Radians { + fn from(radians: f32) -> Self { + Self(radians) + } +} + +impl From<u8> for Radians { + fn from(radians: u8) -> Self { + Self(f32::from(radians)) + } +} + +impl From<Radians> for f64 { + fn from(radians: Radians) -> Self { + Self::from(radians.0) + } +} + +impl num_traits::FromPrimitive for Radians { + fn from_i64(n: i64) -> Option<Self> { + Some(Self(n as f32)) + } + + fn from_u64(n: u64) -> Option<Self> { + Some(Self(n as f32)) + } + + fn from_f64(n: f64) -> Option<Self> { + Some(Self(n as f32)) } } impl Radians { - /// Calculates the line in which the [`Angle`] intercepts the `bounds`. + /// Calculates the line in which the angle intercepts the `bounds`. pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) { - let v1 = Vector::new(f32::cos(self.0), f32::sin(self.0)); + let angle = self.0 - FRAC_PI_2; + let r = Vector::new(f32::cos(angle), f32::sin(angle)); - let distance_to_rect = f32::min( - f32::abs((bounds.y - bounds.center().y) / v1.y), - f32::abs(((bounds.x + bounds.width) - bounds.center().x) / v1.x), + let distance_to_rect = f32::max( + f32::abs(r.x * bounds.width / 2.0), + f32::abs(r.y * bounds.height / 2.0), ); - let start = bounds.center() + v1 * distance_to_rect; - let end = bounds.center() - v1 * distance_to_rect; + let start = bounds.center() - r * distance_to_rect; + let end = bounds.center() + r * distance_to_rect; (start, end) } diff --git a/core/src/gradient.rs b/core/src/gradient.rs index e19622fb..4a0d5ea0 100644 --- a/core/src/gradient.rs +++ b/core/src/gradient.rs @@ -6,10 +6,8 @@ use std::cmp::Ordering; #[derive(Debug, Clone, Copy, PartialEq)] /// A fill which transitions colors progressively along a direction, either linearly, radially (TBD), /// or conically (TBD). -/// -/// For a gradient which can be used as a fill on a canvas, see [`iced_graphics::Gradient`]. pub enum Gradient { - /// A linear gradient interpolates colors along a direction at a specific [`Angle`]. + /// A linear gradient interpolates colors along a direction at a specific angle. Linear(Linear), } diff --git a/core/src/lib.rs b/core/src/lib.rs index c1c8424b..1bfba7bd 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -9,6 +9,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -17,9 +18,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(unsafe_code, rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] pub mod alignment; pub mod clipboard; diff --git a/core/src/shell.rs b/core/src/shell.rs index 74a5c616..246c937a 100644 --- a/core/src/shell.rs +++ b/core/src/shell.rs @@ -35,7 +35,7 @@ impl<'a, Message> Shell<'a, Message> { self.messages.push(message); } - /// Requests a new frame to be drawn at the given [`Instant`]. + /// Requests a new frame to be drawn. pub fn request_redraw(&mut self, request: window::RedrawRequest) { match self.redraw_request { None => { @@ -48,7 +48,7 @@ impl<'a, Message> Shell<'a, Message> { } } - /// Returns the requested [`Instant`] a redraw should happen, if any. + /// Returns the request a redraw should happen, if any. pub fn redraw_request(&self) -> Option<window::RedrawRequest> { self.redraw_request } diff --git a/core/src/window/icon.rs b/core/src/window/icon.rs index 31868ecf..2fc48e3b 100644 --- a/core/src/window/icon.rs +++ b/core/src/window/icon.rs @@ -49,7 +49,7 @@ impl Icon { } #[derive(Debug, thiserror::Error)] -/// An error produced when using [`Icon::from_rgba`] with invalid arguments. +/// An error produced when using [`from_rgba`] with invalid arguments. pub enum Error { /// Produced when the length of the `rgba` argument isn't divisible by 4, thus `rgba` can't be /// safely interpreted as 32bpp RGBA pixels. diff --git a/core/src/window/redraw_request.rs b/core/src/window/redraw_request.rs index 3b4f0fd3..8a59e83c 100644 --- a/core/src/window/redraw_request.rs +++ b/core/src/window/redraw_request.rs @@ -13,7 +13,7 @@ pub enum RedrawRequest { #[cfg(test)] mod tests { use super::*; - use std::time::{Duration, Instant}; + use crate::time::{Duration, Instant}; #[test] fn ordering() { diff --git a/examples/README.md b/examples/README.md index 111e8910..71dad13e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,8 +10,8 @@ A simple UI tour that can run both on native platforms and the web! It showcases The __[`main`](tour/src/main.rs)__ file contains all the code of the example! All the cross-platform GUI is defined in terms of __state__, __messages__, __update logic__ and __view logic__. <div align="center"> - <a href="https://gfycat.com/politeadorableiberianmole"> - <img src="https://thumbs.gfycat.com/PoliteAdorableIberianmole-small.gif"> + <a href="https://iced.rs/examples/tour.mp4"> + <img src="https://iced.rs/examples/tour.gif"> </a> </div> @@ -33,8 +33,8 @@ A todos tracker inspired by [TodoMVC]. It showcases dynamic layout, text input, The example code is located in the __[`main`](todos/src/main.rs)__ file. <div align="center"> - <a href="https://gfycat.com/littlesanehalicore"> - <img src="https://thumbs.gfycat.com/LittleSaneHalicore-small.gif" height="400px"> + <a href="https://iced.rs/examples/todos.mp4"> + <img src="https://iced.rs/examples/todos.gif" height="400px"> </a> </div> @@ -53,9 +53,7 @@ It runs a simulation in a background thread while allowing interaction with a `C The relevant code is located in the __[`main`](game_of_life/src/main.rs)__ file. <div align="center"> - <a href="https://gfycat.com/briefaccurateaardvark"> - <img src="https://thumbs.gfycat.com/BriefAccurateAardvark-size_restricted.gif"> - </a> + <img src="https://iced.rs/examples/game_of_life.gif"> </div> You can run it with `cargo run`: @@ -72,9 +70,7 @@ An example showcasing custom styling with a light and dark theme. The example code is located in the __[`main`](styling/src/main.rs)__ file. <div align="center"> - <a href="https://user-images.githubusercontent.com/518289/71867993-acff4300-310c-11ea-85a3-d01d8f884346.gif"> - <img src="https://user-images.githubusercontent.com/518289/71867993-acff4300-310c-11ea-85a3-d01d8f884346.gif" height="400px"> - </a> + <img src="https://iced.rs/examples/styling.gif"> </div> You can run it with `cargo run`: @@ -120,9 +116,7 @@ Since [Iced was born in May 2019], it has been powering the user interfaces in <div align="center"> - <a href="https://gfycat.com/gloomyweakhammerheadshark"> - <img src="https://thumbs.gfycat.com/GloomyWeakHammerheadshark-small.gif"> - </a> + <img src="https://iced.rs/examples/coffee.gif"> </div> [Iced was born in May 2019]: https://github.com/hecrj/coffee/pull/35 diff --git a/examples/arc/Cargo.toml b/examples/arc/Cargo.toml index e6e74363..5012ff82 100644 --- a/examples/arc/Cargo.toml +++ b/examples/arc/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "tokio", "debug"] } +iced.workspace = true +iced.features = ["canvas", "tokio", "debug"] diff --git a/examples/bezier_tool/Cargo.toml b/examples/bezier_tool/Cargo.toml index 890e3027..b2547ff1 100644 --- a/examples/bezier_tool/Cargo.toml +++ b/examples/bezier_tool/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas"] } +iced.workspace = true +iced.features = ["canvas"] diff --git a/examples/bezier_tool/README.md b/examples/bezier_tool/README.md index ebbb12cc..6dc13785 100644 --- a/examples/bezier_tool/README.md +++ b/examples/bezier_tool/README.md @@ -5,9 +5,7 @@ A Paint-like tool for drawing Bézier curves using the `Canvas` widget. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/soulfulinfiniteantbear"> - <img src="https://thumbs.gfycat.com/SoulfulInfiniteAntbear-small.gif"> - </a> + <img src="https://iced.rs/examples/bezier_tool.gif"> </div> You can run it with `cargo run`: diff --git a/examples/checkbox/Cargo.toml b/examples/checkbox/Cargo.toml index dde8f910..1e027c4c 100644 --- a/examples/checkbox/Cargo.toml +++ b/examples/checkbox/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/clock/Cargo.toml b/examples/clock/Cargo.toml index 5e869eb5..2d3d5908 100644 --- a/examples/clock/Cargo.toml +++ b/examples/clock/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "tokio", "debug"] } -time = { version = "0.3.5", features = ["local-offset"] } +iced.workspace = true +iced.features = ["canvas", "tokio", "debug"] + +time = { version = "0.3", features = ["local-offset"] } diff --git a/examples/color_palette/Cargo.toml b/examples/color_palette/Cargo.toml index 3be732bb..2da6c6ed 100644 --- a/examples/color_palette/Cargo.toml +++ b/examples/color_palette/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "palette"] } -palette = "0.7.0" +iced.workspace = true +iced.features = ["canvas", "palette"] + +palette.workspace = true diff --git a/examples/color_palette/README.md b/examples/color_palette/README.md index f90020b1..9c135937 100644 --- a/examples/color_palette/README.md +++ b/examples/color_palette/README.md @@ -3,13 +3,11 @@ A color palette generator, based on a user-defined root color. <div align="center"> - <a href="https://gfycat.com/dirtylonebighornsheep"> - <img src="screenshot.png"> - </a> + <img src="screenshot.png"> </div> You can run it with `cargo run`: ``` -cargo run --package pure_color_palette +cargo run --package color_palette ``` diff --git a/examples/combo_box/Cargo.toml b/examples/combo_box/Cargo.toml index be1b5e32..0f5ecf2a 100644 --- a/examples/combo_box/Cargo.toml +++ b/examples/combo_box/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } +iced.workspace = true +iced.features = ["debug"] diff --git a/examples/component/Cargo.toml b/examples/component/Cargo.toml index 9db1e6b4..83b7b8a4 100644 --- a/examples/component/Cargo.toml +++ b/examples/component/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug", "lazy"] } +iced.workspace = true +iced.features = ["debug", "lazy"] diff --git a/examples/counter/Cargo.toml b/examples/counter/Cargo.toml index e31f440f..22f86064 100644 --- a/examples/counter/Cargo.toml +++ b/examples/counter/Cargo.toml @@ -6,4 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dependencies] +iced.workspace = true +iced.features = ["webgl"] diff --git a/examples/counter/README.md b/examples/counter/README.md index 4d9fc5b9..18761bba 100644 --- a/examples/counter/README.md +++ b/examples/counter/README.md @@ -5,9 +5,7 @@ The classic counter example explained in the [`README`](../../README.md). The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/fairdeadcatbird"> - <img src="https://thumbs.gfycat.com/FairDeadCatbird-small.gif"> - </a> + <img src="https://iced.rs/examples/counter.gif"> </div> You can run it with `cargo run`: @@ -15,4 +13,12 @@ You can run it with `cargo run`: cargo run --package counter ``` +The web version can be run with [`trunk`]: + +``` +cd examples/counter +trunk serve +``` + [`main`]: src/main.rs +[`trunk`]: https://trunkrs.dev/ diff --git a/examples/custom_quad/Cargo.toml b/examples/custom_quad/Cargo.toml index f097c2dd..31b5055d 100644 --- a/examples/custom_quad/Cargo.toml +++ b/examples/custom_quad/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced"] } +iced.workspace = true +iced.features = ["advanced"] diff --git a/examples/custom_widget/Cargo.toml b/examples/custom_widget/Cargo.toml index dda0efe8..1e94bc52 100644 --- a/examples/custom_widget/Cargo.toml +++ b/examples/custom_widget/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced"] } +iced.workspace = true +iced.features = ["advanced"] diff --git a/examples/custom_widget/README.md b/examples/custom_widget/README.md index 3d6cf902..b80e898f 100644 --- a/examples/custom_widget/README.md +++ b/examples/custom_widget/README.md @@ -5,9 +5,7 @@ A demonstration of how to build a custom widget that draws a circle. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/jealouscornyhomalocephale"> - <img src="https://thumbs.gfycat.com/JealousCornyHomalocephale-small.gif"> - </a> + <img src="https://iced.rs/examples/custom_widget.gif"> </div> You can run it with `cargo run`: diff --git a/examples/download_progress/Cargo.toml b/examples/download_progress/Cargo.toml index 212832f4..18a49f66 100644 --- a/examples/download_progress/Cargo.toml +++ b/examples/download_progress/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["tokio"] } +iced.workspace = true +iced.features = ["tokio"] [dependencies.reqwest] version = "0.11" diff --git a/examples/download_progress/README.md b/examples/download_progress/README.md index 7999ce94..19cb2966 100644 --- a/examples/download_progress/README.md +++ b/examples/download_progress/README.md @@ -5,9 +5,7 @@ A basic application that asynchronously downloads multiple dummy files of 100 MB The example implements a custom `Subscription` in the __[`download`](src/download.rs)__ module. This subscription downloads and produces messages that can be used to keep track of its progress. <div align="center"> - <a href="https://gfycat.com/wildearlyafricanwilddog"> - <img src="https://thumbs.gfycat.com/WildEarlyAfricanwilddog-small.gif"> - </a> + <img src="https://iced.rs/examples/download_progress.gif"> </div> You can run it with `cargo run`: diff --git a/examples/events/Cargo.toml b/examples/events/Cargo.toml index 15ffc0af..87315a10 100644 --- a/examples/events/Cargo.toml +++ b/examples/events/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } +iced.workspace = true +iced.features = ["debug"] diff --git a/examples/events/README.md b/examples/events/README.md index 3c9a1cab..fd7f9b47 100644 --- a/examples/events/README.md +++ b/examples/events/README.md @@ -4,12 +4,6 @@ A log of native events displayed using a conditional `Subscription`. The __[`main`]__ file contains all the code of the example. -<div align="center"> - <a href="https://gfycat.com/infamousicyermine"> - <img src="https://thumbs.gfycat.com/InfamousIcyErmine-small.gif"> - </a> -</div> - You can run it with `cargo run`: ``` cargo run --package events diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 7f3a5e1d..32d0da2c 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -1,9 +1,8 @@ use iced::alignment; +use iced::event::{self, Event}; use iced::executor; -use iced::subscription; use iced::widget::{button, checkbox, container, text, Column}; use iced::window; -use iced::Event; use iced::{ Alignment, Application, Command, Element, Length, Settings, Subscription, Theme, @@ -71,7 +70,7 @@ impl Application for Events { } fn subscription(&self) -> Subscription<Message> { - subscription::events().map(Message::EventOccurred) + event::listen().map(Message::EventOccurred) } fn view(&self) -> Element<Message> { diff --git a/examples/exit/Cargo.toml b/examples/exit/Cargo.toml index 34d0789a..b06fbadc 100644 --- a/examples/exit/Cargo.toml +++ b/examples/exit/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/game_of_life/Cargo.toml b/examples/game_of_life/Cargo.toml index 6de45db6..9b291de8 100644 --- a/examples/game_of_life/Cargo.toml +++ b/examples/game_of_life/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "tokio", "debug"] } -tokio = { version = "1.0", features = ["sync"] } -itertools = "0.9" -rustc-hash = "1.1" -env_logger = "0.10" +iced.workspace = true +iced.features = ["debug", "canvas", "tokio"] + +itertools = "0.11" +rustc-hash.workspace = true +tokio = { workspace = true, features = ["sync"] } +tracing-subscriber = "0.3" diff --git a/examples/game_of_life/README.md b/examples/game_of_life/README.md index aa39201c..60033c1a 100644 --- a/examples/game_of_life/README.md +++ b/examples/game_of_life/README.md @@ -7,9 +7,7 @@ It runs a simulation in a background thread while allowing interaction with a `C The __[`main`]__ file contains the relevant code of the example. <div align="center"> - <a href="https://gfycat.com/WhichPaltryChick"> - <img src="https://thumbs.gfycat.com/WhichPaltryChick-size_restricted.gif"> - </a> + <img src="https://iced.rs/examples/game_of_life.gif"> </div> You can run it with `cargo run`: diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index fa711744..e451cb06 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -18,7 +18,7 @@ use iced::{ use std::time::{Duration, Instant}; pub fn main() -> iced::Result { - env_logger::builder().format_timestamp(None).init(); + tracing_subscriber::fmt::init(); GameOfLife::run(Settings { antialiasing: true, @@ -550,7 +550,7 @@ mod grid { frame.translate(center); frame.scale(self.scaling); frame.translate(self.translation); - frame.scale(Cell::SIZE as f32); + frame.scale(Cell::SIZE); let region = self.visible_region(frame.size()); @@ -576,7 +576,7 @@ mod grid { frame.translate(center); frame.scale(self.scaling); frame.translate(self.translation); - frame.scale(Cell::SIZE as f32); + frame.scale(Cell::SIZE); frame.fill_rectangle( Point::new(cell.j as f32, cell.i as f32), @@ -630,7 +630,7 @@ mod grid { frame.translate(center); frame.scale(self.scaling); frame.translate(self.translation); - frame.scale(Cell::SIZE as f32); + frame.scale(Cell::SIZE); let region = self.visible_region(frame.size()); let rows = region.rows(); @@ -834,7 +834,7 @@ mod grid { } impl Cell { - const SIZE: usize = 20; + const SIZE: u16 = 20; fn at(position: Point) -> Cell { let i = (position.y / Cell::SIZE as f32).ceil() as isize; diff --git a/examples/geometry/Cargo.toml b/examples/geometry/Cargo.toml index 6068d651..9606dcb3 100644 --- a/examples/geometry/Cargo.toml +++ b/examples/geometry/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced"] } +iced.workspace = true +iced.features = ["advanced"] diff --git a/examples/geometry/README.md b/examples/geometry/README.md index 4d5c81cb..16be8d19 100644 --- a/examples/geometry/README.md +++ b/examples/geometry/README.md @@ -5,9 +5,7 @@ A custom widget showcasing how to draw geometry with the `Mesh2D` primitive in [ The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/activeunfitkangaroo"> - <img src="https://thumbs.gfycat.com/ActiveUnfitKangaroo-small.gif"> - </a> + <img src="https://iced.rs/examples/geometry.gif"> </div> You can run it with `cargo run`: diff --git a/examples/gradient/Cargo.toml b/examples/gradient/Cargo.toml new file mode 100644 index 00000000..2dea2c4f --- /dev/null +++ b/examples/gradient/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "gradient" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../.." } diff --git a/examples/gradient/src/main.rs b/examples/gradient/src/main.rs new file mode 100644 index 00000000..1bf5822d --- /dev/null +++ b/examples/gradient/src/main.rs @@ -0,0 +1,99 @@ +use iced::gradient; +use iced::widget::{column, container, horizontal_space, row, slider, text}; +use iced::{ + Alignment, Background, Color, Element, Length, Radians, Sandbox, Settings, +}; + +pub fn main() -> iced::Result { + Gradient::run(Settings::default()) +} + +#[derive(Debug, Clone, Copy)] +struct Gradient { + start: Color, + end: Color, + angle: Radians, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + StartChanged(Color), + EndChanged(Color), + AngleChanged(Radians), +} + +impl Sandbox for Gradient { + type Message = Message; + + fn new() -> Self { + Self { + start: Color::WHITE, + end: Color::new(0.0, 0.0, 1.0, 1.0), + angle: Radians(0.0), + } + } + + fn title(&self) -> String { + String::from("Gradient") + } + + fn update(&mut self, message: Message) { + match message { + Message::StartChanged(color) => self.start = color, + Message::EndChanged(color) => self.end = color, + Message::AngleChanged(angle) => self.angle = angle, + } + } + + fn view(&self) -> Element<Message> { + let Self { start, end, angle } = *self; + + let gradient_box = container(horizontal_space(Length::Fill)) + .width(Length::Fill) + .height(Length::Fill) + .style(move |_: &_| { + let gradient = gradient::Linear::new(angle) + .add_stop(0.0, start) + .add_stop(1.0, end) + .into(); + + container::Appearance { + background: Some(Background::Gradient(gradient)), + ..Default::default() + } + }); + + let angle_picker = row![ + text("Angle").width(64), + slider(Radians::RANGE, self.angle, Message::AngleChanged) + .step(0.01) + ] + .spacing(8) + .padding(8) + .align_items(Alignment::Center); + + column![ + color_picker("Start", self.start).map(Message::StartChanged), + color_picker("End", self.end).map(Message::EndChanged), + angle_picker, + gradient_box + ] + .into() + } +} + +fn color_picker(label: &str, color: Color) -> Element<'_, Color> { + row![ + text(label).width(64), + slider(0.0..=1.0, color.r, move |r| { Color { r, ..color } }) + .step(0.01), + slider(0.0..=1.0, color.g, move |g| { Color { g, ..color } }) + .step(0.01), + slider(0.0..=1.0, color.b, move |b| { Color { b, ..color } }) + .step(0.01), + ] + .spacing(8) + .padding(8) + .align_items(Alignment::Center) + .into() +} diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml index 22914742..a4a961f8 100644 --- a/examples/integration/Cargo.toml +++ b/examples/integration/Cargo.toml @@ -6,19 +6,18 @@ edition = "2021" publish = false [dependencies] -iced_winit = { path = "../../winit" } -iced_wgpu = { path = "../../wgpu" } -iced_widget = { path = "../../widget" } -iced_renderer = { path = "../../renderer", features = ["wgpu"] } -env_logger = "0.10" +iced_winit.workspace = true +iced_wgpu.workspace = true +iced_widget.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tracing-subscriber = "0.3" [target.'cfg(target_arch = "wasm32")'.dependencies] -console_error_panic_hook = "0.1.7" -console_log = "0.2.0" -log = "0.4" +iced_wgpu.workspace = true +iced_wgpu.features = ["webgl"] + +console_error_panic_hook = "0.1" +console_log = "1.0" wasm-bindgen = "0.2" web-sys = { version = "0.3", features = ["Element", "HtmlCanvasElement", "Window", "Document"] } -# This dependency a little bit quirky, it is deep in the tree and without `js` feature it -# refuses to work with `wasm32-unknown-unknown target`. Unfortunately, we need this patch -# to make it work -getrandom = { version = "0.2", features = ["js"] } diff --git a/examples/integration/README.md b/examples/integration/README.md index ece9ba1e..996cdc17 100644 --- a/examples/integration/README.md +++ b/examples/integration/README.md @@ -5,9 +5,7 @@ A demonstration of how to integrate Iced in an existing [`wgpu`] application. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/nicemediocrekodiakbear"> - <img src="https://thumbs.gfycat.com/NiceMediocreKodiakbear-small.gif"> - </a> + <img src="https://iced.rs/examples/integration.gif"> </div> You can run it with `cargo run`: diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs index e011a411..7945bd20 100644 --- a/examples/integration/src/main.rs +++ b/examples/integration/src/main.rs @@ -29,7 +29,7 @@ use winit::platform::web::WindowBuilderExtWebSys; pub fn main() -> Result<(), Box<dyn std::error::Error>> { #[cfg(target_arch = "wasm32")] let canvas_element = { - console_log::init_with_level(log::Level::Debug)?; + console_log::init().expect("Initialize logger"); std::panic::set_hook(Box::new(console_error_panic_hook::hook)); @@ -41,7 +41,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> { }; #[cfg(not(target_arch = "wasm32"))] - env_logger::init(); + tracing_subscriber::fmt::init(); // Initialize winit let event_loop = EventLoop::new(); @@ -82,7 +82,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> { futures::futures::executor::block_on(async { let adapter = wgpu::util::initialize_adapter_from_env_or_default( &instance, - backend, Some(&surface), ) .await diff --git a/examples/lazy/Cargo.toml b/examples/lazy/Cargo.toml index e03e89a9..4ccb9584 100644 --- a/examples/lazy/Cargo.toml +++ b/examples/lazy/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug", "lazy"] } +iced.workspace = true +iced.features = ["debug", "lazy"] diff --git a/examples/loading_spinners/Cargo.toml b/examples/loading_spinners/Cargo.toml index ee9a48aa..a32da386 100644 --- a/examples/loading_spinners/Cargo.toml +++ b/examples/loading_spinners/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced", "canvas"] } -lyon_algorithms = "1" -once_cell = "1" +iced.workspace = true +iced.features = ["advanced", "canvas"] + +lyon_algorithms = "1.0" +once_cell.workspace = true
\ No newline at end of file diff --git a/examples/loading_spinners/README.md b/examples/loading_spinners/README.md index 3573c6f6..75b88804 100644 --- a/examples/loading_spinners/README.md +++ b/examples/loading_spinners/README.md @@ -2,12 +2,6 @@ Example implementation of animated indeterminate loading spinners. -<div align="center"> - <a href="https://gfycat.com/importantdevotedhammerheadbird"> - <img src="https://thumbs.gfycat.com/ImportantDevotedHammerheadbird-small.gif"> - </a> -</div> - You can run it with `cargo run`: ``` cargo run --package loading_spinners diff --git a/examples/modal/Cargo.toml b/examples/modal/Cargo.toml index 3ac61e6a..009d9653 100644 --- a/examples/modal/Cargo.toml +++ b/examples/modal/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced"] } +iced.workspace = true +iced.features = ["advanced"] diff --git a/examples/modal/src/main.rs b/examples/modal/src/main.rs index aa9107d0..c050d3cc 100644 --- a/examples/modal/src/main.rs +++ b/examples/modal/src/main.rs @@ -1,12 +1,14 @@ +use iced::event::{self, Event}; use iced::executor; use iced::keyboard; -use iced::subscription::{self, Subscription}; use iced::theme; use iced::widget::{ self, button, column, container, horizontal_space, pick_list, row, text, text_input, }; -use iced::{Alignment, Application, Command, Element, Event, Length, Settings}; +use iced::{ + Alignment, Application, Command, Element, Length, Settings, Subscription, +}; use modal::Modal; use std::fmt; @@ -49,7 +51,7 @@ impl Application for App { } fn subscription(&self) -> Subscription<Self::Message> { - subscription::events().map(Message::Event) + event::listen().map(Message::Event) } fn update(&mut self, message: Message) -> Command<Message> { diff --git a/examples/multitouch/Cargo.toml b/examples/multitouch/Cargo.toml index 867312f8..e0d14f58 100644 --- a/examples/multitouch/Cargo.toml +++ b/examples/multitouch/Cargo.toml @@ -6,7 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "tokio", "debug"] } -tokio = { version = "1.0", features = ["sync"] } -env_logger = "0.10" +iced.workspace = true +iced.features = ["debug", "canvas", "tokio"] + +tracing-subscriber = "0.3" voronator = "0.2" diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs index 2830b78d..ba8df7aa 100644 --- a/examples/multitouch/src/main.rs +++ b/examples/multitouch/src/main.rs @@ -13,7 +13,7 @@ use iced::{ use std::collections::HashMap; pub fn main() -> iced::Result { - env_logger::builder().format_timestamp(None).init(); + tracing_subscriber::fmt::init(); Multitouch::run(Settings { antialiasing: true, diff --git a/examples/pane_grid/Cargo.toml b/examples/pane_grid/Cargo.toml index 4c0bf072..095ecd10 100644 --- a/examples/pane_grid/Cargo.toml +++ b/examples/pane_grid/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug", "lazy"] } +iced.workspace = true +iced.features = ["debug", "lazy"] diff --git a/examples/pane_grid/README.md b/examples/pane_grid/README.md index a4cfcb7d..65357b23 100644 --- a/examples/pane_grid/README.md +++ b/examples/pane_grid/README.md @@ -15,9 +15,7 @@ This example showcases the `PaneGrid` widget, which features: The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/frailfreshairedaleterrier"> - <img src="https://thumbs.gfycat.com/FrailFreshAiredaleterrier-small.gif"> - </a> + <img src="https://iced.rs/examples/pane_grid.gif"> </div> You can run it with `cargo run`: diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index 04896e20..af87e2c0 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -1,8 +1,6 @@ use iced::alignment::{self, Alignment}; -use iced::event::{self, Event}; use iced::executor; use iced::keyboard; -use iced::subscription; use iced::theme::{self, Theme}; use iced::widget::pane_grid::{self, PaneGrid}; use iced::widget::{ @@ -146,18 +144,12 @@ impl Application for Example { } fn subscription(&self) -> Subscription<Message> { - subscription::events_with(|event, status| { - if let event::Status::Captured = status { + keyboard::on_key_press(|key_code, modifiers| { + if !modifiers.command() { return None; } - match event { - Event::Keyboard(keyboard::Event::KeyPressed { - modifiers, - key_code, - }) if modifiers.command() => handle_hotkey(key_code), - _ => None, - } + handle_hotkey(key_code) }) } diff --git a/examples/pick_list/Cargo.toml b/examples/pick_list/Cargo.toml index 4aa4603a..030558e7 100644 --- a/examples/pick_list/Cargo.toml +++ b/examples/pick_list/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } +iced.workspace = true +iced.features = ["debug"] diff --git a/examples/pokedex/Cargo.toml b/examples/pokedex/Cargo.toml index e99fc0c3..bf7e1e35 100644 --- a/examples/pokedex/Cargo.toml +++ b/examples/pokedex/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["image", "debug", "tokio"] } +iced.workspace = true +iced.features = ["image", "debug", "tokio"] + serde_json = "1.0" [dependencies.serde] @@ -19,5 +21,8 @@ default-features = false features = ["json", "rustls-tls"] [dependencies.rand] -version = "0.7" -features = ["wasm-bindgen"] +version = "0.8" + +[dependencies.getrandom] +version = "0.2" +features = ["js"] diff --git a/examples/pokedex/README.md b/examples/pokedex/README.md index 50720f57..8e8562ac 100644 --- a/examples/pokedex/README.md +++ b/examples/pokedex/README.md @@ -4,9 +4,7 @@ An application that loads a random Pokédex entry using the [PokéAPI]. All the example code can be found in the __[`main`](src/main.rs)__ file. <div align="center"> - <a href="https://gfycat.com/aggressivedarkelephantseal-rust-gui"> - <img src="https://thumbs.gfycat.com/AggressiveDarkElephantseal-small.gif" height="400px"> - </a> + <img src="https://iced.rs/examples/pokedex.gif"> </div> You can run it on native platforms with `cargo run`: diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs index 4482814c..8b71a269 100644 --- a/examples/pokedex/src/main.rs +++ b/examples/pokedex/src/main.rs @@ -153,7 +153,7 @@ impl Pokemon { let id = { let mut rng = rand::rngs::OsRng; - rng.gen_range(0, Pokemon::TOTAL) + rng.gen_range(0..Pokemon::TOTAL) }; let fetch_entry = async { diff --git a/examples/progress_bar/Cargo.toml b/examples/progress_bar/Cargo.toml index 383a9bdd..6624ae15 100644 --- a/examples/progress_bar/Cargo.toml +++ b/examples/progress_bar/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/progress_bar/README.md b/examples/progress_bar/README.md index 1e927b3c..1268ac6b 100644 --- a/examples/progress_bar/README.md +++ b/examples/progress_bar/README.md @@ -5,9 +5,7 @@ A simple progress bar that can be filled by using a slider. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/importantdevotedhammerheadbird"> - <img src="https://thumbs.gfycat.com/ImportantDevotedHammerheadbird-small.gif"> - </a> + <img src="https://iced.rs/examples/pokedex.gif"> </div> You can run it with `cargo run`: diff --git a/examples/qr_code/Cargo.toml b/examples/qr_code/Cargo.toml index 2f164df6..8f33ea8c 100644 --- a/examples/qr_code/Cargo.toml +++ b/examples/qr_code/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["qr_code"] } +iced.workspace = true +iced.features = ["qr_code"] diff --git a/examples/qr_code/README.md b/examples/qr_code/README.md index 2dd89c26..0d1abaa7 100644 --- a/examples/qr_code/README.md +++ b/examples/qr_code/README.md @@ -5,9 +5,7 @@ A basic QR code generator that showcases the `QRCode` widget. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/heavyexhaustedaracari"> - <img src="https://thumbs.gfycat.com/HeavyExhaustedAracari-size_restricted.gif"> - </a> + <img src="https://iced.rs/examples/qr_code.gif"> </div> You can run it with `cargo run`: diff --git a/examples/screenshot/Cargo.toml b/examples/screenshot/Cargo.toml index b79300b7..dcd77439 100644 --- a/examples/screenshot/Cargo.toml +++ b/examples/screenshot/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug", "image", "advanced"] } -image = { version = "0.24.6", features = ["png"]} -env_logger = "0.10.0" +iced.workspace = true +iced.features = ["debug", "image", "advanced"] + +image = { workspace = true, features = ["png"]} +tracing-subscriber = "0.3"
\ No newline at end of file diff --git a/examples/screenshot/src/main.rs b/examples/screenshot/src/main.rs index 83824535..68c9d031 100644 --- a/examples/screenshot/src/main.rs +++ b/examples/screenshot/src/main.rs @@ -4,16 +4,15 @@ use iced::theme::{Button, Container}; use iced::widget::{button, column, container, image, row, text, text_input}; use iced::window::screenshot::{self, Screenshot}; use iced::{ - event, executor, keyboard, subscription, Alignment, Application, Command, - ContentFit, Element, Event, Length, Rectangle, Renderer, Subscription, - Theme, + event, executor, keyboard, Alignment, Application, Command, ContentFit, + Element, Event, Length, Rectangle, Renderer, Subscription, Theme, }; use ::image as img; use ::image::ColorType; fn main() -> iced::Result { - env_logger::builder().format_timestamp(None).init(); + tracing_subscriber::fmt::init(); Example::run(iced::Settings::default()) } @@ -254,7 +253,7 @@ impl Application for Example { } fn subscription(&self) -> Subscription<Self::Message> { - subscription::events_with(|event, status| { + event::listen_with(|event, status| { if let event::Status::Captured = status { return None; } diff --git a/examples/scrollable/Cargo.toml b/examples/scrollable/Cargo.toml index e6411e26..f8c735c0 100644 --- a/examples/scrollable/Cargo.toml +++ b/examples/scrollable/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } -once_cell = "1.16.0" +iced.workspace = true +iced.features = ["debug"] + +once_cell.workspace = true diff --git a/examples/sierpinski_triangle/Cargo.toml b/examples/sierpinski_triangle/Cargo.toml index 39d45f64..600a9e06 100644 --- a/examples/sierpinski_triangle/Cargo.toml +++ b/examples/sierpinski_triangle/Cargo.toml @@ -6,5 +6,7 @@ edition = "2018" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "debug"] } -rand = "0.8.4" +iced.workspace = true +iced.features = ["debug", "canvas"] + +rand = "0.8" diff --git a/examples/sierpinski_triangle/README.md b/examples/sierpinski_triangle/README.md index 9fd18257..8b7676d1 100644 --- a/examples/sierpinski_triangle/README.md +++ b/examples/sierpinski_triangle/README.md @@ -5,9 +5,7 @@ A simple [Sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_tr Left-click add fixed point, right-click remove fixed point. <div align="center"> - <a href="https://gfycat.com/flippantrectangularechidna"> - <img src="https://thumbs.gfycat.com/FlippantRectangularEchidna-size_restricted.gif"> - </a> + <img src="https://iced.rs/examples/sierpinski_triangle.gif"> </div> You can run with cargo: diff --git a/examples/slider/Cargo.toml b/examples/slider/Cargo.toml index 112d7cff..fad8916e 100644 --- a/examples/slider/Cargo.toml +++ b/examples/slider/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/solar_system/Cargo.toml b/examples/solar_system/Cargo.toml index 1a98a87e..ca64da14 100644 --- a/examples/solar_system/Cargo.toml +++ b/examples/solar_system/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["canvas", "tokio", "debug"] } -env_logger = "0.10.0" +iced.workspace = true +iced.features = ["debug", "canvas", "tokio"] + rand = "0.8.3" +tracing-subscriber = "0.3" diff --git a/examples/solar_system/README.md b/examples/solar_system/README.md index acfbc466..81ffd3a5 100644 --- a/examples/solar_system/README.md +++ b/examples/solar_system/README.md @@ -5,9 +5,7 @@ An animated solar system drawn using the `Canvas` widget and showcasing how to c The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/selfassuredaromaticdunnart"> - <img src="https://thumbs.gfycat.com/SelfassuredAromaticDunnart-small.gif"> - </a> + <img src="https://iced.rs/examples/solar_system.gif"> </div> You can run it with `cargo run`: diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index 58d06206..8fa8946e 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -23,7 +23,7 @@ use iced::{ use std::time::Instant; pub fn main() -> iced::Result { - env_logger::builder().format_timestamp(None).init(); + tracing_subscriber::fmt::init(); SolarSystem::run(Settings { antialiasing: true, diff --git a/examples/stopwatch/Cargo.toml b/examples/stopwatch/Cargo.toml index f623feb9..6b1419f6 100644 --- a/examples/stopwatch/Cargo.toml +++ b/examples/stopwatch/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["smol"] } +iced.workspace = true +iced.features = ["smol"] diff --git a/examples/stopwatch/README.md b/examples/stopwatch/README.md index 4cf4582e..1cf370bd 100644 --- a/examples/stopwatch/README.md +++ b/examples/stopwatch/README.md @@ -5,9 +5,7 @@ A watch with start/stop and reset buttons showcasing how to listen to time. The __[`main`]__ file contains all the code of the example. <div align="center"> - <a href="https://gfycat.com/granularenviousgoitered-rust-gui"> - <img src="https://thumbs.gfycat.com/GranularEnviousGoitered-small.gif"> - </a> + <img src="https://iced.rs/examples/stopwatch.gif"> </div> You can run it with `cargo run`: diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs index 842ba3d4..0b0f0607 100644 --- a/examples/stopwatch/src/main.rs +++ b/examples/stopwatch/src/main.rs @@ -1,5 +1,6 @@ use iced::alignment; use iced::executor; +use iced::keyboard; use iced::theme::{self, Theme}; use iced::time; use iced::widget::{button, column, container, row, text}; @@ -77,12 +78,25 @@ impl Application for Stopwatch { } fn subscription(&self) -> Subscription<Message> { - match self.state { + let tick = match self.state { State::Idle => Subscription::none(), State::Ticking { .. } => { time::every(Duration::from_millis(10)).map(Message::Tick) } + }; + + fn handle_hotkey( + key_code: keyboard::KeyCode, + _modifiers: keyboard::Modifiers, + ) -> Option<Message> { + match key_code { + keyboard::KeyCode::Space => Some(Message::Toggle), + keyboard::KeyCode::R => Some(Message::Reset), + _ => None, + } } + + Subscription::batch(vec![tick, keyboard::on_key_press(handle_hotkey)]) } fn view(&self) -> Element<Message> { diff --git a/examples/styling/Cargo.toml b/examples/styling/Cargo.toml index f771708c..c8a90258 100644 --- a/examples/styling/Cargo.toml +++ b/examples/styling/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/styling/README.md b/examples/styling/README.md index 6c198a54..fd12300d 100644 --- a/examples/styling/README.md +++ b/examples/styling/README.md @@ -4,9 +4,7 @@ An example showcasing custom styling with a light and dark theme. All the example code is located in the __[`main`](src/main.rs)__ file. <div align="center"> - <a href="https://user-images.githubusercontent.com/518289/71867993-acff4300-310c-11ea-85a3-d01d8f884346.gif"> - <img src="https://user-images.githubusercontent.com/518289/71867993-acff4300-310c-11ea-85a3-d01d8f884346.gif" height="400px"> - </a> + <img src="https://iced.rs/examples/styling.gif"> </div> You can run it with `cargo run`: diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index f8a4c80a..51538ec2 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -108,6 +108,7 @@ impl Sandbox for Styling { column!["Scroll me!", vertical_space(800), "You did it!"] .width(Length::Fill), ) + .width(Length::Fill) .height(100); let checkbox = checkbox( diff --git a/examples/svg/Cargo.toml b/examples/svg/Cargo.toml index f5a6eaa2..78208fb0 100644 --- a/examples/svg/Cargo.toml +++ b/examples/svg/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["svg"] } +iced.workspace = true +iced.features = ["svg"] diff --git a/examples/system_information/Cargo.toml b/examples/system_information/Cargo.toml index 7d1e4b94..41903122 100644 --- a/examples/system_information/Cargo.toml +++ b/examples/system_information/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["system"] } -bytesize = { version = "1.1.0" } +iced.workspace = true +iced.features = ["system"] + +bytesize = "1.1" diff --git a/examples/toast/Cargo.toml b/examples/toast/Cargo.toml index f703572c..113313e2 100644 --- a/examples/toast/Cargo.toml +++ b/examples/toast/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["advanced"] } +iced.workspace = true +iced.features = ["advanced"] diff --git a/examples/toast/src/main.rs b/examples/toast/src/main.rs index 50fa885a..8570a38e 100644 --- a/examples/toast/src/main.rs +++ b/examples/toast/src/main.rs @@ -1,10 +1,12 @@ +use iced::event::{self, Event}; use iced::executor; use iced::keyboard; -use iced::subscription::{self, Subscription}; use iced::widget::{ self, button, column, container, pick_list, row, slider, text, text_input, }; -use iced::{Alignment, Application, Command, Element, Event, Length, Settings}; +use iced::{ + Alignment, Application, Command, Element, Length, Settings, Subscription, +}; use toast::{Status, Toast}; @@ -57,7 +59,7 @@ impl Application for App { } fn subscription(&self) -> Subscription<Self::Message> { - subscription::events().map(Message::Event) + event::listen().map(Message::Event) } fn update(&mut self, message: Message) -> Command<Message> { diff --git a/examples/todos/Cargo.toml b/examples/todos/Cargo.toml index 7292f665..3c62bfbc 100644 --- a/examples/todos/Cargo.toml +++ b/examples/todos/Cargo.toml @@ -6,21 +6,26 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["async-std", "debug"] } -uuid = { version = "1.0", features = ["v4", "fast-rng", "serde"] } +iced.workspace = true +iced.features = ["async-std", "debug"] + +once_cell.workspace = true serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -once_cell = "1.0" -tracing-subscriber = "0.3" +uuid = { version = "1.0", features = ["v4", "fast-rng", "serde"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -async-std = "1.0" +async-std.workspace = true directories-next = "2.0" +tracing-subscriber = "0.3" [target.'cfg(target_arch = "wasm32")'.dependencies] +iced.workspace = true +iced.features = ["debug", "webgl"] + uuid = { version = "1.0", features = ["js"] } -web-sys = { version = "0.3", features = ["Window", "Storage"] } -wasm-timer = "0.2" +web-sys = { workspace = true, features = ["Window", "Storage"] } +wasm-timer.workspace = true [package.metadata.deb] assets = [ diff --git a/examples/todos/README.md b/examples/todos/README.md index 9c2598b9..5e42f166 100644 --- a/examples/todos/README.md +++ b/examples/todos/README.md @@ -5,8 +5,8 @@ A todos tracker inspired by [TodoMVC]. It showcases dynamic layout, text input, All the example code is located in the __[`main`]__ file. <div align="center"> - <a href="https://gfycat.com/littlesanehalicore"> - <img src="https://thumbs.gfycat.com/LittleSaneHalicore-small.gif" height="400px"> + <a href="https://iced.rs/examples/todos.mp4"> + <img src="https://iced.rs/examples/todos.gif"> </a> </div> @@ -14,7 +14,14 @@ You can run the native version with `cargo run`: ``` cargo run --package todos ``` -We have not yet implemented a `LocalStorage` version of the auto-save feature. Therefore, it does not work on web _yet_! + +The web version can be run with [`trunk`]: + +``` +cd examples/todos +trunk serve +``` [`main`]: src/main.rs [TodoMVC]: http://todomvc.com/ +[`trunk`]: https://trunkrs.dev/ diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index 1dd8a307..5d8936df 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -1,8 +1,6 @@ use iced::alignment::{self, Alignment}; -use iced::event::{self, Event}; use iced::font::{self, Font}; -use iced::keyboard::{self, KeyCode, Modifiers}; -use iced::subscription; +use iced::keyboard; use iced::theme::{self, Theme}; use iced::widget::{ self, button, checkbox, column, container, keyed_column, row, scrollable, @@ -55,7 +53,7 @@ enum Message { FilterChanged(Filter), TaskMessage(usize, TaskMessage), TabPressed { shift: bool }, - ToggleFullscreen(window::Mode), + ChangeWindowMode(window::Mode), } impl Application for Todos { @@ -166,7 +164,7 @@ impl Application for Todos { widget::focus_next() } } - Message::ToggleFullscreen(mode) => { + Message::ChangeWindowMode(mode) => { window::change_mode(mode) } _ => Command::none(), @@ -267,33 +265,19 @@ impl Application for Todos { } fn subscription(&self) -> Subscription<Message> { - subscription::events_with(|event, status| match (event, status) { - ( - Event::Keyboard(keyboard::Event::KeyPressed { - key_code: keyboard::KeyCode::Tab, - modifiers, - .. + keyboard::on_key_press(|key_code, modifiers| { + match (key_code, modifiers) { + (keyboard::KeyCode::Tab, _) => Some(Message::TabPressed { + shift: modifiers.shift(), }), - event::Status::Ignored, - ) => Some(Message::TabPressed { - shift: modifiers.shift(), - }), - ( - Event::Keyboard(keyboard::Event::KeyPressed { - key_code, - modifiers: Modifiers::SHIFT, - }), - event::Status::Ignored, - ) => match key_code { - KeyCode::Up => { - Some(Message::ToggleFullscreen(window::Mode::Fullscreen)) + (keyboard::KeyCode::Up, keyboard::Modifiers::SHIFT) => { + Some(Message::ChangeWindowMode(window::Mode::Fullscreen)) } - KeyCode::Down => { - Some(Message::ToggleFullscreen(window::Mode::Windowed)) + (keyboard::KeyCode::Down, keyboard::Modifiers::SHIFT) => { + Some(Message::ChangeWindowMode(window::Mode::Windowed)) } _ => None, - }, - _ => None, + } }) } } diff --git a/examples/tooltip/Cargo.toml b/examples/tooltip/Cargo.toml index 25840fb4..57bb0dcb 100644 --- a/examples/tooltip/Cargo.toml +++ b/examples/tooltip/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } +iced.workspace = true +iced.features = ["debug"] diff --git a/examples/tour/Cargo.toml b/examples/tour/Cargo.toml index 48471f2d..9e984ad1 100644 --- a/examples/tour/Cargo.toml +++ b/examples/tour/Cargo.toml @@ -6,5 +6,15 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["image", "debug"] } -env_logger = "0.10.0" +iced.workspace = true +iced.features = ["image", "debug"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tracing-subscriber = "0.3" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +iced.workspace = true +iced.features = ["image", "debug", "webgl"] + +console_error_panic_hook = "0.1" +console_log = "1.0" diff --git a/examples/tour/README.md b/examples/tour/README.md index 731e7e66..1c01236b 100644 --- a/examples/tour/README.md +++ b/examples/tour/README.md @@ -5,8 +5,8 @@ A simple UI tour that can run both on native platforms and the web! It showcases The __[`main`]__ file contains all the code of the example! All the cross-platform GUI is defined in terms of __state__, __messages__, __update logic__ and __view logic__. <div align="center"> - <a href="https://gfycat.com/politeadorableiberianmole"> - <img src="https://thumbs.gfycat.com/PoliteAdorableIberianmole-small.gif"> + <a href="https://iced.rs/examples/tour.mp4"> + <img src="https://iced.rs/examples/tour.gif"> </a> </div> diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index 10de2ae1..3e3a8ad7 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -8,7 +8,14 @@ use iced::widget::{Button, Column, Container, Slider}; use iced::{Color, Element, Font, Length, Pixels, Renderer, Sandbox, Settings}; pub fn main() -> iced::Result { - env_logger::init(); + #[cfg(target_arch = "wasm32")] + { + console_log::init().expect("Initialize logger"); + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + } + + #[cfg(not(target_arch = "wasm32"))] + tracing_subscriber::fmt::init(); Tour::run(Settings::default()) } diff --git a/examples/url_handler/Cargo.toml b/examples/url_handler/Cargo.toml index 4dcff92d..7bb9914b 100644 --- a/examples/url_handler/Cargo.toml +++ b/examples/url_handler/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../.." } +iced.workspace = true diff --git a/examples/url_handler/src/main.rs b/examples/url_handler/src/main.rs index f63fa06a..bf570123 100644 --- a/examples/url_handler/src/main.rs +++ b/examples/url_handler/src/main.rs @@ -1,6 +1,5 @@ -use iced::event::{Event, MacOS, PlatformSpecific}; +use iced::event::{self, Event}; use iced::executor; -use iced::subscription; use iced::widget::{container, text}; use iced::{ Application, Command, Element, Length, Settings, Subscription, Theme, @@ -37,9 +36,11 @@ impl Application for App { fn update(&mut self, message: Message) -> Command<Message> { match message { Message::EventOccurred(event) => { - if let Event::PlatformSpecific(PlatformSpecific::MacOS( - MacOS::ReceivedUrl(url), - )) = event + if let Event::PlatformSpecific( + event::PlatformSpecific::MacOS(event::MacOS::ReceivedUrl( + url, + )), + ) = event { self.url = Some(url); } @@ -50,7 +51,7 @@ impl Application for App { } fn subscription(&self) -> Subscription<Message> { - subscription::events().map(Message::EventOccurred) + event::listen().map(Message::EventOccurred) } fn view(&self) -> Element<Message> { diff --git a/examples/visible_bounds/Cargo.toml b/examples/visible_bounds/Cargo.toml index cfa56dd2..37594b84 100644 --- a/examples/visible_bounds/Cargo.toml +++ b/examples/visible_bounds/Cargo.toml @@ -6,5 +6,7 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["debug"] } -once_cell = "1" +iced.workspace = true +iced.features = ["debug"] + +once_cell.workspace = true diff --git a/examples/visible_bounds/src/main.rs b/examples/visible_bounds/src/main.rs index 8b684514..42dfc24c 100644 --- a/examples/visible_bounds/src/main.rs +++ b/examples/visible_bounds/src/main.rs @@ -1,14 +1,14 @@ +use iced::event::{self, Event}; use iced::executor; use iced::mouse; -use iced::subscription::{self, Subscription}; use iced::theme::{self, Theme}; use iced::widget::{ column, container, horizontal_space, row, scrollable, text, vertical_space, }; use iced::window; use iced::{ - Alignment, Application, Color, Command, Element, Event, Font, Length, - Point, Rectangle, Settings, + Alignment, Application, Color, Command, Element, Font, Length, Point, + Rectangle, Settings, Subscription, }; pub fn main() -> iced::Result { @@ -163,7 +163,7 @@ impl Application for Example { } fn subscription(&self) -> Subscription<Message> { - subscription::events_with(|event, _| match event { + event::listen_with(|event, _| match event { Event::Mouse(mouse::Event::CursorMoved { position }) => { Some(Message::MouseMoved(position)) } diff --git a/examples/websocket/Cargo.toml b/examples/websocket/Cargo.toml index 12af9658..2756e8e0 100644 --- a/examples/websocket/Cargo.toml +++ b/examples/websocket/Cargo.toml @@ -6,16 +6,16 @@ edition = "2021" publish = false [dependencies] -iced = { path = "../..", features = ["tokio", "debug"] } -once_cell = "1.15" +iced.workspace = true +iced.features = ["debug", "tokio"] + +once_cell.workspace = true +warp = "0.3" [dependencies.async-tungstenite] version = "0.23" features = ["tokio-rustls-webpki-roots"] [dependencies.tokio] -version = "1" +workspace = true features = ["time"] - -[dependencies.warp] -version = "0.3" diff --git a/futures/Cargo.toml b/futures/Cargo.toml index 044827c2..69a915e4 100644 --- a/futures/Cargo.toml +++ b/futures/Cargo.toml @@ -1,47 +1,40 @@ [package] name = "iced_futures" -version = "0.7.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "Commands, subscriptions, and runtimes for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_futures" -keywords = ["gui", "ui", "graphics", "interface", "futures"] -categories = ["gui"] +description = "Commands, subscriptions, and future executors for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] +all-features = true [features] thread-pool = ["futures/thread-pool"] [dependencies] -log = "0.4" - -[dependencies.iced_core] -version = "0.10" -path = "../core" +iced_core.workspace = true -[dependencies.futures] -version = "0.3" +futures.workspace = true +log.workspace = true -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.tokio] -package = "tokio" -version = "1.0" -optional = true -features = ["rt", "rt-multi-thread", "time"] +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +async-std.workspace = true +async-std.optional = true +async-std.features = ["unstable"] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.async-std] -version = "1.0" -optional = true -features = ["unstable"] +smol.workspace = true +smol.optional = true -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.smol] -version = "1.2" -optional = true +tokio.workspace = true +tokio.optional = true +tokio.features = ["rt", "rt-multi-thread", "time"] [target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen-futures = "0.4" -wasm-timer = "0.2" - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true +wasm-bindgen-futures.workspace = true +wasm-timer.workspace = true diff --git a/futures/src/event.rs b/futures/src/event.rs new file mode 100644 index 00000000..214d2d40 --- /dev/null +++ b/futures/src/event.rs @@ -0,0 +1,59 @@ +//! Listen to runtime events. +use crate::core::event::{self, Event}; +use crate::core::window; +use crate::subscription::{self, Subscription}; +use crate::MaybeSend; + +/// Returns a [`Subscription`] to all the ignored runtime events. +/// +/// This subscription will notify your application of any [`Event`] that was +/// not captured by any widget. +pub fn listen() -> Subscription<Event> { + listen_with(|event, status| match status { + event::Status::Ignored => Some(event), + event::Status::Captured => None, + }) +} + +/// Creates a [`Subscription`] that listens and filters all the runtime events +/// with the provided function, producing messages accordingly. +/// +/// This subscription will call the provided function for every [`Event`] +/// handled by the runtime. If the function: +/// +/// - Returns `None`, the [`Event`] will be discarded. +/// - Returns `Some` message, the `Message` will be produced. +pub fn listen_with<Message>( + f: fn(Event, event::Status) -> Option<Message>, +) -> Subscription<Message> +where + Message: 'static + MaybeSend, +{ + #[derive(Hash)] + struct EventsWith; + + subscription::filter_map( + (EventsWith, f), + move |event, status| match event { + Event::Window(window::Event::RedrawRequested(_)) => None, + _ => f(event, status), + }, + ) +} + +/// Creates a [`Subscription`] that produces a message for every runtime event, +/// including the redraw request events. +/// +/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in +/// an infinite loop. +pub fn listen_raw<Message>( + f: fn(Event, event::Status) -> Option<Message>, +) -> Subscription<Message> +where + Message: 'static + MaybeSend, +{ + #[derive(Hash)] + struct RawEvents; + + subscription::filter_map((RawEvents, f), f) +} diff --git a/futures/src/keyboard.rs b/futures/src/keyboard.rs new file mode 100644 index 00000000..af68e1f2 --- /dev/null +++ b/futures/src/keyboard.rs @@ -0,0 +1,61 @@ +//! Listen to keyboard events. +use crate::core; +use crate::core::keyboard::{Event, KeyCode, Modifiers}; +use crate::subscription::{self, Subscription}; +use crate::MaybeSend; + +/// Listens to keyboard key presses and calls the given function +/// map them into actual messages. +/// +/// If the function returns `None`, the key press will be simply +/// ignored. +pub fn on_key_press<Message>( + f: fn(KeyCode, Modifiers) -> Option<Message>, +) -> Subscription<Message> +where + Message: MaybeSend + 'static, +{ + #[derive(Hash)] + struct OnKeyPress; + + subscription::filter_map((OnKeyPress, f), move |event, status| { + match (event, status) { + ( + core::Event::Keyboard(Event::KeyPressed { + key_code, + modifiers, + }), + core::event::Status::Ignored, + ) => f(key_code, modifiers), + _ => None, + } + }) +} + +/// Listens to keyboard key releases and calls the given function +/// map them into actual messages. +/// +/// If the function returns `None`, the key release will be simply +/// ignored. +pub fn on_key_release<Message>( + f: fn(KeyCode, Modifiers) -> Option<Message>, +) -> Subscription<Message> +where + Message: MaybeSend + 'static, +{ + #[derive(Hash)] + struct OnKeyRelease; + + subscription::filter_map((OnKeyRelease, f), move |event, status| { + match (event, status) { + ( + core::Event::Keyboard(Event::KeyReleased { + key_code, + modifiers, + }), + core::event::Status::Ignored, + ) => f(key_code, modifiers), + _ => None, + } + }) +} diff --git a/futures/src/lib.rs b/futures/src/lib.rs index 34d81e1e..abc46176 100644 --- a/futures/src/lib.rs +++ b/futures/src/lib.rs @@ -4,6 +4,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -12,9 +13,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(unsafe_code, rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub use futures; @@ -24,7 +25,9 @@ mod maybe_send; mod runtime; pub mod backend; +pub mod event; pub mod executor; +pub mod keyboard; pub mod subscription; pub use executor::Executor; diff --git a/futures/src/runtime.rs b/futures/src/runtime.rs index 2241a494..16111b36 100644 --- a/futures/src/runtime.rs +++ b/futures/src/runtime.rs @@ -9,9 +9,9 @@ use std::marker::PhantomData; /// A batteries-included runtime of commands and subscriptions. /// /// If you have an [`Executor`], a [`Runtime`] can be leveraged to run any -/// [`Command`] or [`Subscription`] and get notified of the results! +/// `Command` or [`Subscription`] and get notified of the results! /// -/// [`Command`]: crate::Command +/// [`Subscription`]: crate::Subscription #[derive(Debug)] pub struct Runtime<Executor, Sender, Message> { executor: Executor, @@ -75,6 +75,7 @@ where /// [`Tracker::update`] to learn more about this! /// /// [`Tracker::update`]: subscription::Tracker::update + /// [`Subscription`]: crate::Subscription pub fn track( &mut self, recipes: impl IntoIterator< diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 8f78ce3a..d40125e3 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -4,7 +4,6 @@ mod tracker; pub use tracker::Tracker; use crate::core::event::{self, Event}; -use crate::core::window; use crate::core::Hasher; use crate::futures::{Future, Stream}; use crate::{BoxStream, MaybeSend}; @@ -20,16 +19,14 @@ pub type EventStream = BoxStream<(Event, event::Status)>; /// A request to listen to external events. /// -/// Besides performing async actions on demand with [`Command`], most +/// Besides performing async actions on demand with `Command`, most /// applications also need to listen to external events passively. /// -/// A [`Subscription`] is normally provided to some runtime, like a [`Command`], +/// A [`Subscription`] is normally provided to some runtime, like a `Command`, /// and it will generate events as long as the user keeps requesting it. /// /// For instance, you can use a [`Subscription`] to listen to a WebSocket /// connection, keyboard presses, mouse events, time ticks, etc. -/// -/// [`Command`]: crate::Command #[must_use = "`Subscription` must be returned to runtime to take effect"] pub struct Subscription<Message> { recipes: Vec<Box<dyn Recipe<Output = Message>>>, @@ -215,77 +212,6 @@ where } } -/// Returns a [`Subscription`] to all the ignored runtime events. -/// -/// This subscription will notify your application of any [`Event`] that was -/// not captured by any widget. -pub fn events() -> Subscription<Event> { - events_with(|event, status| match status { - event::Status::Ignored => Some(event), - event::Status::Captured => None, - }) -} - -/// Returns a [`Subscription`] that filters all the runtime events with the -/// provided function, producing messages accordingly. -/// -/// This subscription will call the provided function for every [`Event`] -/// handled by the runtime. If the function: -/// -/// - Returns `None`, the [`Event`] will be discarded. -/// - Returns `Some` message, the `Message` will be produced. -pub fn events_with<Message>( - f: fn(Event, event::Status) -> Option<Message>, -) -> Subscription<Message> -where - Message: 'static + MaybeSend, -{ - #[derive(Hash)] - struct EventsWith; - - Subscription::from_recipe(Runner { - id: (EventsWith, f), - spawn: move |events| { - use futures::future; - use futures::stream::StreamExt; - - events.filter_map(move |(event, status)| { - future::ready(match event { - Event::Window(window::Event::RedrawRequested(_)) => None, - _ => f(event, status), - }) - }) - }, - }) -} - -/// Returns a [`Subscription`] that produces a message for every runtime event, -/// including the redraw request events. -/// -/// **Warning:** This [`Subscription`], if unfiltered, may produce messages in -/// an infinite loop. -pub fn raw_events<Message>( - f: fn(Event, event::Status) -> Option<Message>, -) -> Subscription<Message> -where - Message: 'static + MaybeSend, -{ - #[derive(Hash)] - struct RawEvents; - - Subscription::from_recipe(Runner { - id: (RawEvents, f), - spawn: move |events| { - use futures::future; - use futures::stream::StreamExt; - - events.filter_map(move |(event, status)| { - future::ready(f(event, status)) - }) - }, - }) -} - /// Returns a [`Subscription`] that will call the given function to create and /// asynchronously run the given [`Stream`]. pub fn run<S, Message>(builder: fn() -> S) -> Subscription<Message> @@ -338,6 +264,25 @@ where ) } +pub(crate) fn filter_map<I, F, Message>(id: I, f: F) -> Subscription<Message> +where + I: Hash + 'static, + F: Fn(Event, event::Status) -> Option<Message> + MaybeSend + 'static, + Message: 'static + MaybeSend, +{ + Subscription::from_recipe(Runner { + id, + spawn: |events| { + use futures::future; + use futures::stream::StreamExt; + + events.filter_map(move |(event, status)| { + future::ready(f(event, status)) + }) + }, + }) +} + /// Creates a [`Subscription`] that publishes the events sent from a [`Future`] /// to an [`mpsc::Sender`] with the given bounds. /// diff --git a/futures/src/subscription/tracker.rs b/futures/src/subscription/tracker.rs index ae71cd25..3a83da09 100644 --- a/futures/src/subscription/tracker.rs +++ b/futures/src/subscription/tracker.rs @@ -14,6 +14,8 @@ use std::hash::Hasher as _; /// If you have an application that continuously returns a [`Subscription`], /// you can use a [`Tracker`] to keep track of the different recipes and keep /// its executions alive. +/// +/// [`Subscription`]: crate::Subscription #[derive(Debug, Default)] pub struct Tracker { subscriptions: HashMap<u64, Execution>, @@ -51,6 +53,7 @@ impl Tracker { /// the [`Tracker`] changes. /// /// [`Recipe`]: crate::subscription::Recipe + /// [`Subscription`]: crate::Subscription pub fn update<Message, Receiver>( &mut self, recipes: impl Iterator<Item = Box<dyn Recipe<Output = Message>>>, diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index 6fc6ab00..ff698649 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -1,14 +1,18 @@ [package] name = "iced_graphics" -version = "0.9.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/iced-rs/iced" -documentation = "https://docs.rs/iced_graphics" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +description = "A bunch of backend-agnostic types that can be leveraged to build a renderer for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] +all-features = true [features] geometry = ["lyon_path"] @@ -17,43 +21,29 @@ image = ["dep:image", "kamadak-exif"] web-colors = [] [dependencies] -glam = "0.24" -half = "2.2.1" -log = "0.4" -raw-window-handle = "0.5" -thiserror = "1.0" -bitflags = "1.2" -cosmic-text = "0.9" -rustc-hash = "1.1" - -[dependencies.bytemuck] -version = "1.4" -features = ["derive"] - -[dependencies.iced_core] -version = "0.10" -path = "../core" - -[dependencies.twox-hash] -version = "1.6" -default-features = false - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.twox-hash] -version = "1.6.1" -features = ["std"] - -[dependencies.image] -version = "0.24" -optional = true - -[dependencies.kamadak-exif] -version = "0.5" -optional = true - -[dependencies.lyon_path] -version = "1" -optional = true +iced_core.workspace = true -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true +bitflags.workspace = true +bytemuck.workspace = true +glam.workspace = true +half.workspace = true +log.workspace = true +raw-window-handle.workspace = true +thiserror.workspace = true +cosmic-text.workspace = true +rustc-hash.workspace = true + +lyon_path.workspace = true +lyon_path.optional = true + +image.workspace = true +image.optional = true + +kamadak-exif.workspace = true +kamadak-exif.optional = true + +twox-hash.workspace = true + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +twox-hash.workspace = true +twox-hash.features = ["std"] diff --git a/graphics/src/compositor.rs b/graphics/src/compositor.rs index f7b86045..7173ffa7 100644 --- a/graphics/src/compositor.rs +++ b/graphics/src/compositor.rs @@ -63,7 +63,7 @@ pub trait Compositor: Sized { /// Screenshots the current [`Renderer`] primitives to an offscreen texture, and returns the bytes of /// the texture ordered as `RGBA` in the sRGB color space. /// - /// [`Renderer`]: Self::Renderer; + /// [`Renderer`]: Self::Renderer fn screenshot<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, diff --git a/graphics/src/geometry.rs b/graphics/src/geometry.rs index 7cd3dd3a..d7d6a0aa 100644 --- a/graphics/src/geometry.rs +++ b/graphics/src/geometry.rs @@ -14,11 +14,11 @@ pub use text::Text; pub use crate::gradient::{self, Gradient}; -/// A renderer capable of drawing some [`Geometry`]. +/// A renderer capable of drawing some [`Self::Geometry`]. pub trait Renderer: crate::core::Renderer { /// The kind of geometry this renderer can draw. type Geometry; - /// Draws the given layers of [`Geometry`]. + /// Draws the given layers of [`Self::Geometry`]. fn draw(&mut self, layers: Vec<Self::Geometry>); } diff --git a/graphics/src/geometry/fill.rs b/graphics/src/geometry/fill.rs index b773c99b..670fbc12 100644 --- a/graphics/src/geometry/fill.rs +++ b/graphics/src/geometry/fill.rs @@ -1,4 +1,6 @@ -//! Fill [crate::widget::canvas::Geometry] with a certain style. +//! Fill [`Geometry`] with a certain style. +//! +//! [`Geometry`]: super::Renderer::Geometry pub use crate::geometry::Style; use crate::core::Color; diff --git a/graphics/src/geometry/stroke.rs b/graphics/src/geometry/stroke.rs index 69a76e1c..aff49ab3 100644 --- a/graphics/src/geometry/stroke.rs +++ b/graphics/src/geometry/stroke.rs @@ -1,4 +1,6 @@ -//! Create lines from a [crate::widget::canvas::Path] and assigns them various attributes/styles. +//! Create lines from a [`Path`] and assigns them various attributes/styles. +//! +//! [`Path`]: super::Path pub use crate::geometry::Style; use iced_core::Color; diff --git a/graphics/src/gradient.rs b/graphics/src/gradient.rs index 4db565d8..b274ec86 100644 --- a/graphics/src/gradient.rs +++ b/graphics/src/gradient.rs @@ -1,8 +1,6 @@ -//! A gradient that can be used as a [`Fill`] for some geometry. +//! A gradient that can be used as a fill for some geometry. //! //! For a gradient that you can use as a background variant for a widget, see [`Gradient`]. -//! -//! [`Gradient`]: crate::core::Gradient; use crate::color; use crate::core::gradient::ColorStop; use crate::core::{self, Color, Point, Rectangle}; @@ -36,10 +34,7 @@ impl Gradient { } } -/// A linear gradient that can be used in the style of [`Fill`] or [`Stroke`]. -/// -/// [`Fill`]: crate::geometry::Fill; -/// [`Stroke`]: crate::geometry::Stroke; +/// A linear gradient. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Linear { /// The absolute starting position of the gradient. @@ -53,7 +48,7 @@ pub struct Linear { } impl Linear { - /// Creates a new [`Builder`]. + /// Creates a new [`Linear`] builder. pub fn new(start: Point, end: Point) -> Self { Self { start, diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 902eb5b0..01a358ca 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -7,6 +7,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(rust_2018_idioms)] #![deny( missing_debug_implementations, //missing_docs, @@ -16,9 +17,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] mod antialiasing; diff --git a/graphics/src/mesh.rs b/graphics/src/mesh.rs index cfb5a60f..041986cf 100644 --- a/graphics/src/mesh.rs +++ b/graphics/src/mesh.rs @@ -41,7 +41,7 @@ impl Damage for Mesh { } } -/// A set of [`Vertex2D`] and indices representing a list of triangles. +/// A set of vertices and indices representing a list of triangles. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Indexed<T> { /// The vertices of the mesh diff --git a/graphics/src/text/cache.rs b/graphics/src/text/cache.rs index 9e4fbf65..577c4687 100644 --- a/graphics/src/text/cache.rs +++ b/graphics/src/text/cache.rs @@ -43,7 +43,10 @@ impl Cache { } if let hash_map::Entry::Vacant(entry) = self.entries.entry(hash) { - let metrics = cosmic_text::Metrics::new(key.size, key.line_height); + let metrics = cosmic_text::Metrics::new( + key.size, + key.line_height.max(f32::MIN_POSITIVE), + ); let mut buffer = cosmic_text::Buffer::new(font_system, metrics); buffer.set_size( diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml index 89326d73..56e17209 100644 --- a/renderer/Cargo.toml +++ b/renderer/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "iced_renderer" -version = "0.1.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "The official renderer for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_renderer" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +description = "The official renderer for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [features] wgpu = ["iced_wgpu"] @@ -17,21 +17,15 @@ svg = ["iced_tiny_skia/svg", "iced_wgpu?/svg"] geometry = ["iced_graphics/geometry", "iced_tiny_skia/geometry", "iced_wgpu?/geometry"] tracing = ["iced_wgpu?/tracing"] web-colors = ["iced_wgpu?/web-colors"] +webgl = ["iced_wgpu?/webgl"] [dependencies] -raw-window-handle = "0.5" -thiserror = "1" -log = "0.4" +iced_graphics.workspace = true +iced_tiny_skia.workspace = true -[dependencies.iced_graphics] -version = "0.9" -path = "../graphics" +iced_wgpu.workspace = true +iced_wgpu.optional = true -[dependencies.iced_tiny_skia] -version = "0.1" -path = "../tiny_skia" - -[dependencies.iced_wgpu] -version = "0.11" -path = "../wgpu" -optional = true +log.workspace = true +raw-window-handle.workspace = true +thiserror.workspace = true diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs index 04b5d9e6..1ecb0a43 100644 --- a/renderer/src/geometry.rs +++ b/renderer/src/geometry.rs @@ -96,13 +96,11 @@ impl Frame { /// resulting glyphs will not be rotated or scaled properly. /// /// Additionally, all text will be rendered on top of all the layers of - /// a [`Canvas`]. Therefore, it is currently only meant to be used for + /// a `Canvas`. Therefore, it is currently only meant to be used for /// overlays, which is the most common use case. /// /// Support for vectorial text is planned, and should address all these /// limitations. - /// - /// [`Canvas`]: crate::widget::Canvas pub fn fill_text(&mut self, text: impl Into<Text>) { delegate!(self, frame, frame.fill_text(text)); } @@ -168,12 +166,18 @@ impl Frame { delegate!(self, frame, frame.rotate(angle)); } - /// Applies a scaling to the current transform of the [`Frame`]. + /// Applies a uniform scaling to the current transform of the [`Frame`]. #[inline] - pub fn scale(&mut self, scale: f32) { + pub fn scale(&mut self, scale: impl Into<f32>) { delegate!(self, frame, frame.scale(scale)); } + /// Applies a non-uniform scaling to the current transform of the [`Frame`]. + #[inline] + pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) { + delegate!(self, frame, frame.scale_nonuniform(scale)); + } + pub fn into_geometry(self) -> Geometry { match self { Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()), diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index 2b282a0b..8bdf231d 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -1,3 +1,16 @@ +#![forbid(rust_2018_idioms)] +#![deny( + unsafe_code, + unused_results, + clippy::extra_unused_lifetimes, + clippy::from_over_into, + clippy::needless_borrow, + clippy::new_without_default, + clippy::useless_conversion, + rustdoc::broken_intra_doc_links +)] +#![allow(clippy::inherent_to_string, clippy::type_complexity)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod compositor; #[cfg(feature = "geometry")] diff --git a/renderer/src/settings.rs b/renderer/src/settings.rs index 08f2099e..432eb8a0 100644 --- a/renderer/src/settings.rs +++ b/renderer/src/settings.rs @@ -1,9 +1,7 @@ use crate::core::{Font, Pixels}; use crate::graphics::Antialiasing; -/// The settings of a [`Backend`]. -/// -/// [`Backend`]: crate::Backend +/// The settings of a Backend. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Settings { /// The default [`Font`] to use. diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 9fbe4be7..d19aedd3 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -1,23 +1,21 @@ [package] name = "iced_runtime" -version = "0.1.1" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "A renderer-agnostic runtime for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" +description = "A renderer-agnostic runtime for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [features] debug = [] [dependencies] -thiserror = "1" +iced_core.workspace = true +iced_futures.workspace = true +iced_futures.features = ["thread-pool"] -[dependencies.iced_core] -version = "0.10" -path = "../core" - -[dependencies.iced_futures] -version = "0.7" -path = "../futures" -features = ["thread-pool"] +thiserror.workspace = true diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 59c70ff7..c3261cca 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -2,35 +2,13 @@ //! //!  //! -//! `iced_native` takes [`iced_core`] and builds a native runtime on top of it, -//! featuring: -//! -//! - A custom layout engine, greatly inspired by [`druid`] -//! - Event handling for all the built-in widgets -//! - A renderer-agnostic API -//! -//! To achieve this, it introduces a couple of reusable interfaces: -//! -//! - A [`Widget`] trait, which is used to implement new widgets: from layout -//! requirements to event and drawing logic. -//! - A bunch of `Renderer` traits, meant to keep the crate renderer-agnostic. -//! -//! # Usage -//! The strategy to use this crate depends on your particular use case. If you -//! want to: -//! - Implement a custom shell or integrate it in your own system, check out the -//! [`UserInterface`] type. -//! - Build a new renderer, see the [renderer] module. -//! - Build a custom widget, start at the [`Widget`] trait. +//! `iced_runtime` takes [`iced_core`] and builds a native runtime on top of it. //! //! [`iced_core`]: https://github.com/iced-rs/iced/tree/0.10/core -//! [`iced_winit`]: https://github.com/iced-rs/iced/tree/0.10/winit -//! [`druid`]: https://github.com/xi-editor/druid -//! [`raw-window-handle`]: https://github.com/rust-windowing/raw-window-handle -//! [renderer]: crate::renderer #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -39,9 +17,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(unsafe_code, rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod clipboard; pub mod command; diff --git a/runtime/src/overlay/nested.rs b/runtime/src/overlay/nested.rs index b729f769..21b6f7c1 100644 --- a/runtime/src/overlay/nested.rs +++ b/runtime/src/overlay/nested.rs @@ -6,7 +6,7 @@ use crate::core::renderer; use crate::core::widget; use crate::core::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size}; -/// An [`Overlay`] container that displays nested overlays +/// An overlay container that displays nested overlays #[allow(missing_debug_implementations)] pub struct Nested<'a, Message, Renderer> { overlay: overlay::Element<'a, Message, Renderer>, @@ -27,6 +27,8 @@ where } /// Returns the layout [`Node`] of the [`Nested`] overlay. + /// + /// [`Node`]: layout::Node pub fn layout( &mut self, renderer: &Renderer, diff --git a/runtime/src/program/state.rs b/runtime/src/program/state.rs index 35df6078..9aa2d550 100644 --- a/runtime/src/program/state.rs +++ b/runtime/src/program/state.rs @@ -175,7 +175,7 @@ where (uncaptured_events, command) } - /// Applies [`widget::Operation`]s to the [`State`] + /// Applies [`Operation`]s to the [`State`] pub fn operate( &mut self, renderer: &mut P::Renderer, diff --git a/runtime/src/user_interface.rs b/runtime/src/user_interface.rs index b684fbde..dae9e0ac 100644 --- a/runtime/src/user_interface.rs +++ b/runtime/src/user_interface.rs @@ -361,7 +361,7 @@ where /// It returns the current [`mouse::Interaction`]. You should update the /// icon of the mouse cursor accordingly in your system. /// - /// [`Renderer`]: crate::Renderer + /// [`Renderer`]: crate::core::Renderer /// /// # Example /// We can finally draw our [counter](index.html#usage) by @@ -624,7 +624,7 @@ pub enum State { /// The [`UserInterface`] is up-to-date and can be reused without /// rebuilding. Updated { - /// The [`Instant`] when a redraw should be performed. + /// The [`window::RedrawRequest`] when a redraw should be performed. redraw_request: Option<window::RedrawRequest>, }, } diff --git a/runtime/src/window.rs b/runtime/src/window.rs index 5219fbfd..41816967 100644 --- a/runtime/src/window.rs +++ b/runtime/src/window.rs @@ -10,7 +10,8 @@ use crate::command::{self, Command}; use crate::core::time::Instant; use crate::core::window::{Event, Icon, Level, Mode, UserAttention}; use crate::core::Size; -use crate::futures::subscription::{self, Subscription}; +use crate::futures::event; +use crate::futures::Subscription; /// Subscribes to the frames of the window of the running application. /// @@ -21,7 +22,7 @@ use crate::futures::subscription::{self, Subscription}; /// In any case, this [`Subscription`] is useful to smoothly draw application-driven /// animations without missing any frames. pub fn frames() -> Subscription<Instant> { - subscription::raw_events(|event, _status| match event { + event::listen_raw(|event, _status| match event { iced_core::Event::Window(Event::RedrawRequested(at)) => Some(at), _ => None, }) @@ -20,9 +20,9 @@ //! Check out the [repository] and the [examples] for more details! //! //! [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 +//! [text inputs]: https://iced.rs/examples/text_input.mp4 +//! [scrollables]: https://iced.rs/examples/scrollable.mp4 +//! [Debug overlay with performance metrics]: https://iced.rs/examples/debug.mp4 //! [Modular ecosystem]: https://github.com/iced-rs/iced/blob/master/ECOSYSTEM.md //! [renderer-agnostic native runtime]: https://github.com/iced-rs/iced/tree/0.10/runtime //! [`wgpu`]: https://github.com/gfx-rs/wgpu-rs @@ -151,6 +151,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(rust_2018_idioms, unsafe_code)] #![deny( missing_debug_implementations, missing_docs, @@ -159,9 +160,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(rust_2018_idioms, unsafe_code)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] use iced_widget::graphics; @@ -187,7 +188,6 @@ pub mod advanced; pub use style::theme; pub use crate::core::alignment; -pub use crate::core::event; pub use crate::core::gradient; pub use crate::core::{ color, Alignment, Background, BorderRadius, Color, ContentFit, Degrees, @@ -223,9 +223,16 @@ pub mod font { pub use crate::runtime::font::*; } +pub mod event { + //! Handle events of a user interface. + pub use crate::core::event::{Event, MacOS, PlatformSpecific, Status}; + pub use iced_futures::event::{listen, listen_raw, listen_with}; +} + pub mod keyboard { //! Listen and react to keyboard events. pub use crate::core::keyboard::{Event, KeyCode, Modifiers}; + pub use iced_futures::keyboard::{on_key_press, on_key_release}; } pub mod mouse { @@ -238,7 +245,7 @@ pub mod mouse { pub mod subscription { //! Listen to external events in your application. pub use iced_futures::subscription::{ - channel, events, events_with, run, run_with_id, unfold, Subscription, + channel, run, run_with_id, unfold, Subscription, }; } @@ -252,11 +259,11 @@ pub mod system { pub mod overlay { //! Display interactive elements on top of other widgets. - /// A generic [`Overlay`]. + /// A generic overlay. /// - /// This is an alias of an `iced_native` element with a default `Renderer`. + /// This is an alias of an [`overlay::Element`] with a default `Renderer`. /// - /// [`Overlay`]: iced_native::Overlay + /// [`overlay::Element`]: crate::core::overlay::Element pub type Element<'a, Message, Renderer = crate::Renderer> = crate::core::overlay::Element<'a, Message, Renderer>; diff --git a/src/settings.rs b/src/settings.rs index 794f89fd..d9778d7e 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -23,7 +23,7 @@ pub struct Settings<Flags> { /// The default [`Font`] to be used. /// - /// By default, it uses [`Font::SansSerif`]. + /// By default, it uses [`Family::SansSerif`](crate::font::Family::SansSerif). pub default_font: Font, /// The text size that will be used by default. diff --git a/src/window/icon.rs b/src/window/icon.rs index 0fe010ca..ef71c228 100644 --- a/src/window/icon.rs +++ b/src/window/icon.rs @@ -10,10 +10,10 @@ use std::path::Path; /// Creates an icon from an image file. /// -/// This will return an error in case the file is missing at run-time. You may prefer [`Self::from_file_data`] instead. +/// This will return an error in case the file is missing at run-time. You may prefer [`from_file_data`] instead. #[cfg(feature = "image")] pub fn from_file<P: AsRef<Path>>(icon_path: P) -> Result<Icon, Error> { - let icon = image_rs::io::Reader::open(icon_path)?.decode()?.to_rgba8(); + let icon = image::io::Reader::open(icon_path)?.decode()?.to_rgba8(); Ok(icon::from_rgba(icon.to_vec(), icon.width(), icon.height())?) } @@ -25,9 +25,10 @@ pub fn from_file<P: AsRef<Path>>(icon_path: P) -> Result<Icon, Error> { #[cfg(feature = "image")] pub fn from_file_data( data: &[u8], - explicit_format: Option<image_rs::ImageFormat>, + explicit_format: Option<image::ImageFormat>, ) -> Result<Icon, Error> { - let mut icon = image_rs::io::Reader::new(std::io::Cursor::new(data)); + let mut icon = image::io::Reader::new(std::io::Cursor::new(data)); + let icon_with_format = match explicit_format { Some(format) => { icon.set_format(format); @@ -59,5 +60,5 @@ pub enum Error { /// The `image` crate reported an error. #[cfg(feature = "image")] #[error("Unable to create icon from a file: {0}")] - ImageError(#[from] image_rs::error::ImageError), + ImageError(#[from] image::error::ImageError), } diff --git a/style/Cargo.toml b/style/Cargo.toml index 689cf978..3f00e787 100644 --- a/style/Cargo.toml +++ b/style/Cargo.toml @@ -1,22 +1,18 @@ [package] name = "iced_style" -version = "0.9.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" description = "The default set of styles of Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_style" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true -[dependencies.iced_core] -version = "0.10" -path = "../core" -features = ["palette"] +[dependencies] +iced_core.workspace = true +iced_core.features = ["palette"] -[dependencies.palette] -version = "0.7" - -[dependencies.once_cell] -version = "1.15" +palette.workspace = true +once_cell.workspace = true diff --git a/style/src/lib.rs b/style/src/lib.rs index 286ff9db..0c555ed8 100644 --- a/style/src/lib.rs +++ b/style/src/lib.rs @@ -7,16 +7,18 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( unused_results, clippy::extra_unused_lifetimes, clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + missing_docs, + unused_results, + rustdoc::broken_intra_doc_links )] -#![deny(missing_docs, unused_results)] -#![forbid(unsafe_code, rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] pub use iced_core as core; diff --git a/style/src/theme.rs b/style/src/theme.rs index 64497181..893d7202 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -1,8 +1,7 @@ //! Use the built-in theme and styles. pub mod palette; -use self::palette::Extended; -pub use self::palette::Palette; +pub use palette::Palette; use crate::application; use crate::button; @@ -40,7 +39,16 @@ pub enum Theme { impl Theme { /// Creates a new custom [`Theme`] from the given [`Palette`]. pub fn custom(palette: Palette) -> Self { - Self::Custom(Box::new(Custom::new(palette))) + Self::custom_with_fn(palette, palette::Extended::generate) + } + + /// Creates a new custom [`Theme`] from the given [`Palette`], with + /// a custom generator of a [`palette::Extended`]. + pub fn custom_with_fn( + palette: Palette, + generate: impl FnOnce(Palette) -> palette::Extended, + ) -> Self { + Self::Custom(Box::new(Custom::with_fn(palette, generate))) } /// Returns the [`Palette`] of the [`Theme`]. @@ -66,15 +74,24 @@ impl Theme { #[derive(Debug, Clone, Copy, PartialEq)] pub struct Custom { palette: Palette, - extended: Extended, + extended: palette::Extended, } impl Custom { /// Creates a [`Custom`] theme from the given [`Palette`]. pub fn new(palette: Palette) -> Self { + Self::with_fn(palette, palette::Extended::generate) + } + + /// Creates a [`Custom`] theme from the given [`Palette`] with + /// a custom generator of a [`palette::Extended`]. + pub fn with_fn( + palette: Palette, + generate: impl FnOnce(Palette) -> palette::Extended, + ) -> Self { Self { palette, - extended: Extended::generate(palette), + extended: generate(palette), } } } diff --git a/tiny_skia/Cargo.toml b/tiny_skia/Cargo.toml index 9aa63a4f..15a6928a 100644 --- a/tiny_skia/Cargo.toml +++ b/tiny_skia/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "iced_tiny_skia" -version = "0.1.0" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "A software renderer for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_tiny_skia" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +description = "A software renderer for iced on top of tiny-skia" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [features] image = ["iced_graphics/image"] @@ -16,27 +16,21 @@ svg = ["resvg"] geometry = ["iced_graphics/geometry"] [dependencies] -raw-window-handle = "0.5" -softbuffer = "0.2" -tiny-skia = "0.10" -cosmic-text = "0.9" -bytemuck = "1" -rustc-hash = "1.1" -kurbo = "0.9" -log = "0.4" +iced_graphics.workspace = true -[dependencies.iced_graphics] -version = "0.9" -path = "../graphics" +bytemuck.workspace = true +cosmic-text.workspace = true +kurbo.workspace = true +log.workspace = true +raw-window-handle.workspace = true +rustc-hash.workspace = true +softbuffer.workspace = true +tiny-skia.workspace = true +twox-hash.workspace = true -[dependencies.twox-hash] -version = "1.6" -default-features = false +resvg.workspace = true +resvg.optional = true -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.twox-hash] -version = "1.6.1" -features = ["std"] - -[dependencies.resvg] -version = "0.35" -optional = true +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +twox-hash.workspace = true +twox-hash.features = ["std"] diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs index 0fae7364..047bc0ff 100644 --- a/tiny_skia/src/geometry.rs +++ b/tiny_skia/src/geometry.rs @@ -154,8 +154,16 @@ impl Frame { .pre_concat(tiny_skia::Transform::from_rotate(angle.to_degrees())); } - pub fn scale(&mut self, scale: f32) { - self.transform = self.transform.pre_scale(scale, scale); + pub fn scale(&mut self, scale: impl Into<f32>) { + let scale = scale.into(); + + self.scale_nonuniform(Vector { x: scale, y: scale }); + } + + pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) { + let scale = scale.into(); + + self.transform = self.transform.pre_scale(scale.x, scale.y); } pub fn into_primitive(self) -> Primitive { @@ -295,7 +303,7 @@ pub fn into_fill_rule(rule: fill::Rule) -> tiny_skia::FillRule { } } -pub fn into_stroke(stroke: &Stroke) -> tiny_skia::Stroke { +pub fn into_stroke(stroke: &Stroke<'_>) -> tiny_skia::Stroke { tiny_skia::Stroke { width: stroke.width, line_cap: match stroke.line_cap { diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs index 15de6ce2..e48468e9 100644 --- a/tiny_skia/src/lib.rs +++ b/tiny_skia/src/lib.rs @@ -1,3 +1,16 @@ +#![forbid(rust_2018_idioms)] +#![deny( + unsafe_code, + unused_results, + clippy::extra_unused_lifetimes, + clippy::from_over_into, + clippy::needless_borrow, + clippy::new_without_default, + clippy::useless_conversion, + rustdoc::broken_intra_doc_links +)] +#![allow(clippy::inherent_to_string, clippy::type_complexity)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod window; mod backend; diff --git a/tiny_skia/src/raster.rs b/tiny_skia/src/raster.rs index dedb127c..d13b1167 100644 --- a/tiny_skia/src/raster.rs +++ b/tiny_skia/src/raster.rs @@ -85,14 +85,14 @@ impl Cache { ); } - entry.insert(Some(Entry { + let _ = entry.insert(Some(Entry { width: image.width(), height: image.height(), pixels: buffer, })); } - self.hits.insert(id); + let _ = self.hits.insert(id); self.entries.get(&id).unwrap().as_ref().map(|entry| { tiny_skia::PixmapRef::from_bytes( bytemuck::cast_slice(&entry.pixels), diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index 820e7bd8..cb3ef54c 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -267,10 +267,10 @@ impl GlyphCache { } } - entry.insert((buffer, image.placement)); + let _ = entry.insert((buffer, image.placement)); } - self.recently_used.insert(key); + let _ = self.recently_used.insert(key); self.entries.get(&key).map(|(buffer, placement)| { (bytemuck::cast_slice(buffer.as_slice()), *placement) diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs index 433ca0f5..490b9f69 100644 --- a/tiny_skia/src/vector.rs +++ b/tiny_skia/src/vector.rs @@ -92,10 +92,10 @@ impl Cache { } }; - entry.insert(svg); + let _ = entry.insert(svg); } - self.tree_hits.insert(id); + let _ = self.tree_hits.insert(id); self.trees.get(&id).unwrap().as_ref() } @@ -178,10 +178,10 @@ impl Cache { } } - self.rasters.insert(key, image); + let _ = self.rasters.insert(key, image); } - self.raster_hits.insert(key); + let _ = self.raster_hits.insert(key); self.rasters.get(&key).map(tiny_skia::Pixmap::as_ref) } diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index a996fffc..828e522f 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -46,6 +46,7 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> { width: u32, height: u32, ) -> Surface { + #[allow(unsafe_code)] let window = unsafe { softbuffer::GraphicsContext::new(window, window) } .expect("Create softbuffer for window"); diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 09740f54..a460c127 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -1,54 +1,45 @@ [package] name = "iced_wgpu" -version = "0.11.1" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "A wgpu renderer for Iced" -license = "MIT AND OFL-1.1" -repository = "https://github.com/iced-rs/iced" +description = "A renderer for iced on top of wgpu" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] +all-features = true [features] geometry = ["iced_graphics/geometry", "lyon"] image = ["iced_graphics/image"] svg = ["resvg"] web-colors = ["iced_graphics/web-colors"] +webgl = ["wgpu/webgl"] [dependencies] -wgpu = "0.16" -glyphon = "0.3" -raw-window-handle = "0.5" -guillotiere = "0.6" -futures = "0.3" -bitflags = "1.2" -once_cell = "1.0" -log = "0.4" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wgpu = { version = "0.16", features = ["webgl"] } - -[dependencies.bytemuck] -version = "1.9" -features = ["derive"] - -[dependencies.iced_graphics] -version = "0.9" -path = "../graphics" - -[dependencies.glam] -version = "0.24" - -[dependencies.lyon] -version = "1.0" -optional = true - -[dependencies.resvg] -version = "0.35" -optional = true - -[dependencies.tracing] -version = "0.1.6" -optional = true - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true +iced_graphics.workspace = true + +bitflags.workspace = true +bytemuck.workspace = true +futures.workspace = true +glam.workspace = true +glyphon.workspace = true +guillotiere.workspace = true +log.workspace = true +once_cell.workspace = true +raw-window-handle.workspace = true +wgpu.workspace = true + +lyon.workspace = true +lyon.optional = true + +resvg.workspace = true +resvg.optional = true + +tracing.workspace = true +tracing.optional = true diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index e421e0b0..63a59c05 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -310,13 +310,11 @@ impl Frame { /// resulting glyphs will not be rotated or scaled properly. /// /// Additionally, all text will be rendered on top of all the layers of - /// a [`Canvas`]. Therefore, it is currently only meant to be used for + /// a `Canvas`. Therefore, it is currently only meant to be used for /// overlays, which is the most common use case. /// /// Support for vectorial text is planned, and should address all these /// limitations. - /// - /// [`Canvas`]: crate::widget::Canvas pub fn fill_text(&mut self, text: impl Into<Text>) { let text = text.into(); @@ -444,11 +442,21 @@ impl Frame { self.transforms.current.is_identity = false; } - /// Applies a scaling to the current transform of the [`Frame`]. + /// Applies a uniform scaling to the current transform of the [`Frame`]. + #[inline] + pub fn scale(&mut self, scale: impl Into<f32>) { + let scale = scale.into(); + + self.scale_nonuniform(Vector { x: scale, y: scale }); + } + + /// Applies a non-uniform scaling to the current transform of the [`Frame`]. #[inline] - pub fn scale(&mut self, scale: f32) { + pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) { + let scale = scale.into(); + self.transforms.current.raw = - self.transforms.current.raw.pre_scale(scale, scale); + self.transforms.current.raw.pre_scale(scale.x, scale.y); self.transforms.current.is_identity = false; } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index cd457072..2f483751 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -20,6 +20,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(rust_2018_idioms)] #![deny( missing_debug_implementations, //missing_docs, @@ -29,9 +30,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub mod layer; diff --git a/wgpu/src/quad/gradient.rs b/wgpu/src/quad/gradient.rs index 6db37252..a8e83d01 100644 --- a/wgpu/src/quad/gradient.rs +++ b/wgpu/src/quad/gradient.rs @@ -1,3 +1,4 @@ +use crate::graphics::color; use crate::graphics::gradient; use crate::quad::{self, Quad}; use crate::Buffer; @@ -78,7 +79,23 @@ impl Pipeline { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.quad.gradient.shader"), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( - include_str!("../shader/quad.wgsl"), + if color::GAMMA_CORRECTION { + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/gradient.wgsl"), + "\n", + include_str!("../shader/color/oklab.wgsl") + ) + } else { + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/gradient.wgsl"), + "\n", + include_str!("../shader/color/linear_rgb.wgsl") + ) + }, )), }); diff --git a/wgpu/src/quad/solid.rs b/wgpu/src/quad/solid.rs index f8f1e3a5..9bc6b466 100644 --- a/wgpu/src/quad/solid.rs +++ b/wgpu/src/quad/solid.rs @@ -72,7 +72,11 @@ impl Pipeline { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.quad.solid.shader"), source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed( - include_str!("../shader/quad.wgsl"), + concat!( + include_str!("../shader/quad.wgsl"), + "\n", + include_str!("../shader/quad/solid.wgsl"), + ), )), }); diff --git a/wgpu/src/shader/color/linear_rgb.wgsl b/wgpu/src/shader/color/linear_rgb.wgsl new file mode 100644 index 00000000..a5cf45d4 --- /dev/null +++ b/wgpu/src/shader/color/linear_rgb.wgsl @@ -0,0 +1,3 @@ +fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> { + return mix(from_, to_, factor); +} diff --git a/wgpu/src/shader/color/oklab.wgsl b/wgpu/src/shader/color/oklab.wgsl new file mode 100644 index 00000000..0dc37ba6 --- /dev/null +++ b/wgpu/src/shader/color/oklab.wgsl @@ -0,0 +1,26 @@ +const to_lms = mat3x4<f32>( + vec4<f32>(0.4121656120, 0.2118591070, 0.0883097947, 0.0), + vec4<f32>(0.5362752080, 0.6807189584, 0.2818474174, 0.0), + vec4<f32>(0.0514575653, 0.1074065790, 0.6302613616, 0.0), +); + +const to_rgb = mat3x4<f32>( + vec4<f32>( 4.0767245293, -3.3072168827, 0.2307590544, 0.0), + vec4<f32>(-1.2681437731, 2.6093323231, -0.3411344290, 0.0), + vec4<f32>(-0.0041119885, -0.7034763098, 1.7068625689, 0.0), +); + +fn interpolate_color(from_: vec4<f32>, to_: vec4<f32>, factor: f32) -> vec4<f32> { + // To Oklab + let lms_a = pow(from_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let lms_b = pow(to_ * to_lms, vec3<f32>(1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0)); + let mixed = mix(lms_a, lms_b, factor); + + // Back to linear RGB + var color = to_rgb * (mixed * mixed * mixed); + + // Alpha interpolation + color.a = mix(from_.a, to_.a, factor); + + return color; +} diff --git a/wgpu/src/shader/quad.wgsl b/wgpu/src/shader/quad.wgsl index fb402158..f919cfe2 100644 --- a/wgpu/src/shader/quad.wgsl +++ b/wgpu/src/shader/quad.wgsl @@ -37,309 +37,3 @@ fn select_border_radius(radi: vec4<f32>, position: vec2<f32>, center: vec2<f32>) rx = select(rx, ry, position.y > center.y); return rx; } - -fn unpack_u32(color: vec2<u32>) -> vec4<f32> { - let rg: vec2<f32> = unpack2x16float(color.x); - let ba: vec2<f32> = unpack2x16float(color.y); - - return vec4<f32>(rg.y, rg.x, ba.y, ba.x); -} - -struct SolidVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) color: vec4<f32>, - @location(2) pos: vec2<f32>, - @location(3) scale: vec2<f32>, - @location(4) border_color: vec4<f32>, - @location(5) border_radius: vec4<f32>, - @location(6) border_width: f32, -} - -struct SolidVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) color: vec4<f32>, - @location(1) border_color: vec4<f32>, - @location(2) pos: vec2<f32>, - @location(3) scale: vec2<f32>, - @location(4) border_radius: vec4<f32>, - @location(5) border_width: f32, -} - -@vertex -fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { - var out: SolidVertexOutput; - - var pos: vec2<f32> = input.pos * globals.scale; - var scale: vec2<f32> = input.scale * globals.scale; - - var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; - var border_radius: vec4<f32> = vec4<f32>( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4<f32> = mat4x4<f32>( - vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), - vec4<f32>(0.0, 0.0, 1.0, 0.0), - vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); - out.color = input.color; - out.border_color = input.border_color; - out.pos = pos; - out.scale = scale; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -@fragment -fn solid_fs_main( - input: SolidVertexOutput -) -> @location(0) vec4<f32> { - var mixed_color: vec4<f32> = input.color; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (input.pos + input.scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - input.pos + vec2<f32>(input.border_width, input.border_width), - input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(input.color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - vec2<f32>(input.position.x, input.position.y), - input.pos, - input.scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist - ); - - return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} - -struct GradientVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, - @location(7) position_and_scale: vec4<f32>, - @location(8) border_color: vec4<f32>, - @location(9) border_radius: vec4<f32>, - @location(10) border_width: f32, -} - -struct GradientVertexOutput { - @builtin(position) position: vec4<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, - @location(7) position_and_scale: vec4<f32>, - @location(8) border_color: vec4<f32>, - @location(9) border_radius: vec4<f32>, - @location(10) border_width: f32, -} - -@vertex -fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { - var out: GradientVertexOutput; - - var pos: vec2<f32> = input.position_and_scale.xy * globals.scale; - var scale: vec2<f32> = input.position_and_scale.zw * globals.scale; - - var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; - var border_radius: vec4<f32> = vec4<f32>( - min(input.border_radius.x, min_border_radius), - min(input.border_radius.y, min_border_radius), - min(input.border_radius.z, min_border_radius), - min(input.border_radius.w, min_border_radius) - ); - - var transform: mat4x4<f32> = mat4x4<f32>( - vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), - vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), - vec4<f32>(0.0, 0.0, 1.0, 0.0), - vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) - ); - - out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); - out.colors_1 = input.colors_1; - out.colors_2 = input.colors_2; - out.colors_3 = input.colors_3; - out.colors_4 = input.colors_4; - out.offsets = input.offsets; - out.direction = input.direction * globals.scale; - out.position_and_scale = vec4<f32>(pos, scale); - out.border_color = input.border_color; - out.border_radius = border_radius * globals.scale; - out.border_width = input.border_width * globals.scale; - - return out; -} - -fn random(coords: vec2<f32>) -> f32 { - return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); -} - -/// Returns the current interpolated color with a max 8-stop gradient -fn gradient( - raw_position: vec2<f32>, - direction: vec4<f32>, - colors: array<vec4<f32>, 8>, - offsets: array<f32, 8>, - last_index: i32 -) -> vec4<f32> { - let start = direction.xy; - let end = direction.zw; - - let v1 = end - start; - let v2 = raw_position - start; - let unit = normalize(v1); - let coord_offset = dot(unit, v2) / length(v1); - - //need to store these as a var to use dynamic indexing in a loop - //this is already added to wgsl spec but not in wgpu yet - var colors_arr = colors; - var offsets_arr = offsets; - - var color: vec4<f32>; - - let noise_granularity: f32 = 0.3/255.0; - - for (var i: i32 = 0; i < last_index; i++) { - let curr_offset = offsets_arr[i]; - let next_offset = offsets_arr[i+1]; - - if (coord_offset <= offsets_arr[0]) { - color = colors_arr[0]; - } - - if (curr_offset <= coord_offset && coord_offset <= next_offset) { - color = mix(colors_arr[i], colors_arr[i+1], smoothstep( - curr_offset, - next_offset, - coord_offset, - )); - } - - if (coord_offset >= offsets_arr[last_index]) { - color = colors_arr[last_index]; - } - } - - return color + mix(-noise_granularity, noise_granularity, random(raw_position)); -} - -@fragment -fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { - let colors = array<vec4<f32>, 8>( - unpack_u32(input.colors_1.xy), - unpack_u32(input.colors_1.zw), - unpack_u32(input.colors_2.xy), - unpack_u32(input.colors_2.zw), - unpack_u32(input.colors_3.xy), - unpack_u32(input.colors_3.zw), - unpack_u32(input.colors_4.xy), - unpack_u32(input.colors_4.zw), - ); - - let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); - let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); - - var offsets = array<f32, 8>( - offsets_1.x, - offsets_1.y, - offsets_1.z, - offsets_1.w, - offsets_2.x, - offsets_2.y, - offsets_2.z, - offsets_2.w, - ); - - //TODO could just pass this in to the shader but is probably more performant to just check it here - var last_index = 7; - for (var i: i32 = 0; i <= 7; i++) { - if (offsets[i] > 1.0) { - last_index = i - 1; - break; - } - } - - var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index); - - let pos = input.position_and_scale.xy; - let scale = input.position_and_scale.zw; - - var border_radius = select_border_radius( - input.border_radius, - input.position.xy, - (pos + scale * 0.5).xy - ); - - if (input.border_width > 0.0) { - var internal_border: f32 = max(border_radius - input.border_width, 0.0); - - var internal_distance: f32 = distance_alg( - input.position.xy, - pos + vec2<f32>(input.border_width, input.border_width), - scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), - internal_border - ); - - var border_mix: f32 = smoothstep( - max(internal_border - 0.5, 0.0), - internal_border + 0.5, - internal_distance - ); - - mixed_color = mix(mixed_color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); - } - - var dist: f32 = distance_alg( - input.position.xy, - pos, - scale, - border_radius - ); - - var radius_alpha: f32 = 1.0 - smoothstep( - max(border_radius - 0.5, 0.0), - border_radius + 0.5, - dist); - - return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); -} diff --git a/wgpu/src/shader/quad/gradient.wgsl b/wgpu/src/shader/quad/gradient.wgsl new file mode 100644 index 00000000..0754e97f --- /dev/null +++ b/wgpu/src/shader/quad/gradient.wgsl @@ -0,0 +1,205 @@ +struct GradientVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, + @location(7) position_and_scale: vec4<f32>, + @location(8) border_color: vec4<f32>, + @location(9) border_radius: vec4<f32>, + @location(10) border_width: f32, +} + +struct GradientVertexOutput { + @builtin(position) position: vec4<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, + @location(7) position_and_scale: vec4<f32>, + @location(8) border_color: vec4<f32>, + @location(9) border_radius: vec4<f32>, + @location(10) border_width: f32, +} + +@vertex +fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { + var out: GradientVertexOutput; + + var pos: vec2<f32> = input.position_and_scale.xy * globals.scale; + var scale: vec2<f32> = input.position_and_scale.zw * globals.scale; + + var min_border_radius = min(input.position_and_scale.z, input.position_and_scale.w) * 0.5; + var border_radius: vec4<f32> = vec4<f32>( + min(input.border_radius.x, min_border_radius), + min(input.border_radius.y, min_border_radius), + min(input.border_radius.z, min_border_radius), + min(input.border_radius.w, min_border_radius) + ); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), + vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) + ); + + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + out.colors_1 = input.colors_1; + out.colors_2 = input.colors_2; + out.colors_3 = input.colors_3; + out.colors_4 = input.colors_4; + out.offsets = input.offsets; + out.direction = input.direction * globals.scale; + out.position_and_scale = vec4<f32>(pos, scale); + out.border_color = input.border_color; + out.border_radius = border_radius * globals.scale; + out.border_width = input.border_width * globals.scale; + + return out; +} + +fn random(coords: vec2<f32>) -> f32 { + return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); +} + +/// Returns the current interpolated color with a max 8-stop gradient +fn gradient( + raw_position: vec2<f32>, + direction: vec4<f32>, + colors: array<vec4<f32>, 8>, + offsets: array<f32, 8>, + last_index: i32 +) -> vec4<f32> { + let start = direction.xy; + let end = direction.zw; + + let v1 = end - start; + let v2 = raw_position - start; + let unit = normalize(v1); + let coord_offset = dot(unit, v2) / length(v1); + + //need to store these as a var to use dynamic indexing in a loop + //this is already added to wgsl spec but not in wgpu yet + var colors_arr = colors; + var offsets_arr = offsets; + + var color: vec4<f32>; + + let noise_granularity: f32 = 0.3/255.0; + + for (var i: i32 = 0; i < last_index; i++) { + let curr_offset = offsets_arr[i]; + let next_offset = offsets_arr[i+1]; + + if (coord_offset <= offsets_arr[0]) { + color = colors_arr[0]; + } + + if (curr_offset <= coord_offset && coord_offset <= next_offset) { + let from_ = colors_arr[i]; + let to_ = colors_arr[i+1]; + let factor = smoothstep(curr_offset, next_offset, coord_offset); + + color = interpolate_color(from_, to_, factor); + } + + if (coord_offset >= offsets_arr[last_index]) { + color = colors_arr[last_index]; + } + } + + return color + mix(-noise_granularity, noise_granularity, random(raw_position)); +} + +@fragment +fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { + let colors = array<vec4<f32>, 8>( + unpack_u32(input.colors_1.xy), + unpack_u32(input.colors_1.zw), + unpack_u32(input.colors_2.xy), + unpack_u32(input.colors_2.zw), + unpack_u32(input.colors_3.xy), + unpack_u32(input.colors_3.zw), + unpack_u32(input.colors_4.xy), + unpack_u32(input.colors_4.zw), + ); + + let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); + let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); + + var offsets = array<f32, 8>( + offsets_1.x, + offsets_1.y, + offsets_1.z, + offsets_1.w, + offsets_2.x, + offsets_2.y, + offsets_2.z, + offsets_2.w, + ); + + //TODO could just pass this in to the shader but is probably more performant to just check it here + var last_index = 7; + for (var i: i32 = 0; i <= 7; i++) { + if (offsets[i] > 1.0) { + last_index = i - 1; + break; + } + } + + var mixed_color: vec4<f32> = gradient(input.position.xy, input.direction, colors, offsets, last_index); + + let pos = input.position_and_scale.xy; + let scale = input.position_and_scale.zw; + + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (pos + scale * 0.5).xy + ); + + if (input.border_width > 0.0) { + var internal_border: f32 = max(border_radius - input.border_width, 0.0); + + var internal_distance: f32 = distance_alg( + input.position.xy, + pos + vec2<f32>(input.border_width, input.border_width), + scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), + internal_border + ); + + var border_mix: f32 = smoothstep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(mixed_color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); + } + + var dist: f32 = distance_alg( + input.position.xy, + pos, + scale, + border_radius + ); + + var radius_alpha: f32 = 1.0 - smoothstep( + max(border_radius - 0.5, 0.0), + border_radius + 0.5, + dist); + + return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} + +fn unpack_u32(color: vec2<u32>) -> vec4<f32> { + let rg: vec2<f32> = unpack2x16float(color.x); + let ba: vec2<f32> = unpack2x16float(color.y); + + return vec4<f32>(rg.y, rg.x, ba.y, ba.x); +} diff --git a/wgpu/src/shader/quad/solid.wgsl b/wgpu/src/shader/quad/solid.wgsl new file mode 100644 index 00000000..ebd6d877 --- /dev/null +++ b/wgpu/src/shader/quad/solid.wgsl @@ -0,0 +1,99 @@ +struct SolidVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) color: vec4<f32>, + @location(2) pos: vec2<f32>, + @location(3) scale: vec2<f32>, + @location(4) border_color: vec4<f32>, + @location(5) border_radius: vec4<f32>, + @location(6) border_width: f32, +} + +struct SolidVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) color: vec4<f32>, + @location(1) border_color: vec4<f32>, + @location(2) pos: vec2<f32>, + @location(3) scale: vec2<f32>, + @location(4) border_radius: vec4<f32>, + @location(5) border_width: f32, +} + +@vertex +fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { + var out: SolidVertexOutput; + + var pos: vec2<f32> = input.pos * globals.scale; + var scale: vec2<f32> = input.scale * globals.scale; + + var min_border_radius = min(input.scale.x, input.scale.y) * 0.5; + var border_radius: vec4<f32> = vec4<f32>( + min(input.border_radius.x, min_border_radius), + min(input.border_radius.y, min_border_radius), + min(input.border_radius.z, min_border_radius), + min(input.border_radius.w, min_border_radius) + ); + + var transform: mat4x4<f32> = mat4x4<f32>( + vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0), + vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0), + vec4<f32>(0.0, 0.0, 1.0, 0.0), + vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0) + ); + + out.position = globals.transform * transform * vec4<f32>(input.v_pos, 0.0, 1.0); + out.color = input.color; + out.border_color = input.border_color; + out.pos = pos; + out.scale = scale; + out.border_radius = border_radius * globals.scale; + out.border_width = input.border_width * globals.scale; + + return out; +} + +@fragment +fn solid_fs_main( + input: SolidVertexOutput +) -> @location(0) vec4<f32> { + var mixed_color: vec4<f32> = input.color; + + var border_radius = select_border_radius( + input.border_radius, + input.position.xy, + (input.pos + input.scale * 0.5).xy + ); + + if (input.border_width > 0.0) { + var internal_border: f32 = max(border_radius - input.border_width, 0.0); + + var internal_distance: f32 = distance_alg( + input.position.xy, + input.pos + vec2<f32>(input.border_width, input.border_width), + input.scale - vec2<f32>(input.border_width * 2.0, input.border_width * 2.0), + internal_border + ); + + var border_mix: f32 = smoothstep( + max(internal_border - 0.5, 0.0), + internal_border + 0.5, + internal_distance + ); + + mixed_color = mix(input.color, input.border_color, vec4<f32>(border_mix, border_mix, border_mix, border_mix)); + } + + var dist: f32 = distance_alg( + vec2<f32>(input.position.x, input.position.y), + input.pos, + input.scale, + border_radius + ); + + var radius_alpha: f32 = 1.0 - smoothstep( + max(border_radius - 0.5, 0.0), + border_radius + 0.5, + dist + ); + + return vec4<f32>(mixed_color.x, mixed_color.y, mixed_color.z, mixed_color.w * radius_alpha); +} diff --git a/wgpu/src/shader/triangle.wgsl b/wgpu/src/shader/triangle.wgsl index 9f512d14..e4c19344 100644 --- a/wgpu/src/shader/triangle.wgsl +++ b/wgpu/src/shader/triangle.wgsl @@ -3,163 +3,3 @@ struct Globals { } @group(0) @binding(0) var<uniform> globals: Globals; - -fn unpack_u32(color: vec2<u32>) -> vec4<f32> { - let rg: vec2<f32> = unpack2x16float(color.x); - let ba: vec2<f32> = unpack2x16float(color.y); - - return vec4<f32>(rg.y, rg.x, ba.y, ba.x); -} - -struct SolidVertexInput { - @location(0) position: vec2<f32>, - @location(1) color: vec4<f32>, -} - -struct SolidVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) color: vec4<f32>, -} - -@vertex -fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { - var out: SolidVertexOutput; - - out.color = input.color; - out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0); - - return out; -} - -@fragment -fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { - return input.color; -} - -struct GradientVertexInput { - @location(0) v_pos: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, -} - -struct GradientVertexOutput { - @builtin(position) position: vec4<f32>, - @location(0) raw_position: vec2<f32>, - @location(1) colors_1: vec4<u32>, - @location(2) colors_2: vec4<u32>, - @location(3) colors_3: vec4<u32>, - @location(4) colors_4: vec4<u32>, - @location(5) offsets: vec4<u32>, - @location(6) direction: vec4<f32>, -} - -@vertex -fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { - var output: GradientVertexOutput; - - output.position = globals.transform * vec4<f32>(input.v_pos, 0.0, 1.0); - output.raw_position = input.v_pos; - output.colors_1 = input.colors_1; - output.colors_2 = input.colors_2; - output.colors_3 = input.colors_3; - output.colors_4 = input.colors_4; - output.offsets = input.offsets; - output.direction = input.direction; - - return output; -} - -fn random(coords: vec2<f32>) -> f32 { - return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); -} - -/// Returns the current interpolated color with a max 8-stop gradient -fn gradient( - raw_position: vec2<f32>, - direction: vec4<f32>, - colors: array<vec4<f32>, 8>, - offsets: array<f32, 8>, - last_index: i32 -) -> vec4<f32> { - let start = direction.xy; - let end = direction.zw; - - let v1 = end - start; - let v2 = raw_position - start; - let unit = normalize(v1); - let coord_offset = dot(unit, v2) / length(v1); - - //need to store these as a var to use dynamic indexing in a loop - //this is already added to wgsl spec but not in wgpu yet - var colors_arr = colors; - var offsets_arr = offsets; - - var color: vec4<f32>; - - let noise_granularity: f32 = 0.3/255.0; - - for (var i: i32 = 0; i < last_index; i++) { - let curr_offset = offsets_arr[i]; - let next_offset = offsets_arr[i+1]; - - if (coord_offset <= offsets_arr[0]) { - color = colors_arr[0]; - } - - if (curr_offset <= coord_offset && coord_offset <= next_offset) { - color = mix(colors_arr[i], colors_arr[i+1], smoothstep( - curr_offset, - next_offset, - coord_offset, - )); - } - - if (coord_offset >= offsets_arr[last_index]) { - color = colors_arr[last_index]; - } - } - - return color + mix(-noise_granularity, noise_granularity, random(raw_position)); -} - -@fragment -fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { - let colors = array<vec4<f32>, 8>( - unpack_u32(input.colors_1.xy), - unpack_u32(input.colors_1.zw), - unpack_u32(input.colors_2.xy), - unpack_u32(input.colors_2.zw), - unpack_u32(input.colors_3.xy), - unpack_u32(input.colors_3.zw), - unpack_u32(input.colors_4.xy), - unpack_u32(input.colors_4.zw), - ); - - let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); - let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); - - var offsets = array<f32, 8>( - offsets_1.x, - offsets_1.y, - offsets_1.z, - offsets_1.w, - offsets_2.x, - offsets_2.y, - offsets_2.z, - offsets_2.w, - ); - - var last_index = 7; - for (var i: i32 = 0; i <= 7; i++) { - if (offsets[i] >= 1.0) { - last_index = i; - break; - } - } - - return gradient(input.raw_position, input.direction, colors, offsets, last_index); -} diff --git a/wgpu/src/shader/triangle/gradient.wgsl b/wgpu/src/shader/triangle/gradient.wgsl new file mode 100644 index 00000000..1a8ae3b5 --- /dev/null +++ b/wgpu/src/shader/triangle/gradient.wgsl @@ -0,0 +1,134 @@ +struct GradientVertexInput { + @location(0) v_pos: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, +} + +struct GradientVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) raw_position: vec2<f32>, + @location(1) @interpolate(flat) colors_1: vec4<u32>, + @location(2) @interpolate(flat) colors_2: vec4<u32>, + @location(3) @interpolate(flat) colors_3: vec4<u32>, + @location(4) @interpolate(flat) colors_4: vec4<u32>, + @location(5) @interpolate(flat) offsets: vec4<u32>, + @location(6) direction: vec4<f32>, +} + +@vertex +fn gradient_vs_main(input: GradientVertexInput) -> GradientVertexOutput { + var output: GradientVertexOutput; + + output.position = globals.transform * vec4<f32>(input.v_pos, 0.0, 1.0); + output.raw_position = input.v_pos; + output.colors_1 = input.colors_1; + output.colors_2 = input.colors_2; + output.colors_3 = input.colors_3; + output.colors_4 = input.colors_4; + output.offsets = input.offsets; + output.direction = input.direction; + + return output; +} + +/// Returns the current interpolated color with a max 8-stop gradient +fn gradient( + raw_position: vec2<f32>, + direction: vec4<f32>, + colors: array<vec4<f32>, 8>, + offsets: array<f32, 8>, + last_index: i32 +) -> vec4<f32> { + let start = direction.xy; + let end = direction.zw; + + let v1 = end - start; + let v2 = raw_position - start; + let unit = normalize(v1); + let coord_offset = dot(unit, v2) / length(v1); + + //need to store these as a var to use dynamic indexing in a loop + //this is already added to wgsl spec but not in wgpu yet + var colors_arr = colors; + var offsets_arr = offsets; + + var color: vec4<f32>; + + let noise_granularity: f32 = 0.3/255.0; + + for (var i: i32 = 0; i < last_index; i++) { + let curr_offset = offsets_arr[i]; + let next_offset = offsets_arr[i+1]; + + if (coord_offset <= offsets_arr[0]) { + color = colors_arr[0]; + } + + if (curr_offset <= coord_offset && coord_offset <= next_offset) { + let from_ = colors_arr[i]; + let to_ = colors_arr[i+1]; + let factor = smoothstep(curr_offset, next_offset, coord_offset); + + color = interpolate_color(from_, to_, factor); + } + + if (coord_offset >= offsets_arr[last_index]) { + color = colors_arr[last_index]; + } + } + + return color + mix(-noise_granularity, noise_granularity, random(raw_position)); +} + +@fragment +fn gradient_fs_main(input: GradientVertexOutput) -> @location(0) vec4<f32> { + let colors = array<vec4<f32>, 8>( + unpack_u32(input.colors_1.xy), + unpack_u32(input.colors_1.zw), + unpack_u32(input.colors_2.xy), + unpack_u32(input.colors_2.zw), + unpack_u32(input.colors_3.xy), + unpack_u32(input.colors_3.zw), + unpack_u32(input.colors_4.xy), + unpack_u32(input.colors_4.zw), + ); + + let offsets_1: vec4<f32> = unpack_u32(input.offsets.xy); + let offsets_2: vec4<f32> = unpack_u32(input.offsets.zw); + + var offsets = array<f32, 8>( + offsets_1.x, + offsets_1.y, + offsets_1.z, + offsets_1.w, + offsets_2.x, + offsets_2.y, + offsets_2.z, + offsets_2.w, + ); + + var last_index = 7; + for (var i: i32 = 0; i <= 7; i++) { + if (offsets[i] >= 1.0) { + last_index = i; + break; + } + } + + return gradient(input.raw_position, input.direction, colors, offsets, last_index); +} + +fn unpack_u32(color: vec2<u32>) -> vec4<f32> { + let rg: vec2<f32> = unpack2x16float(color.x); + let ba: vec2<f32> = unpack2x16float(color.y); + + return vec4<f32>(rg.y, rg.x, ba.y, ba.x); +} + +fn random(coords: vec2<f32>) -> f32 { + return fract(sin(dot(coords, vec2(12.9898,78.233))) * 43758.5453); +} diff --git a/wgpu/src/shader/triangle/solid.wgsl b/wgpu/src/shader/triangle/solid.wgsl new file mode 100644 index 00000000..9ef81982 --- /dev/null +++ b/wgpu/src/shader/triangle/solid.wgsl @@ -0,0 +1,24 @@ +struct SolidVertexInput { + @location(0) position: vec2<f32>, + @location(1) color: vec4<f32>, +} + +struct SolidVertexOutput { + @builtin(position) position: vec4<f32>, + @location(0) color: vec4<f32>, +} + +@vertex +fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput { + var out: SolidVertexOutput; + + out.color = input.color; + out.position = globals.transform * vec4<f32>(input.position, 0.0, 1.0); + + return out; +} + +@fragment +fn solid_fs_main(input: SolidVertexOutput) -> @location(0) vec4<f32> { + return input.color; +} diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index d8b23dfe..d430e607 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -487,8 +487,10 @@ mod solid { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.triangle.solid.shader"), source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/triangle.wgsl" + std::borrow::Cow::Borrowed(concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!("shader/triangle/solid.wgsl"), )), ), }); @@ -537,6 +539,7 @@ mod solid { } mod gradient { + use crate::graphics::color; use crate::graphics::mesh; use crate::graphics::Antialiasing; use crate::triangle; @@ -633,9 +636,31 @@ mod gradient { device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("iced_wgpu.triangle.gradient.shader"), source: wgpu::ShaderSource::Wgsl( - std::borrow::Cow::Borrowed(include_str!( - "shader/triangle.wgsl" - )), + std::borrow::Cow::Borrowed( + if color::GAMMA_CORRECTION { + concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!( + "shader/triangle/gradient.wgsl" + ), + "\n", + include_str!("shader/color/oklab.wgsl") + ) + } else { + concat!( + include_str!("shader/triangle.wgsl"), + "\n", + include_str!( + "shader/triangle/gradient.wgsl" + ), + "\n", + include_str!( + "shader/color/linear_rgb.wgsl" + ) + ) + }, + ), ), }); diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 09e11fdc..a9521a15 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -6,8 +6,6 @@ use crate::graphics::compositor; use crate::graphics::{Error, Viewport}; use crate::{Backend, Primitive, Renderer, Settings}; -use futures::stream::{self, StreamExt}; - use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; use std::marker::PhantomData; @@ -95,14 +93,15 @@ impl<Theme> Compositor<Theme> { let limits = [wgpu::Limits::default(), wgpu::Limits::downlevel_defaults()]; - let limits = limits.into_iter().map(|limits| wgpu::Limits { + let mut limits = limits.into_iter().map(|limits| wgpu::Limits { max_bind_groups: 2, ..limits }); - let (device, queue) = stream::iter(limits) - .filter_map(|limits| async { - adapter.request_device( + let (device, queue) = + loop { + let limits = limits.next()?; + let device = adapter.request_device( &wgpu::DeviceDescriptor { label: Some( "iced_wgpu::window::compositor device descriptor", @@ -111,11 +110,12 @@ impl<Theme> Compositor<Theme> { limits, }, None, - ).await.ok() - }) - .boxed() - .next() - .await?; + ).await.ok(); + + if let Some(device) = device { + break Some(device); + } + }?; Some(Compositor { instance, diff --git a/widget/Cargo.toml b/widget/Cargo.toml index 128a7c38..6d62c181 100644 --- a/widget/Cargo.toml +++ b/widget/Cargo.toml @@ -1,14 +1,18 @@ [package] name = "iced_widget" -version = "0.1.3" -authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] -edition = "2021" -description = "The built-in widgets for Iced" -license = "MIT" -repository = "https://github.com/iced-rs/iced" -documentation = "https://docs.rs/iced_widget" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +description = "The built-in widgets for iced" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true + +[package.metadata.docs.rs] +rustdoc-args = ["--cfg", "docsrs"] +all-features = true [features] lazy = ["ouroboros"] @@ -18,31 +22,16 @@ canvas = ["iced_renderer/geometry"] qr_code = ["canvas", "qrcode"] [dependencies] -unicode-segmentation = "1.6" -num-traits = "0.2" -thiserror = "1" - -[dependencies.iced_runtime] -version = "0.1" -path = "../runtime" +iced_renderer.workspace = true +iced_runtime.workspace = true +iced_style.workspace = true -[dependencies.iced_renderer] -version = "0.1" -path = "../renderer" +num-traits.workspace = true +thiserror.workspace = true +unicode-segmentation.workspace = true -[dependencies.iced_style] -version = "0.9" -path = "../style" +ouroboros.workspace = true +ouroboros.optional = true -[dependencies.ouroboros] -version = "0.17" -optional = true - -[dependencies.qrcode] -version = "0.12" -optional = true -default-features = false - -[package.metadata.docs.rs] -rustdoc-args = ["--cfg", "docsrs"] -all-features = true +qrcode.workspace = true +qrcode.optional = true diff --git a/widget/src/button.rs b/widget/src/button.rs index 8ca4a542..4915bd49 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -119,9 +119,9 @@ where /// Sets the style variant of this [`Button`]. pub fn style( mut self, - style: <Renderer::Theme as StyleSheet>::Style, + style: impl Into<<Renderer::Theme as StyleSheet>::Style>, ) -> Self { - self.style = style; + self.style = style.into(); self } } diff --git a/widget/src/canvas/event.rs b/widget/src/canvas/event.rs index 4508c184..1288365f 100644 --- a/widget/src/canvas/event.rs +++ b/widget/src/canvas/event.rs @@ -7,7 +7,7 @@ pub use crate::core::event::Status; /// A [`Canvas`] event. /// -/// [`Canvas`]: crate::widget::Canvas +/// [`Canvas`]: crate::Canvas #[derive(Debug, Clone, Copy, PartialEq)] pub enum Event { /// A mouse event. diff --git a/widget/src/canvas/program.rs b/widget/src/canvas/program.rs index b3f6175e..2ac23061 100644 --- a/widget/src/canvas/program.rs +++ b/widget/src/canvas/program.rs @@ -8,7 +8,7 @@ use crate::graphics::geometry; /// A [`Program`] can mutate internal state and produce messages for an /// application. /// -/// [`Canvas`]: crate::widget::Canvas +/// [`Canvas`]: crate::Canvas pub trait Program<Message, Renderer = crate::Renderer> where Renderer: geometry::Renderer, @@ -26,7 +26,7 @@ where /// /// By default, this method does and returns nothing. /// - /// [`Canvas`]: crate::widget::Canvas + /// [`Canvas`]: crate::Canvas fn update( &self, _state: &mut Self::State, @@ -42,8 +42,9 @@ where /// [`Geometry`] can be easily generated with a [`Frame`] or stored in a /// [`Cache`]. /// - /// [`Frame`]: crate::widget::canvas::Frame - /// [`Cache`]: crate::widget::canvas::Cache + /// [`Geometry`]: crate::canvas::Geometry + /// [`Frame`]: crate::canvas::Frame + /// [`Cache`]: crate::canvas::Cache fn draw( &self, state: &Self::State, @@ -58,7 +59,7 @@ where /// The interaction returned will be in effect even if the cursor position /// is out of bounds of the program's [`Canvas`]. /// - /// [`Canvas`]: crate::widget::Canvas + /// [`Canvas`]: crate::Canvas fn mouse_interaction( &self, _state: &Self::State, diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 2860d496..d7fdf339 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -121,7 +121,7 @@ where self } - /// Sets the text [`LineHeight`] of the [`Checkbox`]. + /// Sets the text [`text::LineHeight`] of the [`Checkbox`]. pub fn text_line_height( mut self, line_height: impl Into<text::LineHeight>, @@ -136,9 +136,9 @@ where self } - /// Sets the [`Font`] of the text of the [`Checkbox`]. + /// Sets the [`Renderer::Font`] of the text of the [`Checkbox`]. /// - /// [`Font`]: crate::text::Renderer::Font + /// [`Renderer::Font`]: crate::core::text::Renderer pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { self.font = Some(font.into()); self diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index 650954ef..d6915281 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -20,7 +20,7 @@ use std::time::Instant; /// /// This widget is composed by a [`TextInput`] that can be filled with the text /// to search for corresponding values from the list of options that are displayed -/// as a [`Menu`]. +/// as a Menu. #[allow(missing_debug_implementations)] pub struct ComboBox<'a, T, Message, Renderer = crate::Renderer> where @@ -131,14 +131,16 @@ where self } - /// Sets the [`Font`] of the [`ComboBox`]. + /// Sets the [`Renderer::Font`] of the [`ComboBox`]. + /// + /// [`Renderer::Font`]: text::Renderer pub fn font(mut self, font: Renderer::Font) -> Self { self.text_input = self.text_input.font(font); self.font = Some(font); self } - /// Sets the [`Icon`] of the [`ComboBox`]. + /// Sets the [`text_input::Icon`] of the [`ComboBox`]. pub fn icon(mut self, icon: text_input::Icon<Renderer::Font>) -> Self { self.text_input = self.text_input.icon(icon); self diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index c885d724..3c9c2b29 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -26,7 +26,7 @@ use std::ops::RangeInclusive; /// Creates a [`Column`] with the given children. /// -/// [`Column`]: widget::Column +/// [`Column`]: crate::Column #[macro_export] macro_rules! column { () => ( @@ -39,7 +39,7 @@ macro_rules! column { /// Creates a [`Row`] with the given children. /// -/// [`Row`]: widget::Row +/// [`Row`]: crate::Row #[macro_export] macro_rules! row { () => ( @@ -52,7 +52,7 @@ macro_rules! row { /// Creates a new [`Container`] with the provided content. /// -/// [`Container`]: widget::Container +/// [`Container`]: crate::Container pub fn container<'a, Message, Renderer>( content: impl Into<Element<'a, Message, Renderer>>, ) -> Container<'a, Message, Renderer> @@ -82,7 +82,7 @@ where /// Creates a new [`Row`] with the given children. /// -/// [`Row`]: widget::Row +/// [`Row`]: crate::Row pub fn row<Message, Renderer>( children: Vec<Element<'_, Message, Renderer>>, ) -> Row<'_, Message, Renderer> { @@ -91,7 +91,7 @@ pub fn row<Message, Renderer>( /// Creates a new [`Scrollable`] with the provided content. /// -/// [`Scrollable`]: widget::Scrollable +/// [`Scrollable`]: crate::Scrollable pub fn scrollable<'a, Message, Renderer>( content: impl Into<Element<'a, Message, Renderer>>, ) -> Scrollable<'a, Message, Renderer> @@ -104,7 +104,7 @@ where /// Creates a new [`Button`] with the provided content. /// -/// [`Button`]: widget::Button +/// [`Button`]: crate::Button pub fn button<'a, Message, Renderer>( content: impl Into<Element<'a, Message, Renderer>>, ) -> Button<'a, Message, Renderer> @@ -118,8 +118,8 @@ where /// Creates a new [`Tooltip`] with the provided content, tooltip text, and [`tooltip::Position`]. /// -/// [`Tooltip`]: widget::Tooltip -/// [`tooltip::Position`]: widget::tooltip::Position +/// [`Tooltip`]: crate::Tooltip +/// [`tooltip::Position`]: crate::tooltip::Position pub fn tooltip<'a, Message, Renderer>( content: impl Into<Element<'a, Message, Renderer>>, tooltip: impl ToString, @@ -134,7 +134,7 @@ where /// Creates a new [`Text`] widget with the provided content. /// -/// [`Text`]: widget::Text +/// [`Text`]: core::widget::Text pub fn text<'a, Renderer>(text: impl ToString) -> Text<'a, Renderer> where Renderer: core::text::Renderer, @@ -145,7 +145,7 @@ where /// Creates a new [`Checkbox`]. /// -/// [`Checkbox`]: widget::Checkbox +/// [`Checkbox`]: crate::Checkbox pub fn checkbox<'a, Message, Renderer>( label: impl Into<String>, is_checked: bool, @@ -160,7 +160,7 @@ where /// Creates a new [`Radio`]. /// -/// [`Radio`]: widget::Radio +/// [`Radio`]: crate::Radio pub fn radio<Message, Renderer, V>( label: impl Into<String>, value: V, @@ -178,7 +178,7 @@ where /// Creates a new [`Toggler`]. /// -/// [`Toggler`]: widget::Toggler +/// [`Toggler`]: crate::Toggler pub fn toggler<'a, Message, Renderer>( label: impl Into<Option<String>>, is_checked: bool, @@ -193,7 +193,7 @@ where /// Creates a new [`TextInput`]. /// -/// [`TextInput`]: widget::TextInput +/// [`TextInput`]: crate::TextInput pub fn text_input<'a, Message, Renderer>( placeholder: &str, value: &str, @@ -208,7 +208,7 @@ where /// Creates a new [`Slider`]. /// -/// [`Slider`]: widget::Slider +/// [`Slider`]: crate::Slider pub fn slider<'a, T, Message, Renderer>( range: std::ops::RangeInclusive<T>, value: T, @@ -225,7 +225,7 @@ where /// Creates a new [`VerticalSlider`]. /// -/// [`VerticalSlider`]: widget::VerticalSlider +/// [`VerticalSlider`]: crate::VerticalSlider pub fn vertical_slider<'a, T, Message, Renderer>( range: std::ops::RangeInclusive<T>, value: T, @@ -242,7 +242,7 @@ where /// Creates a new [`PickList`]. /// -/// [`PickList`]: widget::PickList +/// [`PickList`]: crate::PickList pub fn pick_list<'a, Message, Renderer, T>( options: impl Into<Cow<'a, [T]>>, selected: Option<T>, @@ -264,7 +264,7 @@ where /// Creates a new [`ComboBox`]. /// -/// [`ComboBox`]: widget::ComboBox +/// [`ComboBox`]: crate::ComboBox pub fn combo_box<'a, T, Message, Renderer>( state: &'a combo_box::State<T>, placeholder: &str, @@ -281,21 +281,21 @@ where /// Creates a new horizontal [`Space`] with the given [`Length`]. /// -/// [`Space`]: widget::Space +/// [`Space`]: crate::Space pub fn horizontal_space(width: impl Into<Length>) -> Space { Space::with_width(width) } /// Creates a new vertical [`Space`] with the given [`Length`]. /// -/// [`Space`]: widget::Space +/// [`Space`]: crate::Space pub fn vertical_space(height: impl Into<Length>) -> Space { Space::with_height(height) } /// Creates a horizontal [`Rule`] with the given height. /// -/// [`Rule`]: widget::Rule +/// [`Rule`]: crate::Rule pub fn horizontal_rule<Renderer>(height: impl Into<Pixels>) -> Rule<Renderer> where Renderer: core::Renderer, @@ -306,7 +306,7 @@ where /// Creates a vertical [`Rule`] with the given width. /// -/// [`Rule`]: widget::Rule +/// [`Rule`]: crate::Rule pub fn vertical_rule<Renderer>(width: impl Into<Pixels>) -> Rule<Renderer> where Renderer: core::Renderer, @@ -321,7 +321,7 @@ where /// * an inclusive range of possible values, and /// * the current value of the [`ProgressBar`]. /// -/// [`ProgressBar`]: widget::ProgressBar +/// [`ProgressBar`]: crate::ProgressBar pub fn progress_bar<Renderer>( range: RangeInclusive<f32>, value: f32, @@ -335,7 +335,7 @@ where /// Creates a new [`Image`]. /// -/// [`Image`]: widget::Image +/// [`Image`]: crate::Image #[cfg(feature = "image")] pub fn image<Handle>(handle: impl Into<Handle>) -> crate::Image<Handle> { crate::Image::new(handle.into()) @@ -343,8 +343,8 @@ pub fn image<Handle>(handle: impl Into<Handle>) -> crate::Image<Handle> { /// Creates a new [`Svg`] widget from the given [`Handle`]. /// -/// [`Svg`]: widget::Svg -/// [`Handle`]: widget::svg::Handle +/// [`Svg`]: crate::Svg +/// [`Handle`]: crate::svg::Handle #[cfg(feature = "svg")] pub fn svg<Renderer>( handle: impl Into<core::svg::Handle>, @@ -357,6 +357,8 @@ where } /// Creates a new [`Canvas`]. +/// +/// [`Canvas`]: crate::Canvas #[cfg(feature = "canvas")] pub fn canvas<P, Message, Renderer>( program: P, diff --git a/widget/src/lib.rs b/widget/src/lib.rs index 707fec04..7e204171 100644 --- a/widget/src/lib.rs +++ b/widget/src/lib.rs @@ -2,6 +2,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(unsafe_code, rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -10,9 +11,9 @@ clippy::from_over_into, clippy::needless_borrow, clippy::new_without_default, - clippy::useless_conversion + clippy::useless_conversion, + rustdoc::broken_intra_doc_links )] -#![forbid(unsafe_code, rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub use iced_renderer as renderer; diff --git a/widget/src/overlay/menu.rs b/widget/src/overlay/menu.rs index 5a2e1bf0..b293f9fa 100644 --- a/widget/src/overlay/menu.rs +++ b/widget/src/overlay/menu.rs @@ -89,7 +89,7 @@ where self } - /// Sets the text [`LineHeight`] of the [`Menu`]. + /// Sets the text [`text::LineHeight`] of the [`Menu`]. pub fn text_line_height( mut self, line_height: impl Into<text::LineHeight>, diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 6e2b39a4..f868a648 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -1,6 +1,6 @@ //! Let your users split regions of your application and organize layout dynamically. //! -//! [](https://gfycat.com/mixedflatjellyfish) +//!  //! //! # Example //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, @@ -49,7 +49,7 @@ use crate::core::{ /// A collection of panes distributed using either vertical or horizontal splits /// to completely fill the space available. /// -/// [](https://gfycat.com/frailfreshairedaleterrier) +///  /// /// This distribution of space is common in tiling window managers (like /// [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even diff --git a/widget/src/pane_grid/configuration.rs b/widget/src/pane_grid/configuration.rs index ddbc3bc2..b8aa2c7d 100644 --- a/widget/src/pane_grid/configuration.rs +++ b/widget/src/pane_grid/configuration.rs @@ -2,7 +2,7 @@ use crate::pane_grid::Axis; /// The arrangement of a [`PaneGrid`]. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::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::widget::pane_grid::Pane + /// [`Pane`]: super::Pane Pane(T), } diff --git a/widget/src/pane_grid/content.rs b/widget/src/pane_grid/content.rs index 5dbc5496..826ea663 100644 --- a/widget/src/pane_grid/content.rs +++ b/widget/src/pane_grid/content.rs @@ -10,7 +10,7 @@ use crate::pane_grid::{Draggable, TitleBar}; /// The content of a [`Pane`]. /// -/// [`Pane`]: crate::widget::pane_grid::Pane +/// [`Pane`]: super::Pane #[allow(missing_debug_implementations)] pub struct Content<'a, Message, Renderer = crate::Renderer> where @@ -87,7 +87,7 @@ where /// Draws the [`Content`] with the provided [`Renderer`] and [`Layout`]. /// - /// [`Renderer`]: crate::Renderer + /// [`Renderer`]: crate::core::Renderer pub fn draw( &self, tree: &Tree, diff --git a/widget/src/pane_grid/node.rs b/widget/src/pane_grid/node.rs index 6de5920f..3c707f15 100644 --- a/widget/src/pane_grid/node.rs +++ b/widget/src/pane_grid/node.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; /// A layout node of a [`PaneGrid`]. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::PaneGrid #[derive(Debug, Clone)] pub enum Node { /// The region of this [`Node`] is split into two. diff --git a/widget/src/pane_grid/pane.rs b/widget/src/pane_grid/pane.rs index d6fbab83..cabf55c1 100644 --- a/widget/src/pane_grid/pane.rs +++ b/widget/src/pane_grid/pane.rs @@ -1,5 +1,5 @@ /// A rectangular region in a [`PaneGrid`] used to display widgets. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::PaneGrid #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Pane(pub(super) usize); diff --git a/widget/src/pane_grid/split.rs b/widget/src/pane_grid/split.rs index 8132272a..ce021978 100644 --- a/widget/src/pane_grid/split.rs +++ b/widget/src/pane_grid/split.rs @@ -1,5 +1,5 @@ /// A divider that splits a region in a [`PaneGrid`] into two different panes. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::PaneGrid #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Split(pub(super) usize); diff --git a/widget/src/pane_grid/state.rs b/widget/src/pane_grid/state.rs index 6fd15890..28a52cf0 100644 --- a/widget/src/pane_grid/state.rs +++ b/widget/src/pane_grid/state.rs @@ -1,6 +1,6 @@ //! The state of a [`PaneGrid`]. //! -//! [`PaneGrid`]: crate::widget::PaneGrid +//! [`PaneGrid`]: super::PaneGrid use crate::core::{Point, Size}; use crate::pane_grid::{ Axis, Configuration, Direction, Edge, Node, Pane, Region, Split, Target, @@ -18,23 +18,23 @@ use std::collections::HashMap; /// provided to the view function of [`PaneGrid::new`] for displaying each /// [`Pane`]. /// -/// [`PaneGrid`]: crate::widget::PaneGrid -/// [`PaneGrid::new`]: crate::widget::PaneGrid::new +/// [`PaneGrid`]: super::PaneGrid +/// [`PaneGrid::new`]: super::PaneGrid::new #[derive(Debug, Clone)] pub struct State<T> { /// The panes of the [`PaneGrid`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub panes: HashMap<Pane, T>, /// The internal state of the [`PaneGrid`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub internal: Internal, /// The maximized [`Pane`] of the [`PaneGrid`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub(super) maximized: Option<Pane>, } @@ -236,6 +236,8 @@ impl<T> State<T> { } /// Move [`Pane`] to an [`Edge`] of the [`PaneGrid`]. + /// + /// [`PaneGrid`]: super::PaneGrid pub fn move_to_edge(&mut self, pane: &Pane, edge: Edge) { match edge { Edge::Top => { @@ -269,8 +271,8 @@ impl<T> State<T> { /// If you want to swap panes on drag and drop in your [`PaneGrid`], you /// will need to call this method when handling a [`DragEvent`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid - /// [`DragEvent`]: crate::widget::pane_grid::DragEvent + /// [`PaneGrid`]: super::PaneGrid + /// [`DragEvent`]: super::DragEvent pub fn swap(&mut self, a: &Pane, b: &Pane) { self.internal.layout.update(&|node| match node { Node::Split { .. } => {} @@ -292,8 +294,8 @@ impl<T> State<T> { /// If you want to enable resize interactions in your [`PaneGrid`], you will /// need to call this method when handling a [`ResizeEvent`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid - /// [`ResizeEvent`]: crate::widget::pane_grid::ResizeEvent + /// [`PaneGrid`]: super::PaneGrid + /// [`ResizeEvent`]: super::ResizeEvent pub fn resize(&mut self, split: &Split, ratio: f32) { let _ = self.internal.layout.resize(split, ratio); } @@ -315,7 +317,7 @@ impl<T> State<T> { /// Maximize the given [`Pane`]. Only this pane will be rendered by the /// [`PaneGrid`] until [`Self::restore()`] is called. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub fn maximize(&mut self, pane: &Pane) { self.maximized = Some(*pane); } @@ -323,14 +325,14 @@ impl<T> State<T> { /// Restore the currently maximized [`Pane`] to it's normal size. All panes /// will be rendered by the [`PaneGrid`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub fn restore(&mut self) { let _ = self.maximized.take(); } /// Returns the maximized [`Pane`] of the [`PaneGrid`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub fn maximized(&self) -> Option<Pane> { self.maximized } @@ -338,7 +340,7 @@ impl<T> State<T> { /// The internal state of a [`PaneGrid`]. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::PaneGrid #[derive(Debug, Clone)] pub struct Internal { layout: Node, @@ -349,7 +351,7 @@ impl Internal { /// Initializes the [`Internal`] state of a [`PaneGrid`] from a /// [`Configuration`]. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid pub fn from_configuration<T>( panes: &mut HashMap<Pane, T>, content: Configuration<T>, @@ -394,16 +396,16 @@ impl Internal { /// The current action of a [`PaneGrid`]. /// -/// [`PaneGrid`]: crate::widget::PaneGrid +/// [`PaneGrid`]: super::PaneGrid #[derive(Debug, Clone, Copy, PartialEq)] pub enum Action { /// The [`PaneGrid`] is idle. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid Idle, /// A [`Pane`] in the [`PaneGrid`] is being dragged. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid Dragging { /// The [`Pane`] being dragged. pane: Pane, @@ -412,7 +414,7 @@ pub enum Action { }, /// A [`Split`] in the [`PaneGrid`] is being dragged. /// - /// [`PaneGrid`]: crate::widget::PaneGrid + /// [`PaneGrid`]: super::PaneGrid Resizing { /// The [`Split`] being dragged. split: Split, diff --git a/widget/src/pane_grid/title_bar.rs b/widget/src/pane_grid/title_bar.rs index 8a4523e8..5ae7a6a0 100644 --- a/widget/src/pane_grid/title_bar.rs +++ b/widget/src/pane_grid/title_bar.rs @@ -11,7 +11,7 @@ use crate::core::{ /// The title bar of a [`Pane`]. /// -/// [`Pane`]: crate::widget::pane_grid::Pane +/// [`Pane`]: super::Pane #[allow(missing_debug_implementations)] pub struct TitleBar<'a, Message, Renderer = crate::Renderer> where @@ -75,7 +75,7 @@ where /// [`TitleBar`] is hovered. /// /// [`controls`]: Self::controls - /// [`Pane`]: crate::widget::pane_grid::Pane + /// [`Pane`]: super::Pane pub fn always_show_controls(mut self) -> Self { self.always_show_controls = true; self @@ -114,7 +114,7 @@ where /// Draws the [`TitleBar`] with the provided [`Renderer`] and [`Layout`]. /// - /// [`Renderer`]: crate::Renderer + /// [`Renderer`]: crate::core::Renderer pub fn draw( &self, tree: &Tree, diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 8feb1788..056a5e65 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -105,7 +105,7 @@ where self } - /// Sets the text [`LineHeight`] of the [`PickList`]. + /// Sets the text [`text::LineHeight`] of the [`PickList`]. pub fn text_line_height( mut self, line_height: impl Into<text::LineHeight>, diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index d176021d..1dc4da7f 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -87,7 +87,7 @@ impl<'a, Message, Theme> Widget<Message, Renderer<Theme>> for QRCode<'a> { let geometry = self.state.cache.draw(renderer, bounds.size(), |frame| { // Scale units to cell size - frame.scale(f32::from(self.cell_size)); + frame.scale(self.cell_size); // Draw background frame.fill_rectangle( diff --git a/widget/src/radio.rs b/widget/src/radio.rs index a85dad63..57acc033 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -156,7 +156,7 @@ where self } - /// Sets the text [`LineHeight`] of the [`Radio`] button. + /// Sets the text [`text::LineHeight`] of the [`Radio`] button. pub fn text_line_height( mut self, line_height: impl Into<text::LineHeight>, diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index 5decfd9d..def28821 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -1151,6 +1151,16 @@ impl Viewport { RelativeOffset { x, y } } + + /// Returns the bounds of the current [`Viewport`]. + pub fn bounds(&self) -> Rectangle { + self.bounds + } + + /// Returns the content bounds of the current [`Viewport`]. + pub fn content_bounds(&self) -> Rectangle { + self.content_bounds + } } impl State { diff --git a/widget/src/slider.rs b/widget/src/slider.rs index a9727aa3..2c4a2913 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -137,8 +137,8 @@ where } /// Sets the step size of the [`Slider`]. - pub fn step(mut self, step: T) -> Self { - self.step = step; + pub fn step(mut self, step: impl Into<T>) -> Self { + self.step = step.into(); self } } diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index aa35b5e4..bfd196fd 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -182,7 +182,7 @@ where self } - /// Sets the [`LineHeight`] of the [`TextInput`]. + /// Sets the [`text::LineHeight`] of the [`TextInput`]. pub fn line_height( mut self, line_height: impl Into<text::LineHeight>, diff --git a/widget/src/text_input/value.rs b/widget/src/text_input/value.rs index cf4da562..d1b056c8 100644 --- a/widget/src/text_input/value.rs +++ b/widget/src/text_input/value.rs @@ -2,7 +2,7 @@ use unicode_segmentation::UnicodeSegmentation; /// The value of a [`TextInput`]. /// -/// [`TextInput`]: crate::widget::TextInput +/// [`TextInput`]: super::TextInput // TODO: Reduce allocations, cache results (?) #[derive(Debug, Clone)] pub struct Value { diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index acb9b25d..2440317f 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -109,7 +109,7 @@ where self } - /// Sets the text [`LineHeight`] of the [`Toggler`]. + /// Sets the text [`text::LineHeight`] of the [`Toggler`]. pub fn text_line_height( mut self, line_height: impl Into<text::LineHeight>, @@ -136,9 +136,9 @@ where self } - /// Sets the [`Font`] of the text of the [`Toggler`] + /// Sets the [`Renderer::Font`] of the text of the [`Toggler`] /// - /// [`Font`]: crate::text::Renderer::Font + /// [`Renderer::Font`]: crate::core::text::Renderer pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self { self.font = Some(font.into()); self diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 67216147..674a66d3 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -1,19 +1,17 @@ [package] name = "iced_winit" -version = "0.10.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/iced-rs/iced" -documentation = "https://docs.rs/iced_winit" -keywords = ["gui", "ui", "graphics", "interface", "widgets"] -categories = ["gui"] +description = "A runtime for iced on top of winit" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +categories.workspace = true +keywords.workspace = true [features] default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] -trace = ["tracing", "tracing-core", "tracing-subscriber"] -chrome-trace = ["trace", "tracing-chrome"] debug = ["iced_runtime/debug"] system = ["sysinfo"] application = [] @@ -23,54 +21,23 @@ wayland-dlopen = ["winit/wayland-dlopen"] wayland-csd-adwaita = ["winit/wayland-csd-adwaita"] [dependencies] -window_clipboard = "0.3" -log = "0.4" -thiserror = "1.0" -raw-window-handle = "0.5" - -[dependencies.winit] -version = "0.28" -git = "https://github.com/iced-rs/winit.git" -rev = "c52db2045d0a2f1b8d9923870de1d4ab1994146e" -default-features = false - -[dependencies.iced_runtime] -version = "0.1" -path = "../runtime" - -[dependencies.iced_graphics] -version = "0.9" -path = "../graphics" - -[dependencies.iced_style] -version = "0.9" -path = "../style" - -[dependencies.tracing] -version = "0.1.37" -optional = true -features = ["std"] - -[dependencies.tracing-core] -version = "0.1.30" -optional = true - -[dependencies.tracing-subscriber] -version = "0.3.16" -optional = true -features = ["registry"] - -[dependencies.tracing-chrome] -version = "0.7.0" -optional = true - -[target.'cfg(target_os = "windows")'.dependencies.winapi] -version = "0.3.6" - -[target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] -version = "0.3" -features = ["Document", "Window"] - -[dependencies.sysinfo] -version = "0.28" -optional = true +iced_graphics.workspace = true +iced_runtime.workspace = true +iced_style.workspace = true + +log.workspace = true +raw-window-handle.workspace = true +thiserror.workspace = true +tracing.workspace = true +window_clipboard.workspace = true +winit.workspace = true + +sysinfo.workspace = true +sysinfo.optional = true + +[target.'cfg(target_os = "windows")'.dependencies] +winapi.workspace = true + +[target.'cfg(target_arch = "wasm32")'.dependencies] +web-sys.workspace = true +web-sys.features = ["Document", "Window"] diff --git a/winit/src/application/state.rs b/winit/src/application/state.rs index 967f43f2..e655529a 100644 --- a/winit/src/application/state.rs +++ b/winit/src/application/state.rs @@ -184,9 +184,7 @@ where /// window. /// /// Normally an [`Application`] should be synchronized with its [`State`] - /// and window after calling [`Application::update`]. - /// - /// [`Application::update`]: crate::Program::update + /// and window after calling [`crate::application::update`]. pub fn synchronize(&mut self, application: &A, window: &Window) { // Update window title let new_title = application.title(); diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index b2398e62..3ecd044c 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -521,7 +521,7 @@ pub fn user_attention( } } -/// Converts some [`Icon`] into it's `winit` counterpart. +/// Converts some [`window::Icon`] into it's `winit` counterpart. /// /// Returns `None` if there is an error during the conversion. pub fn icon(icon: window::Icon) -> Option<winit::window::Icon> { diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 1a87ca11..9852a182 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -17,6 +17,7 @@ #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] +#![forbid(rust_2018_idioms)] #![deny( missing_debug_implementations, missing_docs, @@ -26,9 +27,9 @@ clippy::needless_borrow, clippy::new_without_default, clippy::useless_conversion, - unsafe_code + unsafe_code, + rustdoc::broken_intra_doc_links )] -#![forbid(rust_2018_idioms)] #![allow(clippy::inherent_to_string, clippy::type_complexity)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] pub use iced_graphics as graphics; |