From b3afe89be1e0a5fdeffb27c630970a2a912dd5b0 Mon Sep 17 00:00:00 2001 From: David Campbell Date: Sat, 14 Sep 2024 15:13:14 -0400 Subject: [PATCH 01/47] Add rust-version. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 52464e3870..fbf6a01ee7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,6 +119,7 @@ members = [ version = "0.13.0-dev" authors = ["Héctor Ramón Jiménez "] edition = "2021" +rust-version = "1.75.0" license = "MIT" repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" From 850b3d579d4f9a131c90a48f592ebdb88739f7dc Mon Sep 17 00:00:00 2001 From: David Campbell Date: Sat, 14 Sep 2024 15:22:08 -0400 Subject: [PATCH 02/47] Add to workspaces. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index fbf6a01ee7..296fef9830 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ name = "iced" description = "A cross-platform GUI library inspired by Elm" version.workspace = true edition.workspace = true +rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true From f9ee3229c1e641b451f18d6f1b0a75a608a6b023 Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Wed, 18 Sep 2024 01:27:35 -0400 Subject: [PATCH 03/47] Allow specifying a custom executor --- src/application.rs | 18 +++++++++++ src/program.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/application.rs b/src/application.rs index d0f7730447..d175cf8564 100644 --- a/src/application.rs +++ b/src/application.rs @@ -30,6 +30,8 @@ //! ] //! } //! ``` +use iced_futures::Executor; + use crate::program::{self, Program}; use crate::window; use crate::{Element, Font, Result, Settings, Size, Subscription, Task}; @@ -376,6 +378,22 @@ impl Application

{ window: self.window, } } + + /// Sets the executor of the [`Application`]. + pub fn executor( + self, + ) -> Application< + impl Program, + > + where + E: Executor, + { + Application { + raw: program::with_executor::(self.raw), + settings: self.settings, + window: self.window, + } + } } /// The title logic of some [`Application`]. diff --git a/src/program.rs b/src/program.rs index 2b697fbede..68efab882c 100644 --- a/src/program.rs +++ b/src/program.rs @@ -550,6 +550,80 @@ pub fn with_scale_factor( } } +pub fn with_executor( + program: P, +) -> impl Program { + use std::marker::PhantomData; + + struct WithExecutor { + program: P, + executor: PhantomData, + } + + impl Program for WithExecutor + where + E: Executor, + { + type State = P::State; + type Message = P::Message; + type Theme = P::Theme; + type Renderer = P::Renderer; + type Executor = E; + + fn theme( + &self, + state: &Self::State, + window: window::Id, + ) -> Self::Theme { + self.program.theme(state, window) + } + + fn title(&self, state: &Self::State, window: window::Id) -> String { + self.program.title(state, window) + } + + fn update( + &self, + state: &mut Self::State, + message: Self::Message, + ) -> Task { + self.program.update(state, message) + } + + fn view<'a>( + &self, + state: &'a Self::State, + window: window::Id, + ) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> { + self.program.view(state, window) + } + + fn subscription( + &self, + state: &Self::State, + ) -> Subscription { + self.program.subscription(state) + } + + fn style( + &self, + state: &Self::State, + theme: &Self::Theme, + ) -> Appearance { + self.program.style(state, theme) + } + + fn scale_factor(&self, state: &Self::State, window: window::Id) -> f64 { + self.program.scale_factor(state, window) + } + } + + WithExecutor { + program, + executor: PhantomData::, + } +} + /// The renderer of some [`Program`]. pub trait Renderer: text::Renderer + compositor::Default {} From 1448c5bfa5d0977e54670bb8c640ba186bb13167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 20:30:14 +0200 Subject: [PATCH 04/47] Implement some `From` traits for `text_input::Id` --- core/src/window/id.rs | 8 ++++++- examples/multi_window/src/main.rs | 6 ++--- examples/todos/Cargo.toml | 1 - examples/todos/src/main.rs | 7 ++---- widget/src/text_input.rs | 39 +++++++++++++++++++++---------- 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/core/src/window/id.rs b/core/src/window/id.rs index 1a75fa27d1..5d5a817e48 100644 --- a/core/src/window/id.rs +++ b/core/src/window/id.rs @@ -1,5 +1,5 @@ +use std::fmt; use std::hash::Hash; - use std::sync::atomic::{self, AtomicU64}; /// The id of the window. @@ -14,3 +14,9 @@ impl Id { Id(COUNT.fetch_add(1, atomic::Ordering::Relaxed)) } } + +impl fmt::Display for Id { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} diff --git a/examples/multi_window/src/main.rs b/examples/multi_window/src/main.rs index ab09116e04..b43a627a0d 100644 --- a/examples/multi_window/src/main.rs +++ b/examples/multi_window/src/main.rs @@ -25,7 +25,6 @@ struct Window { scale_input: String, current_scale: f64, theme: Theme, - input_id: iced::widget::text_input::Id, } #[derive(Debug, Clone)] @@ -86,7 +85,7 @@ impl Example { } Message::WindowOpened(id) => { let window = Window::new(self.windows.len() + 1); - let focus_input = text_input::focus(window.input_id.clone()); + let focus_input = text_input::focus(format!("input-{id}")); self.windows.insert(id, window); @@ -163,7 +162,6 @@ impl Window { scale_input: "1.0".to_string(), current_scale: 1.0, theme: Theme::ALL[count % Theme::ALL.len()].clone(), - input_id: text_input::Id::unique(), } } @@ -182,7 +180,7 @@ impl Window { text("Window title:"), text_input("Window Title", &self.title) .on_input(move |msg| { Message::TitleChanged(id, msg) }) - .id(self.input_id.clone()) + .id(format!("input-{id}")) ]; let new_window_button = diff --git a/examples/todos/Cargo.toml b/examples/todos/Cargo.toml index 3c62bfbc8f..0d72be8695 100644 --- a/examples/todos/Cargo.toml +++ b/examples/todos/Cargo.toml @@ -9,7 +9,6 @@ publish = false iced.workspace = true iced.features = ["async-std", "debug"] -once_cell.workspace = true serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.0", features = ["v4", "fast-rng", "serde"] } diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs index a5f7b36ad9..25e3ead2a6 100644 --- a/examples/todos/src/main.rs +++ b/examples/todos/src/main.rs @@ -6,12 +6,9 @@ use iced::widget::{ use iced::window; use iced::{Center, Element, Fill, Font, Subscription, Task as Command}; -use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use uuid::Uuid; -static INPUT_ID: Lazy = Lazy::new(text_input::Id::unique); - pub fn main() -> iced::Result { #[cfg(not(target_arch = "wasm32"))] tracing_subscriber::fmt::init(); @@ -85,7 +82,7 @@ impl Todos { _ => {} } - text_input::focus(INPUT_ID.clone()) + text_input::focus("new-task") } Todos::Loaded(state) => { let mut saved = false; @@ -198,7 +195,7 @@ impl Todos { .align_x(Center); let input = text_input("What needs to be done?", input_value) - .id(INPUT_ID.clone()) + .id("new-task") .on_input(Message::InputChanged) .on_submit(Message::CreateTask) .padding(15) diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index d5ede52462..3032dd1353 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -114,8 +114,8 @@ where } /// Sets the [`Id`] of the [`TextInput`]. - pub fn id(mut self, id: Id) -> Self { - self.id = Some(id); + pub fn id(mut self, id: impl Into) -> Self { + self.id = Some(id.into()); self } @@ -1226,38 +1226,53 @@ impl From for widget::Id { } } +impl From<&'static str> for Id { + fn from(id: &'static str) -> Self { + Self::new(id) + } +} + +impl From for Id { + fn from(id: String) -> Self { + Self::new(id) + } +} + /// Produces a [`Task`] that focuses the [`TextInput`] with the given [`Id`]. -pub fn focus(id: Id) -> Task { - task::effect(Action::widget(operation::focusable::focus(id.0))) +pub fn focus(id: impl Into) -> Task { + task::effect(Action::widget(operation::focusable::focus(id.into().0))) } /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the /// end. -pub fn move_cursor_to_end(id: Id) -> Task { +pub fn move_cursor_to_end(id: impl Into) -> Task { task::effect(Action::widget(operation::text_input::move_cursor_to_end( - id.0, + id.into().0, ))) } /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the /// front. -pub fn move_cursor_to_front(id: Id) -> Task { +pub fn move_cursor_to_front(id: impl Into) -> Task { task::effect(Action::widget(operation::text_input::move_cursor_to_front( - id.0, + id.into().0, ))) } /// Produces a [`Task`] that moves the cursor of the [`TextInput`] with the given [`Id`] to the /// provided position. -pub fn move_cursor_to(id: Id, position: usize) -> Task { +pub fn move_cursor_to(id: impl Into, position: usize) -> Task { task::effect(Action::widget(operation::text_input::move_cursor_to( - id.0, position, + id.into().0, + position, ))) } /// Produces a [`Task`] that selects all the content of the [`TextInput`] with the given [`Id`]. -pub fn select_all(id: Id) -> Task { - task::effect(Action::widget(operation::text_input::select_all(id.0))) +pub fn select_all(id: impl Into) -> Task { + task::effect(Action::widget(operation::text_input::select_all( + id.into().0, + ))) } /// The state of a [`TextInput`]. From 45992109ddea00b24484e68ac78ae4b55d2c6c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 20:41:49 +0200 Subject: [PATCH 05/47] Fix scrolling direction with trackpad in `scrollable` --- widget/src/scrollable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index af6a3945fd..a56101661c 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -751,7 +751,7 @@ where // TODO: Configurable speed/friction (?) -movement * 60.0 } - mouse::ScrollDelta::Pixels { x, y } => Vector::new(x, y), + mouse::ScrollDelta::Pixels { x, y } => -Vector::new(x, y), }; state.scroll( From 72e75e04914a7663b74a90ece004f135f5012137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 20:45:56 +0200 Subject: [PATCH 06/47] Remove trailing `0` in `rust-version` --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 296fef9830..82b60faa4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,13 +3,13 @@ name = "iced" description = "A cross-platform GUI library inspired by Elm" version.workspace = true edition.workspace = true -rust-version.workspace = true authors.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true categories.workspace = true keywords.workspace = true +rust-version.workspace = true [lints] workspace = true @@ -120,12 +120,12 @@ members = [ version = "0.13.0-dev" authors = ["Héctor Ramón Jiménez "] edition = "2021" -rust-version = "1.75.0" license = "MIT" repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] +rust-version = "1.75" [workspace.dependencies] iced = { version = "0.13.0-dev", path = "." } From cfe912cbc32772fb9549c1f17fce202f3eb2ad99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:03:37 +0200 Subject: [PATCH 07/47] Add MSRV to test matrix in GitHub CI --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47c61f5e85..d75c59ea91 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - rust: [stable, beta] + rust: [stable, beta, 1.75] steps: - uses: hecrj/setup-rust-action@v2 with: From 14353c285f4e65bd58e7d109a6dc7d598dd9cb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:12:50 +0200 Subject: [PATCH 08/47] Bump MSRV to `1.77` --- .github/workflows/test.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d75c59ea91..225b3d92f2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - rust: [stable, beta, 1.75] + rust: [stable, beta, 1.77] steps: - uses: hecrj/setup-rust-action@v2 with: diff --git a/Cargo.toml b/Cargo.toml index 82b60faa4b..35133f977d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,7 +125,7 @@ repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] -rust-version = "1.75" +rust-version = "1.77" [workspace.dependencies] iced = { version = "0.13.0-dev", path = "." } From d20ce8d82cb4936602c57064a896f7ed686529be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:19:18 +0200 Subject: [PATCH 09/47] Import `Executor` directly from `crate` --- src/application.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/application.rs b/src/application.rs index d175cf8564..2ba764bed6 100644 --- a/src/application.rs +++ b/src/application.rs @@ -30,11 +30,11 @@ //! ] //! } //! ``` -use iced_futures::Executor; - use crate::program::{self, Program}; use crate::window; -use crate::{Element, Font, Result, Settings, Size, Subscription, Task}; +use crate::{ + Element, Executor, Font, Result, Settings, Size, Subscription, Task, +}; use std::borrow::Cow; From 93068836182cb2a6527a267453f280eb5c0d34a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:19:33 +0200 Subject: [PATCH 10/47] Fix order of `Program::theme` implementation --- src/program.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/program.rs b/src/program.rs index 68efab882c..94cb9a7d33 100644 --- a/src/program.rs +++ b/src/program.rs @@ -570,14 +570,6 @@ pub fn with_executor( type Renderer = P::Renderer; type Executor = E; - fn theme( - &self, - state: &Self::State, - window: window::Id, - ) -> Self::Theme { - self.program.theme(state, window) - } - fn title(&self, state: &Self::State, window: window::Id) -> String { self.program.title(state, window) } @@ -605,6 +597,14 @@ pub fn with_executor( self.program.subscription(state) } + fn theme( + &self, + state: &Self::State, + window: window::Id, + ) -> Self::Theme { + self.program.theme(state, window) + } + fn style( &self, state: &Self::State, From 11ac9125491c4d743c393857445b9b67ea5a437a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:45:25 +0200 Subject: [PATCH 11/47] Fix `scrollable` transactions when `on_scroll` is not set --- widget/src/scrollable.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index af6a3945fd..b8de66e32b 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -760,13 +760,17 @@ where content_bounds, ); - if notify_scroll( + let has_scrolled = notify_scroll( state, &self.on_scroll, bounds, content_bounds, shell, - ) { + ); + + let in_transaction = state.last_scrolled.is_some(); + + if has_scrolled || in_transaction { event::Status::Captured } else { event::Status::Ignored @@ -1194,11 +1198,6 @@ fn notify_viewport( return false; } - let Some(on_scroll) = on_scroll else { - state.last_notified = None; - return false; - }; - let viewport = Viewport { offset_x: state.offset_x, offset_y: state.offset_y, @@ -1229,9 +1228,12 @@ fn notify_viewport( } } - shell.publish(on_scroll(viewport)); state.last_notified = Some(viewport); + if let Some(on_scroll) = on_scroll { + shell.publish(on_scroll(viewport)); + } + true } From 7f4a73e1856134821e3e0af11f21469cdc4544a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:21:02 +0200 Subject: [PATCH 12/47] Implement `executor` method for `Daemon` --- src/daemon.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/daemon.rs b/src/daemon.rs index 6a6ad13327..81254bf947 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -2,7 +2,7 @@ use crate::application; use crate::program::{self, Program}; use crate::window; -use crate::{Element, Font, Result, Settings, Subscription, Task}; +use crate::{Element, Executor, Font, Result, Settings, Subscription, Task}; use std::borrow::Cow; @@ -223,6 +223,21 @@ impl Daemon

{ settings: self.settings, } } + + /// Sets the executor of the [`Daemon`]. + pub fn executor( + self, + ) -> Daemon< + impl Program, + > + where + E: Executor, + { + Daemon { + raw: program::with_executor::(self.raw), + settings: self.settings, + } + } } /// The title logic of some [`Daemon`]. From 71af846c6d0feab483a2b4e8bcd49a2ccc31f478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:51:12 +0200 Subject: [PATCH 13/47] Remove redundant import in `markdown` widget --- widget/src/markdown.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/markdown.rs b/widget/src/markdown.rs index fa4ee6bf03..4bcd33530e 100644 --- a/widget/src/markdown.rs +++ b/widget/src/markdown.rs @@ -239,7 +239,7 @@ pub fn parse(markdown: &str) -> impl Iterator + '_ { ) if !metadata && !table => { #[cfg(feature = "highlighter")] { - use iced_highlighter::{self, Highlighter}; + use iced_highlighter::Highlighter; use text::Highlighter as _; highlighter = From 15e6c949d73fa43285ad713c5abe32355823956f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 21:51:19 +0200 Subject: [PATCH 14/47] Bump MSRV to `1.80` --- .github/workflows/test.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 225b3d92f2..ea941509b1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - rust: [stable, beta, 1.77] + rust: [stable, beta, "1.80"] steps: - uses: hecrj/setup-rust-action@v2 with: diff --git a/Cargo.toml b/Cargo.toml index 35133f977d..04ac35ed49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -125,7 +125,7 @@ repository = "https://github.com/iced-rs/iced" homepage = "https://iced.rs" categories = ["gui"] keywords = ["gui", "ui", "graphics", "interface", "widgets"] -rust-version = "1.77" +rust-version = "1.80" [workspace.dependencies] iced = { version = "0.13.0-dev", path = "." } From 9e5afc54cea74c6d06a9d3f1ae0f7372ff1e13cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:00:40 +0200 Subject: [PATCH 15/47] Show `Action` pattern in The Pocket Guide --- src/lib.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 022f8d6e13..0ff9e3aafb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -380,16 +380,18 @@ //! # use iced::{Element, Task}; //! # pub struct Contacts; //! # impl Contacts { -//! # pub fn update(&mut self, message: Message) -> Task { unimplemented!() } +//! # pub fn update(&mut self, message: Message) -> Action { unimplemented!() } //! # pub fn view(&self) -> Element { unimplemented!() } //! # } //! # #[derive(Debug)] //! # pub enum Message {} +//! # pub enum Action { None, Run(Task), Chat(()) } //! # } //! # mod conversation { //! # use iced::{Element, Task}; //! # pub struct Conversation; //! # impl Conversation { +//! # pub fn new(contact: ()) -> (Self, Task) { unimplemented!() } //! # pub fn update(&mut self, message: Message) -> Task { unimplemented!() } //! # pub fn view(&self) -> Element { unimplemented!() } //! # } @@ -419,7 +421,19 @@ //! match message { //! Message::Contacts(message) => { //! if let Screen::Contacts(contacts) = &mut state.screen { -//! contacts.update(message).map(Message::Contacts) +//! let action = contacts.update(message); +//! +//! match action { +//! contacts::Action::None => Task::none(), +//! contacts::Action::Run(task) => task.map(Message::Contacts), +//! contacts::Action::Chat(contact) => { +//! let (conversation, task) = Conversation::new(contact); +//! +//! state.screen = Screen::Conversation(conversation); +//! +//! task.map(Message::Conversation) +//! } +//! } //! } else { //! Task::none() //! } From 1ada297b082ffa79f7e56c14af20b359af745a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:08:43 +0200 Subject: [PATCH 16/47] Explain `Action` pattern a bit in The Pocket Guide --- src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0ff9e3aafb..91d8e53fe0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -456,8 +456,16 @@ //! } //! ``` //! -//! Functor methods like [`Task::map`], [`Element::map`], and [`Subscription::map`] make this -//! approach seamless. +//! The `update` method of a screen can return an `Action` enum that can be leveraged by the parent to +//! execute a task or transition to a completely different screen altogether. The variants of `Action` can +//! have associated data. For instance, in the example above, the `Conversation` screen is created when +//! `Contacts::update` returns an `Action::Chat` with the selected contact. +//! +//! Effectively, this approach lets you "tell a story" to connect different screens together in a type safe +//! way. +//! +//! Furthermore, functor methods like [`Task::map`], [`Element::map`], and [`Subscription::map`] make composition +//! seamless. #![doc( html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/bdf0430880f5c29443f5f0a0ae4895866dfef4c6/docs/logo.svg" )] From ad74e4c69d9c7d65fcb3f081e76e358b60e0e51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:13:09 +0200 Subject: [PATCH 17/47] Improve imports of `Subscription::run` doc example --- futures/src/subscription.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/futures/src/subscription.rs b/futures/src/subscription.rs index 946995d8c2..8067c25906 100644 --- a/futures/src/subscription.rs +++ b/futures/src/subscription.rs @@ -138,11 +138,16 @@ impl Subscription { /// and returning the `Sender` as a `Message` for the `Application`: /// /// ``` - /// use iced_futures::subscription::{self, Subscription}; - /// use iced_futures::stream; - /// use iced_futures::futures::channel::mpsc; - /// use iced_futures::futures::sink::SinkExt; - /// use iced_futures::futures::Stream; + /// # mod iced { + /// # pub use iced_futures::Subscription; + /// # pub use iced_futures::futures; + /// # pub use iced_futures::stream; + /// # } + /// use iced::futures::channel::mpsc; + /// use iced::futures::sink::SinkExt; + /// use iced::futures::Stream; + /// use iced::stream; + /// use iced::Subscription; /// /// pub enum Event { /// Ready(mpsc::Sender), From ab2cedc7d7de6cb4892a73e48b20bb9bab6d661b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:19:29 +0200 Subject: [PATCH 18/47] Remove outdated references in `README` and `ECOSYSTEM` guide --- ECOSYSTEM.md | 91 ---------------------------------------------------- README.md | 23 +++---------- 2 files changed, 5 insertions(+), 109 deletions(-) delete mode 100644 ECOSYSTEM.md diff --git a/ECOSYSTEM.md b/ECOSYSTEM.md deleted file mode 100644 index da3066d8be..0000000000 --- a/ECOSYSTEM.md +++ /dev/null @@ -1,91 +0,0 @@ -# Ecosystem -This document describes the Iced ecosystem and explains how the different crates relate to each other. - -## Overview -Iced is meant to be used by 2 different types of users: - -- __End-users__. They should be able to: - - get started quickly, - - have many widgets available, - - keep things simple, - - and build applications that are __maintainable__ and __performant__. -- __GUI toolkit developers / Ecosystem contributors__. They should be able to: - - build new kinds of widgets, - - implement custom runtimes, - - integrate existing runtimes in their own system (like game engines), - - and create their own custom renderers. - -Iced consists of different crates which offer different layers of abstractions for our users. This modular architecture helps us keep implementation details hidden and decoupled, which should allow us to rewrite or change strategies in the future. - -

- The Iced Ecosystem -

- -## The foundations -There are a bunch of concepts that permeate the whole ecosystem. These concepts are considered __the foundations__, and they are provided by three different crates: - -- [`iced_core`] contains many lightweight, reusable primitives (e.g. `Point`, `Rectangle`, `Color`). -- [`iced_futures`] implements the concurrent concepts of [The Elm Architecture] on top of the [`futures`] ecosystem. -- [`iced_style`] defines the default styling capabilities of built-in widgets. - -

- The foundations -

- -## The native target -The native side of the ecosystem is split into two different groups: __renderers__ and __shells__. - -

- The native target -

- -### Renderers -The widgets of a _graphical_ user interface produce some primitives that eventually need to be drawn on screen. __Renderers__ take care of this task, potentially leveraging GPU acceleration. - -Currently, there are two different official renderers: - -- [`iced_wgpu`] is powered by [`wgpu`] and supports Vulkan, DirectX 12, and Metal. -- [`tiny-skia`] is used as a fallback software renderer when `wgpu` is not supported. - -Additionally, the [`iced_graphics`] subcrate contains a bunch of backend-agnostic types that can be leveraged to build renderers. Both of the renderers rely on the graphical foundations provided by this crate. - -### Shells -The widgets of a graphical user _interface_ are interactive. __Shells__ gather and process user interactions in an event loop. - -Normally, a shell will be responsible of creating a window and managing the lifecycle of a user interface, implementing a runtime of [The Elm Architecture]. - -As of now, there is one official shell: [`iced_winit`] implements a shell runtime on top of [`winit`]. - -## The web target -The Web platform provides all the abstractions necessary to draw widgets and gather users interactions. - -Therefore, unlike the native path, the web side of the ecosystem does not need to split renderers and shells. Instead, [`iced_web`] leverages [`dodrio`] to both render widgets and implement a proper runtime. - -## Iced -Finally, [`iced`] unifies everything into a simple abstraction to create cross-platform applications: - -- On native, it uses __[shells](#shells)__ and __[renderers](#renderers)__. -- On the web, it uses [`iced_web`]. - -

- Iced -

- -[`iced_core`]: core -[`iced_futures`]: futures -[`iced_style`]: style -[`iced_native`]: native -[`iced_web`]: https://github.com/iced-rs/iced_web -[`iced_graphics`]: graphics -[`iced_wgpu`]: wgpu -[`iced_glow`]: glow -[`iced_winit`]: winit -[`iced_glutin`]: glutin -[`iced`]: .. -[`futures`]: https://github.com/rust-lang/futures-rs -[`glow`]: https://github.com/grovesNL/glow -[`wgpu`]: https://github.com/gfx-rs/wgpu -[`winit`]: https://github.com/rust-windowing/winit -[`glutin`]: https://github.com/rust-windowing/glutin -[`dodrio`]: https://github.com/fitzgen/dodrio -[The Elm Architecture]: https://guide.elm-lang.org/architecture/ diff --git a/README.md b/README.md index a9c3797795..41fa220ae3 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,12 @@ Inspired by [Elm]. * Custom widget support (create your own!) * [Debug overlay with performance metrics] * First-class support for async actions (use futures!) -* [Modular ecosystem] split into reusable parts: +* Modular ecosystem split into reusable parts: * A [renderer-agnostic native runtime] enabling integration with existing systems - * Two [built-in renderers] leveraging [`wgpu`] and [`tiny-skia`] + * Two built-in renderers leveraging [`wgpu`] and [`tiny-skia`] * [`iced_wgpu`] supporting Vulkan, Metal and DX12 * [`iced_tiny_skia`] offering a software alternative as a fallback * A [windowing shell] - * A [web runtime] leveraging the DOM __Iced is currently experimental software.__ [Take a look at the roadmap], [check out the issues], and [feel free to contribute!] @@ -49,16 +48,12 @@ __Iced is currently experimental software.__ [Take a look at the roadmap], [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 [`tiny-skia`]: https://github.com/RazrFalcon/tiny-skia [`iced_wgpu`]: wgpu/ [`iced_tiny_skia`]: tiny_skia/ -[built-in renderers]: ECOSYSTEM.md#Renderers [windowing shell]: winit/ -[`dodrio`]: https://github.com/fitzgen/dodrio -[web runtime]: https://github.com/iced-rs/iced_web [Take a look at the roadmap]: ROADMAP.md [check out the issues]: https://github.com/iced-rs/iced/issues [feel free to contribute!]: #contributing--feedback @@ -164,7 +159,7 @@ Read the [book], the [documentation], and the [examples] to learn more! ## Implementation details Iced was originally born as an attempt at bringing the simplicity of [Elm] and -[The Elm Architecture] into [Coffee], a 2D game engine I am working on. +[The Elm Architecture] into [Coffee], a 2D game library I am working on. The core of the library was implemented during May 2019 in [this pull request]. [The first alpha version] was eventually released as @@ -172,25 +167,17 @@ The core of the library was implemented during May 2019 in [this pull request]. implemented the current [tour example] on top of [`ggez`], a game library. Since then, the focus has shifted towards providing a batteries-included, -end-user-oriented GUI library, while keeping [the ecosystem] modular: - -

- - The Iced Ecosystem - -

+end-user-oriented GUI library, while keeping the ecosystem modular. [this pull request]: https://github.com/hecrj/coffee/pull/35 [The first alpha version]: https://github.com/iced-rs/iced/tree/0.1.0-alpha [a renderer-agnostic GUI library]: https://www.reddit.com/r/rust/comments/czzjnv/iced_a_rendereragnostic_gui_library_focused_on/ [tour example]: examples/README.md#tour [`ggez`]: https://github.com/ggez/ggez -[the ecosystem]: ECOSYSTEM.md ## Contributing / Feedback -Contributions are greatly appreciated! If you want to contribute, please -read our [contributing guidelines] for more details. +If you want to contribute, please read our [contributing guidelines] for more details. Feedback is also welcome! You can create a new topic in [our Discourse forum] or come chat to [our Discord server]. From ed4d0781c7172e9ed1f047a37f01a908c7896bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:20:35 +0200 Subject: [PATCH 19/47] Remove "feel free to contribute!" link in `README` --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 41fa220ae3..1780493958 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ Inspired by [Elm]. * [`iced_tiny_skia`] offering a software alternative as a fallback * A [windowing shell] -__Iced is currently experimental software.__ [Take a look at the roadmap], -[check out the issues], and [feel free to contribute!] +__Iced is currently experimental software.__ [Take a look at the roadmap] and +[check out the issues]. [Cross-platform support]: https://raw.githubusercontent.com/iced-rs/iced/master/docs/images/todos_desktop.jpg [text inputs]: https://iced.rs/examples/text_input.mp4 @@ -56,7 +56,6 @@ __Iced is currently experimental software.__ [Take a look at the roadmap], [windowing shell]: winit/ [Take a look at the roadmap]: ROADMAP.md [check out the issues]: https://github.com/iced-rs/iced/issues -[feel free to contribute!]: #contributing--feedback ## Overview From dc2efb3fabc5378671eb91f0983464f372143c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 22:25:59 +0200 Subject: [PATCH 20/47] Showcase `halloy` and `icebreaker` in `README` :tada: --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1780493958..9cfa03de13 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,11 @@ A cross-platform GUI library for Rust focused on simplicity and type-safety. Inspired by [Elm]. - - + + - - + + From 0a95af78f46728b86cb78380791f40f008be99eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 18 Sep 2024 23:05:50 +0200 Subject: [PATCH 21/47] Add quick example to `widget::button` module --- widget/src/button.rs | 46 +++++++++++++++++++++++++++++++------------ widget/src/helpers.rs | 16 ++++++++++++++- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/widget/src/button.rs b/widget/src/button.rs index eafa71b993..a76035f76b 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -1,4 +1,20 @@ -//! Allow your users to perform actions by pressing a button. +//! Buttons allow your users to perform actions by pressing them. +//! +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::button; +//! +//! #[derive(Clone)] +//! enum Message { +//! ButtonPressed, +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! button("Press me!").on_press(Message::ButtonPressed).into() +//! } +//! ``` use crate::core::border::{self, Border}; use crate::core::event::{self, Event}; use crate::core::layout; @@ -17,33 +33,37 @@ use crate::core::{ /// A generic widget that produces a message when pressed. /// /// ```no_run -/// # type Button<'a, Message> = iced_widget::Button<'a, Message>; -/// # +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::button; +/// /// #[derive(Clone)] /// enum Message { /// ButtonPressed, /// } /// -/// let button = Button::new("Press me!").on_press(Message::ButtonPressed); +/// fn view(state: &State) -> Element<'_, Message> { +/// button("Press me!").on_press(Message::ButtonPressed).into() +/// } /// ``` /// /// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will /// be disabled: /// -/// ``` -/// # type Button<'a, Message> = iced_widget::Button<'a, Message>; -/// # +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::button; +/// /// #[derive(Clone)] /// enum Message { /// ButtonPressed, /// } /// -/// fn disabled_button<'a>() -> Button<'a, Message> { -/// Button::new("I'm disabled!") -/// } -/// -/// fn enabled_button<'a>() -> Button<'a, Message> { -/// disabled_button().on_press(Message::ButtonPressed) +/// fn view(state: &State) -> Element<'_, Message> { +/// button("I am disabled!").into() /// } /// ``` #[allow(missing_debug_implementations)] diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 51978823b3..2ad6215670 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -653,7 +653,21 @@ where /// Creates a new [`Button`] with the provided content. /// -/// [`Button`]: crate::Button +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::button; +/// +/// #[derive(Clone)] +/// enum Message { +/// ButtonPressed, +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// button("Press me!").on_press(Message::ButtonPressed).into() +/// } +/// ``` pub fn button<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Button<'a, Message, Theme, Renderer> From 5d25562644907488203604769f338feb2c7df9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 02:47:03 +0200 Subject: [PATCH 22/47] Show `canvas` doc example in multiple places --- widget/src/canvas.rs | 86 +++++++++++++++++++++++++++++++++++++------ widget/src/helpers.rs | 51 +++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 11 deletions(-) diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index 185fa0829d..fb6d55e162 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -1,4 +1,55 @@ //! Draw 2D graphics for your users. +//! +//! ## Drawing a simple circle +//! Here's how we can use a [`Canvas`] to draw a simple circle: +//! +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::mouse; +//! use iced::widget::canvas; +//! use iced::{Color, Rectangle, Renderer, Theme}; +//! +//! // First, we define the data we need for drawing +//! #[derive(Debug)] +//! struct Circle { +//! radius: f32, +//! } +//! +//! // Then, we implement the `Program` trait +//! impl canvas::Program for Circle { +//! // No internal state +//! type State = (); +//! +//! fn draw( +//! &self, +//! _state: &(), +//! renderer: &Renderer, +//! _theme: &Theme, +//! bounds: Rectangle, +//! _cursor: mouse::Cursor +//! ) -> Vec { +//! // We prepare a new `Frame` +//! let mut frame = canvas::Frame::new(renderer, bounds.size()); +//! +//! // We create a `Path` representing a simple circle +//! let circle = canvas::Path::circle(frame.center(), self.radius); +//! +//! // And fill it with some color +//! frame.fill(&circle, Color::BLACK); +//! +//! // Then, we produce the geometry +//! vec![frame.into_geometry()] +//! } +//! } +//! +//! // Finally, we simply use our `Circle` to create the `Canvas`! +//! fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> { +//! canvas(Circle { radius: 50.0 }).into() +//! } +//! ``` pub mod event; mod program; @@ -40,14 +91,17 @@ pub type Frame = geometry::Frame; /// A widget capable of drawing 2D graphics. /// /// ## Drawing a simple circle -/// If you want to get a quick overview, here's how we can draw a simple circle: +/// Here's how we can use a [`Canvas`] to draw a simple circle: /// /// ```no_run -/// # use iced_widget::canvas::{self, Canvas, Fill, Frame, Geometry, Path, Program}; -/// # use iced_widget::core::{Color, Rectangle}; -/// # use iced_widget::core::mouse; -/// # use iced_widget::{Renderer, Theme}; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # +/// use iced::mouse; +/// use iced::widget::canvas; +/// use iced::{Color, Rectangle, Renderer, Theme}; +/// /// // First, we define the data we need for drawing /// #[derive(Debug)] /// struct Circle { @@ -55,26 +109,36 @@ pub type Frame = geometry::Frame; /// } /// /// // Then, we implement the `Program` trait -/// impl Program<()> for Circle { +/// impl canvas::Program for Circle { +/// // No internal state /// type State = (); /// -/// fn draw(&self, _state: &(), renderer: &Renderer, _theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor) -> Vec { +/// fn draw( +/// &self, +/// _state: &(), +/// renderer: &Renderer, +/// _theme: &Theme, +/// bounds: Rectangle, +/// _cursor: mouse::Cursor +/// ) -> Vec { /// // We prepare a new `Frame` -/// let mut frame = Frame::new(renderer, bounds.size()); +/// let mut frame = canvas::Frame::new(renderer, bounds.size()); /// /// // We create a `Path` representing a simple circle -/// let circle = Path::circle(frame.center(), self.radius); +/// let circle = canvas::Path::circle(frame.center(), self.radius); /// /// // And fill it with some color /// frame.fill(&circle, Color::BLACK); /// -/// // Finally, we produce the geometry +/// // Then, we produce the geometry /// vec![frame.into_geometry()] /// } /// } /// /// // Finally, we simply use our `Circle` to create the `Canvas`! -/// let canvas = Canvas::new(Circle { radius: 50.0 }); +/// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> { +/// canvas(Circle { radius: 50.0 }).into() +/// } /// ``` #[derive(Debug)] pub struct Canvas diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 2ad6215670..30d40edca0 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1000,6 +1000,57 @@ where /// Creates a new [`Canvas`]. /// /// [`Canvas`]: crate::Canvas +/// +/// ## Drawing a simple circle +/// Here's how we can use a [`Canvas`] to draw a simple circle: +/// +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::mouse; +/// use iced::widget::canvas; +/// use iced::{Color, Rectangle, Renderer, Theme}; +/// +/// // First, we define the data we need for drawing +/// #[derive(Debug)] +/// struct Circle { +/// radius: f32, +/// } +/// +/// // Then, we implement the `Program` trait +/// impl canvas::Program for Circle { +/// // No internal state +/// type State = (); +/// +/// fn draw( +/// &self, +/// _state: &(), +/// renderer: &Renderer, +/// _theme: &Theme, +/// bounds: Rectangle, +/// _cursor: mouse::Cursor +/// ) -> Vec { +/// // We prepare a new `Frame` +/// let mut frame = canvas::Frame::new(renderer, bounds.size()); +/// +/// // We create a `Path` representing a simple circle +/// let circle = canvas::Path::circle(frame.center(), self.radius); +/// +/// // And fill it with some color +/// frame.fill(&circle, Color::BLACK); +/// +/// // Then, we produce the geometry +/// vec![frame.into_geometry()] +/// } +/// } +/// +/// // Finally, we simply use our `Circle` to create the `Canvas`! +/// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> { +/// canvas(Circle { radius: 50.0 }).into() +/// } +/// ``` #[cfg(feature = "canvas")] pub fn canvas( program: P, From 51f7ce73248bea2bb7cc2b662433e46fa0c44dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 03:03:11 +0200 Subject: [PATCH 23/47] Show `checkbox` doc example in multiple places --- widget/src/button.rs | 2 ++ widget/src/canvas.rs | 4 +-- widget/src/checkbox.rs | 60 +++++++++++++++++++++++++++++++++++++----- widget/src/helpers.rs | 34 ++++++++++++++++++++++-- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/widget/src/button.rs b/widget/src/button.rs index a76035f76b..3323c0d326 100644 --- a/widget/src/button.rs +++ b/widget/src/button.rs @@ -1,5 +1,6 @@ //! Buttons allow your users to perform actions by pressing them. //! +//! # Example //! ```no_run //! # mod iced { pub mod widget { pub use iced_widget::*; } } //! # pub type State = (); @@ -32,6 +33,7 @@ use crate::core::{ /// A generic widget that produces a message when pressed. /// +/// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index fb6d55e162..bb6b03536b 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -1,6 +1,6 @@ //! Draw 2D graphics for your users. //! -//! ## Drawing a simple circle +//! # Example: Drawing a Simple Circle //! Here's how we can use a [`Canvas`] to draw a simple circle: //! //! ```no_run @@ -90,7 +90,7 @@ pub type Frame = geometry::Frame; /// A widget capable of drawing 2D graphics. /// -/// ## Drawing a simple circle +/// # Example: Drawing a Simple Circle /// Here's how we can use a [`Canvas`] to draw a simple circle: /// /// ```no_run diff --git a/widget/src/checkbox.rs b/widget/src/checkbox.rs index 32db509085..4a3f35ed21 100644 --- a/widget/src/checkbox.rs +++ b/widget/src/checkbox.rs @@ -1,4 +1,35 @@ -//! Show toggle controls using checkboxes. +//! Checkboxes can be used to let users make binary choices. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::checkbox; +//! +//! struct State { +//! is_checked: bool, +//! } +//! +//! enum Message { +//! CheckboxToggled(bool), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! checkbox("Toggle me!", state.is_checked) +//! .on_toggle(Message::CheckboxToggled) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::CheckboxToggled(is_checked) => { +//! state.is_checked = is_checked; +//! } +//! } +//! } +//! ``` +//! ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) use crate::core::alignment; use crate::core::event::{self, Event}; use crate::core::layout; @@ -17,19 +48,34 @@ use crate::core::{ /// A box that can be checked. /// /// # Example -/// /// ```no_run -/// # type Checkbox<'a, Message> = iced_widget::Checkbox<'a, Message>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// pub enum Message { +/// use iced::widget::checkbox; +/// +/// struct State { +/// is_checked: bool, +/// } +/// +/// enum Message { /// CheckboxToggled(bool), /// } /// -/// let is_checked = true; +/// fn view(state: &State) -> Element<'_, Message> { +/// checkbox("Toggle me!", state.is_checked) +/// .on_toggle(Message::CheckboxToggled) +/// .into() +/// } /// -/// Checkbox::new("Toggle me!", is_checked).on_toggle(Message::CheckboxToggled); +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::CheckboxToggled(is_checked) => { +/// state.is_checked = is_checked; +/// } +/// } +/// } /// ``` -/// /// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) #[allow(missing_debug_implementations)] pub struct Checkbox< diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 30d40edca0..1ed0bde261 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -653,6 +653,7 @@ where /// Creates a new [`Button`] with the provided content. /// +/// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); @@ -747,7 +748,36 @@ pub use crate::markdown::view as markdown; /// Creates a new [`Checkbox`]. /// -/// [`Checkbox`]: crate::Checkbox +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::checkbox; +/// +/// struct State { +/// is_checked: bool, +/// } +/// +/// enum Message { +/// CheckboxToggled(bool), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// checkbox("Toggle me!", state.is_checked) +/// .on_toggle(Message::CheckboxToggled) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::CheckboxToggled(is_checked) => { +/// state.is_checked = is_checked; +/// } +/// } +/// } +/// ``` +/// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) pub fn checkbox<'a, Message, Theme, Renderer>( label: impl Into, is_checked: bool, @@ -1001,7 +1031,7 @@ where /// /// [`Canvas`]: crate::Canvas /// -/// ## Drawing a simple circle +/// # Example: Drawing a Simple Circle /// Here's how we can use a [`Canvas`] to draw a simple circle: /// /// ```no_run From 3e6e669c4c111b2ac65c7aff1d03c1a1f5ba645f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 03:18:08 +0200 Subject: [PATCH 24/47] Show `combo_box` doc example in multiple places --- widget/src/combo_box.rs | 114 ++++++++++++++++++++++++++++++++++++++-- widget/src/helpers.rs | 57 +++++++++++++++++++- 2 files changed, 166 insertions(+), 5 deletions(-) diff --git a/widget/src/combo_box.rs b/widget/src/combo_box.rs index a51701ca61..fb661ad5cb 100644 --- a/widget/src/combo_box.rs +++ b/widget/src/combo_box.rs @@ -1,4 +1,59 @@ -//! Display a dropdown list of searchable and selectable options. +//! Combo boxes display a dropdown list of searchable and selectable options. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::combo_box; +//! +//! struct State { +//! fruits: combo_box::State, +//! favorite: Option, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Fruit { +//! Apple, +//! Orange, +//! Strawberry, +//! Tomato, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! FruitSelected(Fruit), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! combo_box( +//! &state.fruits, +//! "Select your favorite fruit...", +//! state.favorite.as_ref(), +//! Message::FruitSelected +//! ) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::FruitSelected(fruit) => { +//! state.favorite = Some(fruit); +//! } +//! } +//! } +//! +//! impl std::fmt::Display for Fruit { +//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +//! f.write_str(match self { +//! Self::Apple => "Apple", +//! Self::Orange => "Orange", +//! Self::Strawberry => "Strawberry", +//! Self::Tomato => "Tomato", +//! }) +//! } +//! } +//! ``` use crate::core::event::{self, Event}; use crate::core::keyboard; use crate::core::keyboard::key; @@ -21,9 +76,60 @@ use std::fmt::Display; /// A widget for searching and selecting a single value from a list of options. /// -/// 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. +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::combo_box; +/// +/// struct State { +/// fruits: combo_box::State, +/// favorite: Option, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Fruit { +/// Apple, +/// Orange, +/// Strawberry, +/// Tomato, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// FruitSelected(Fruit), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// combo_box( +/// &state.fruits, +/// "Select your favorite fruit...", +/// state.favorite.as_ref(), +/// Message::FruitSelected +/// ) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::FruitSelected(fruit) => { +/// state.favorite = Some(fruit); +/// } +/// } +/// } +/// +/// impl std::fmt::Display for Fruit { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// f.write_str(match self { +/// Self::Apple => "Apple", +/// Self::Orange => "Orange", +/// Self::Strawberry => "Strawberry", +/// Self::Tomato => "Tomato", +/// }) +/// } +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct ComboBox< 'a, diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 1ed0bde261..d839bc3a1b 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -902,7 +902,62 @@ where /// Creates a new [`ComboBox`]. /// -/// [`ComboBox`]: crate::ComboBox +/// Combo boxes display a dropdown list of searchable and selectable options. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::combo_box; +/// +/// struct State { +/// fruits: combo_box::State, +/// favorite: Option, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Fruit { +/// Apple, +/// Orange, +/// Strawberry, +/// Tomato, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// FruitSelected(Fruit), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// combo_box( +/// &state.fruits, +/// "Select your favorite fruit...", +/// state.favorite.as_ref(), +/// Message::FruitSelected +/// ) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::FruitSelected(fruit) => { +/// state.favorite = Some(fruit); +/// } +/// } +/// } +/// +/// impl std::fmt::Display for Fruit { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// f.write_str(match self { +/// Self::Apple => "Apple", +/// Self::Orange => "Orange", +/// Self::Strawberry => "Strawberry", +/// Self::Tomato => "Tomato", +/// }) +/// } +/// } +/// ``` pub fn combo_box<'a, T, Message, Theme, Renderer>( state: &'a combo_box::State, placeholder: &str, From 96615d5537d04f0b8d3938f417e08bbc3c34e1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 03:33:09 +0200 Subject: [PATCH 25/47] Show `container` doc example in multiple places --- widget/src/canvas.rs | 6 +----- widget/src/container.rs | 44 ++++++++++++++++++++++++++++++++++++++--- widget/src/helpers.rs | 26 +++++++++++++++++++++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/widget/src/canvas.rs b/widget/src/canvas.rs index bb6b03536b..9fbccf824e 100644 --- a/widget/src/canvas.rs +++ b/widget/src/canvas.rs @@ -1,8 +1,6 @@ -//! Draw 2D graphics for your users. +//! Canvases can be leveraged to draw interactive 2D graphics. //! //! # Example: Drawing a Simple Circle -//! Here's how we can use a [`Canvas`] to draw a simple circle: -//! //! ```no_run //! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } //! # pub type State = (); @@ -91,8 +89,6 @@ pub type Frame = geometry::Frame; /// A widget capable of drawing 2D graphics. /// /// # Example: Drawing a Simple Circle -/// Here's how we can use a [`Canvas`] to draw a simple circle: -/// /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type State = (); diff --git a/widget/src/container.rs b/widget/src/container.rs index 3b794099fd..b256540c1c 100644 --- a/widget/src/container.rs +++ b/widget/src/container.rs @@ -1,4 +1,24 @@ -//! Decorate content and apply alignment. +//! Containers let you align a widget inside their boundaries. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::container; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! container("This text is centered inside a rounded box!") +//! .padding(10) +//! .center(800) +//! .style(container::rounded_box) +//! .into() +//! } +//! ``` use crate::core::alignment::{self, Alignment}; use crate::core::border::{self, Border}; use crate::core::event::{self, Event}; @@ -16,9 +36,27 @@ use crate::core::{ }; use crate::runtime::task::{self, Task}; -/// An element decorating some content. +/// A widget that aligns its contents inside of its boundaries. /// -/// It is normally used for alignment purposes. +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::container; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// container("This text is centered inside a rounded box!") +/// .padding(10) +/// .center(800) +/// .style(container::rounded_box) +/// .into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Container< 'a, diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index d839bc3a1b..0699446dcd 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -128,7 +128,27 @@ macro_rules! rich_text { /// Creates a new [`Container`] with the provided content. /// -/// [`Container`]: crate::Container +/// Containers let you align a widget inside their boundaries. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::container; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// container("This text is centered inside a rounded box!") +/// .padding(10) +/// .center(800) +/// .style(container::rounded_box) +/// .into() +/// } +/// ``` pub fn container<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> @@ -1084,11 +1104,11 @@ where /// Creates a new [`Canvas`]. /// +/// Canvases can be leveraged to draw interactive 2D graphics. +/// /// [`Canvas`]: crate::Canvas /// /// # Example: Drawing a Simple Circle -/// Here's how we can use a [`Canvas`] to draw a simple circle: -/// /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type State = (); From e98a441b0fa0c1e2ddffe615a48f3fe23a4fedad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 03:40:38 +0200 Subject: [PATCH 26/47] Show `image` doc example in multiple places --- widget/src/helpers.rs | 19 +++++++++++++++++++ widget/src/image.rs | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 0699446dcd..bae2e10e39 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1047,7 +1047,26 @@ where /// Creates a new [`Image`]. /// +/// Images display raster graphics in different formats (PNG, JPG, etc.). +/// /// [`Image`]: crate::Image +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::image; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// image("ferris.png").into() +/// } +/// ``` +/// #[cfg(feature = "image")] pub fn image(handle: impl Into) -> crate::Image { crate::Image::new(handle.into()) diff --git a/widget/src/image.rs b/widget/src/image.rs index e04f2d6f0f..c8f2a620f6 100644 --- a/widget/src/image.rs +++ b/widget/src/image.rs @@ -1,4 +1,21 @@ -//! Display images in your user interface. +//! Images display raster graphics in different formats (PNG, JPG, etc.). +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::image; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! image("ferris.png").into() +//! } +//! ``` +//! pub mod viewer; pub use viewer::Viewer; @@ -22,16 +39,23 @@ pub fn viewer(handle: Handle) -> Viewer { /// A frame that displays an image while keeping aspect ratio. /// /// # Example -/// /// ```no_run -/// # use iced_widget::image::{self, Image}; -/// # -/// let image = Image::::new("resources/ferris.png"); -/// ``` +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::image; /// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// image("ferris.png").into() +/// } +/// ``` /// #[derive(Debug)] -pub struct Image { +pub struct Image { handle: Handle, width: Length, height: Length, From 70dd0501af2084f410b4511d6ddc63296b643f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 03:54:29 +0200 Subject: [PATCH 27/47] Show `keyed_column` doc example in multiple places --- widget/src/helpers.rs | 22 +++++++++++++++++++++- widget/src/keyed.rs | 32 +++++++++++++++++++++++++++----- widget/src/keyed/column.rs | 22 ++++++++++++++++++++-- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index bae2e10e39..11eed6baa1 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -191,7 +191,27 @@ where Column::with_children(children) } -/// Creates a new [`keyed::Column`] with the given children. +/// Creates a new [`keyed::Column`] from an iterator of elements. +/// +/// Keyed columns distribute content vertically while keeping continuity. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{keyed_column, text}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// keyed_column((0..=100).map(|i| { +/// (i, text!("Item {i}").into()) +/// })).into() +/// } +/// ``` pub fn keyed_column<'a, Key, Message, Theme, Renderer>( children: impl IntoIterator)>, ) -> keyed::Column<'a, Key, Message, Theme, Renderer> diff --git a/widget/src/keyed.rs b/widget/src/keyed.rs index ad531e6642..923cb118ed 100644 --- a/widget/src/keyed.rs +++ b/widget/src/keyed.rs @@ -1,4 +1,4 @@ -//! Use widgets that can provide hints to ensure continuity. +//! Keyed widgets can provide hints to ensure continuity. //! //! # What is continuity? //! Continuity is the feeling of persistence of state. @@ -41,13 +41,35 @@ pub mod column; pub use column::Column; -/// Creates a [`Column`] with the given children. +/// Creates a keyed [`Column`] with the given children. +/// +/// Keyed columns distribute content vertically while keeping continuity. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::keyed_column; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// keyed_column![ +/// (0, "Item 0"), +/// (1, "Item 1"), +/// (2, "Item 2"), +/// ].into() +/// } +/// ``` #[macro_export] macro_rules! keyed_column { () => ( - $crate::Column::new() + $crate::keyed::Column::new() ); - ($($x:expr),+ $(,)?) => ( - $crate::keyed::Column::with_children(vec![$($crate::core::Element::from($x)),+]) + ($(($key:expr, $x:expr)),+ $(,)?) => ( + $crate::keyed::Column::with_children(vec![$(($key, $crate::core::Element::from($x))),+]) ); } diff --git a/widget/src/keyed/column.rs b/widget/src/keyed/column.rs index 2c56c6051e..5852ede19d 100644 --- a/widget/src/keyed/column.rs +++ b/widget/src/keyed/column.rs @@ -1,4 +1,4 @@ -//! Distribute content vertically. +//! Keyed columns distribute content vertically while keeping continuity. use crate::core::event::{self, Event}; use crate::core::layout; use crate::core::mouse; @@ -11,7 +11,25 @@ use crate::core::{ Shell, Size, Vector, Widget, }; -/// A container that distributes its contents vertically. +/// A container that distributes its contents vertically while keeping continuity. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{keyed_column, text}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// keyed_column((0..=100).map(|i| { +/// (i, text!("Item {i}").into()) +/// })).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Column< 'a, From a2c16aa68e46ca3ff4e022aa05f70ef0efc1df7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 04:05:46 +0200 Subject: [PATCH 28/47] Show `markdown` doc example in multiple places --- widget/src/markdown.rs | 131 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/widget/src/markdown.rs b/widget/src/markdown.rs index fa4ee6bf03..6e5929984d 100644 --- a/widget/src/markdown.rs +++ b/widget/src/markdown.rs @@ -1,9 +1,52 @@ -//! Parse and display Markdown. +//! Markdown widgets can parse and display Markdown. //! //! You can enable the `highlighter` feature for syntax highligting //! in code blocks. //! //! Only the variants of [`Item`] are currently supported. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::markdown; +//! use iced::Theme; +//! +//! struct State { +//! markdown: Vec, +//! } +//! +//! enum Message { +//! LinkClicked(markdown::Url), +//! } +//! +//! impl State { +//! pub fn new() -> Self { +//! Self { +//! markdown: markdown::parse("This is some **Markdown**!").collect(), +//! } +//! } +//! +//! fn view(&self) -> Element<'_, Message> { +//! markdown::view( +//! &self.markdown, +//! markdown::Settings::default(), +//! markdown::Style::from_palette(Theme::TokyoNightStorm.palette()), +//! ) +//! .map(Message::LinkClicked) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::LinkClicked(url) => { +//! println!("The following url was clicked: {url}"); +//! } +//! } +//! } +//! } +//! ``` use crate::core::border; use crate::core::font::{self, Font}; use crate::core::padding; @@ -145,6 +188,49 @@ impl Span { } /// Parse the given Markdown content. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::markdown; +/// use iced::Theme; +/// +/// struct State { +/// markdown: Vec, +/// } +/// +/// enum Message { +/// LinkClicked(markdown::Url), +/// } +/// +/// impl State { +/// pub fn new() -> Self { +/// Self { +/// markdown: markdown::parse("This is some **Markdown**!").collect(), +/// } +/// } +/// +/// fn view(&self) -> Element<'_, Message> { +/// markdown::view( +/// &self.markdown, +/// markdown::Settings::default(), +/// markdown::Style::from_palette(Theme::TokyoNightStorm.palette()), +/// ) +/// .map(Message::LinkClicked) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::LinkClicked(url) => { +/// println!("The following url was clicked: {url}"); +/// } +/// } +/// } +/// } +/// ``` pub fn parse(markdown: &str) -> impl Iterator + '_ { struct List { start: Option, @@ -484,6 +570,49 @@ impl Style { /// Display a bunch of Markdown items. /// /// You can obtain the items with [`parse`]. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::markdown; +/// use iced::Theme; +/// +/// struct State { +/// markdown: Vec, +/// } +/// +/// enum Message { +/// LinkClicked(markdown::Url), +/// } +/// +/// impl State { +/// pub fn new() -> Self { +/// Self { +/// markdown: markdown::parse("This is some **Markdown**!").collect(), +/// } +/// } +/// +/// fn view(&self) -> Element<'_, Message> { +/// markdown::view( +/// &self.markdown, +/// markdown::Settings::default(), +/// markdown::Style::from_palette(Theme::TokyoNightStorm.palette()), +/// ) +/// .map(Message::LinkClicked) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::LinkClicked(url) => { +/// println!("The following url was clicked: {url}"); +/// } +/// } +/// } +/// } +/// ``` pub fn view<'a, Theme, Renderer>( items: impl IntoIterator, settings: Settings, From 8c6caefd9f88ae87d619b3b6f778bc91e06bad8e Mon Sep 17 00:00:00 2001 From: lufte Date: Wed, 18 Sep 2024 23:32:50 -0300 Subject: [PATCH 29/47] Set the text color determined by the style function Fixes: https://github.com/iced-rs/iced/issues/2557 --- widget/src/text_editor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 1df97962a2..c8e7fa9ad6 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -742,7 +742,7 @@ where tree: &widget::Tree, renderer: &mut Renderer, theme: &Theme, - defaults: &renderer::Style, + _defaults: &renderer::Style, layout: Layout<'_>, cursor: mouse::Cursor, _viewport: &Rectangle, @@ -811,7 +811,7 @@ where renderer.fill_editor( &internal.editor, text_bounds.position(), - defaults.text_color, + style.value, text_bounds, ); } From b78243d86f4e35aac7b2e126877909411404e97a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 04:35:39 +0200 Subject: [PATCH 30/47] Show `pane_grid` doc example in multiple places --- widget/src/helpers.rs | 53 ++++++++++++++++++++++++++++ widget/src/pane_grid.rs | 78 +++++++++++++++++++++++++++++++++-------- 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 11eed6baa1..ea632eccf6 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -9,6 +9,7 @@ use crate::core::window; use crate::core::{Element, Length, Pixels, Widget}; use crate::keyed; use crate::overlay; +use crate::pane_grid::{self, PaneGrid}; use crate::pick_list::{self, PickList}; use crate::progress_bar::{self, ProgressBar}; use crate::radio::{self, Radio}; @@ -1269,3 +1270,55 @@ where { Themer::new(move |_| new_theme.clone(), content) } + +/// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function. +/// +/// Pane grids let your users split regions of your application and organize layout dynamically. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::{pane_grid, text}; +/// +/// struct State { +/// panes: pane_grid::State, +/// } +/// +/// enum Pane { +/// SomePane, +/// AnotherKindOfPane, +/// } +/// +/// enum Message { +/// PaneDragged(pane_grid::DragEvent), +/// PaneResized(pane_grid::ResizeEvent), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// pane_grid(&state.panes, |pane, state, is_maximized| { +/// pane_grid::Content::new(match state { +/// Pane::SomePane => text("This is some pane"), +/// Pane::AnotherKindOfPane => text("This is another kind of pane"), +/// }) +/// }) +/// .on_drag(Message::PaneDragged) +/// .on_resize(10, Message::PaneResized) +/// .into() +/// } +/// ``` +pub fn pane_grid<'a, T, Message, Theme, Renderer>( + state: &'a pane_grid::State, + view: impl Fn( + pane_grid::Pane, + &'a T, + bool, + ) -> pane_grid::Content<'a, Message, Theme, Renderer>, +) -> PaneGrid<'a, Message, Theme, Renderer> +where + Theme: pane_grid::Catalog, + Renderer: core::Renderer, +{ + PaneGrid::new(state, view) +} diff --git a/widget/src/pane_grid.rs b/widget/src/pane_grid.rs index 4473119d41..9d4dda25f8 100644 --- a/widget/src/pane_grid.rs +++ b/widget/src/pane_grid.rs @@ -1,8 +1,54 @@ -//! Let your users split regions of your application and organize layout dynamically. +//! Pane grids let your users split regions of your application and organize layout dynamically. //! //! ![Pane grid - Iced](https://iced.rs/examples/pane_grid.gif) //! +//! This distribution of space is common in tiling window managers (like +//! [`awesome`](https://awesomewm.org/), [`i3`](https://i3wm.org/), or even +//! [`tmux`](https://github.com/tmux/tmux)). +//! +//! A [`PaneGrid`] supports: +//! +//! * Vertical and horizontal splits +//! * Tracking of the last active pane +//! * Mouse-based resizing +//! * Drag and drop to reorganize panes +//! * Hotkey support +//! * Configurable modifier keys +//! * [`State`] API to perform actions programmatically (`split`, `swap`, `resize`, etc.) +//! //! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::{pane_grid, text}; +//! +//! struct State { +//! panes: pane_grid::State, +//! } +//! +//! enum Pane { +//! SomePane, +//! AnotherKindOfPane, +//! } +//! +//! enum Message { +//! PaneDragged(pane_grid::DragEvent), +//! PaneResized(pane_grid::ResizeEvent), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! pane_grid(&state.panes, |pane, state, is_maximized| { +//! pane_grid::Content::new(match state { +//! Pane::SomePane => text("This is some pane"), +//! Pane::AnotherKindOfPane => text("This is another kind of pane"), +//! }) +//! }) +//! .on_drag(Message::PaneDragged) +//! .on_resize(10, Message::PaneResized) +//! .into() +//! } +//! ``` //! The [`pane_grid` example] showcases how to use a [`PaneGrid`] with resizing, //! drag and drop, and hotkey support. //! @@ -68,14 +114,18 @@ const THICKNESS_RATIO: f32 = 25.0; /// * Configurable modifier keys /// * [`State`] API to perform actions programmatically (`split`, `swap`, `resize`, etc.) /// -/// ## Example -/// +/// # Example /// ```no_run -/// # use iced_widget::{pane_grid, text}; -/// # -/// # type PaneGrid<'a, Message> = iced_widget::PaneGrid<'a, Message>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// enum PaneState { +/// use iced::widget::{pane_grid, text}; +/// +/// struct State { +/// panes: pane_grid::State, +/// } +/// +/// enum Pane { /// SomePane, /// AnotherKindOfPane, /// } @@ -85,17 +135,17 @@ const THICKNESS_RATIO: f32 = 25.0; /// PaneResized(pane_grid::ResizeEvent), /// } /// -/// let (mut state, _) = pane_grid::State::new(PaneState::SomePane); -/// -/// let pane_grid = -/// PaneGrid::new(&state, |pane, state, is_maximized| { +/// fn view(state: &State) -> Element<'_, Message> { +/// pane_grid(&state.panes, |pane, state, is_maximized| { /// pane_grid::Content::new(match state { -/// PaneState::SomePane => text("This is some pane"), -/// PaneState::AnotherKindOfPane => text("This is another kind of pane"), +/// Pane::SomePane => text("This is some pane"), +/// Pane::AnotherKindOfPane => text("This is another kind of pane"), /// }) /// }) /// .on_drag(Message::PaneDragged) -/// .on_resize(10, Message::PaneResized); +/// .on_resize(10, Message::PaneResized) +/// .into() +/// } /// ``` #[allow(missing_debug_implementations)] pub struct PaneGrid< From 7b22b7e87699e22f3e16869093e8a01a91d2e93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 04:45:15 +0200 Subject: [PATCH 31/47] Show `pick_list` doc example in multiple places --- widget/src/helpers.rs | 63 +++++++++++++++++++- widget/src/pick_list.rs | 124 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index ea632eccf6..72d5d7fe91 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -924,7 +924,68 @@ where /// Creates a new [`PickList`]. /// -/// [`PickList`]: crate::PickList +/// Pick lists display a dropdown list of selectable options. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::pick_list; +/// +/// struct State { +/// favorite: Option, +/// } +/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// enum Fruit { +/// Apple, +/// Orange, +/// Strawberry, +/// Tomato, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// FruitSelected(Fruit), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// let fruits = [ +/// Fruit::Apple, +/// Fruit::Orange, +/// Fruit::Strawberry, +/// Fruit::Tomato, +/// ]; +/// +/// pick_list( +/// fruits, +/// state.favorite, +/// Message::FruitSelected, +/// ) +/// .placeholder("Select your favorite fruit...") +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::FruitSelected(fruit) => { +/// state.favorite = Some(fruit); +/// } +/// } +/// } +/// +/// impl std::fmt::Display for Fruit { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// f.write_str(match self { +/// Self::Apple => "Apple", +/// Self::Orange => "Orange", +/// Self::Strawberry => "Strawberry", +/// Self::Tomato => "Tomato", +/// }) +/// } +/// } +/// ``` pub fn pick_list<'a, T, L, V, Message, Theme, Renderer>( options: L, selected: Option, diff --git a/widget/src/pick_list.rs b/widget/src/pick_list.rs index 1fc9951e34..ff54fe8a69 100644 --- a/widget/src/pick_list.rs +++ b/widget/src/pick_list.rs @@ -1,4 +1,65 @@ -//! Display a dropdown list of selectable values. +//! Pick lists display a dropdown list of selectable options. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::pick_list; +//! +//! struct State { +//! favorite: Option, +//! } +//! +//! #[derive(Debug, Clone, Copy, PartialEq, Eq)] +//! enum Fruit { +//! Apple, +//! Orange, +//! Strawberry, +//! Tomato, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! FruitSelected(Fruit), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! let fruits = [ +//! Fruit::Apple, +//! Fruit::Orange, +//! Fruit::Strawberry, +//! Fruit::Tomato, +//! ]; +//! +//! pick_list( +//! fruits, +//! state.favorite, +//! Message::FruitSelected, +//! ) +//! .placeholder("Select your favorite fruit...") +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::FruitSelected(fruit) => { +//! state.favorite = Some(fruit); +//! } +//! } +//! } +//! +//! impl std::fmt::Display for Fruit { +//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +//! f.write_str(match self { +//! Self::Apple => "Apple", +//! Self::Orange => "Orange", +//! Self::Strawberry => "Strawberry", +//! Self::Tomato => "Tomato", +//! }) +//! } +//! } +//! ``` use crate::core::alignment; use crate::core::event::{self, Event}; use crate::core::keyboard; @@ -20,6 +81,67 @@ use std::borrow::Borrow; use std::f32; /// A widget for selecting a single value from a list of options. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::pick_list; +/// +/// struct State { +/// favorite: Option, +/// } +/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// enum Fruit { +/// Apple, +/// Orange, +/// Strawberry, +/// Tomato, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// FruitSelected(Fruit), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// let fruits = [ +/// Fruit::Apple, +/// Fruit::Orange, +/// Fruit::Strawberry, +/// Fruit::Tomato, +/// ]; +/// +/// pick_list( +/// fruits, +/// state.favorite, +/// Message::FruitSelected, +/// ) +/// .placeholder("Select your favorite fruit...") +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::FruitSelected(fruit) => { +/// state.favorite = Some(fruit); +/// } +/// } +/// } +/// +/// impl std::fmt::Display for Fruit { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// f.write_str(match self { +/// Self::Apple => "Apple", +/// Self::Orange => "Orange", +/// Self::Strawberry => "Strawberry", +/// Self::Tomato => "Tomato", +/// }) +/// } +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct PickList< 'a, From c646ff5f1feb1112f9e34d75e40246e4fc1c74e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 04:57:32 +0200 Subject: [PATCH 32/47] Show `progress_bar` doc example in multiple places --- widget/src/helpers.rs | 22 +++++++++++++++++++- widget/src/progress_bar.rs | 41 ++++++++++++++++++++++++++++++++------ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 72d5d7fe91..53286e0a35 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1112,11 +1112,31 @@ where /// Creates a new [`ProgressBar`]. /// +/// Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation. +/// /// It expects: /// * an inclusive range of possible values, and /// * the current value of the [`ProgressBar`]. /// -/// [`ProgressBar`]: crate::ProgressBar +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::progress_bar; +/// +/// struct State { +/// progress: f32, +/// } +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// progress_bar(0.0..=100.0, state.progress).into() +/// } +/// ``` pub fn progress_bar<'a, Theme>( range: RangeInclusive, value: f32, diff --git a/widget/src/progress_bar.rs b/widget/src/progress_bar.rs index a10feea6d3..8c665c8cba 100644 --- a/widget/src/progress_bar.rs +++ b/widget/src/progress_bar.rs @@ -1,4 +1,24 @@ -//! Provide progress feedback to your users. +//! Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::progress_bar; +//! +//! struct State { +//! progress: f32, +//! } +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! progress_bar(0.0..=100.0, state.progress).into() +//! } +//! ``` use crate::core::border::{self, Border}; use crate::core::layout; use crate::core::mouse; @@ -15,14 +35,23 @@ use std::ops::RangeInclusive; /// /// # Example /// ```no_run -/// # type ProgressBar<'a> = iced_widget::ProgressBar<'a>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// let value = 50.0; +/// use iced::widget::progress_bar; /// -/// ProgressBar::new(0.0..=100.0, value); -/// ``` +/// struct State { +/// progress: f32, +/// } +/// +/// enum Message { +/// // ... +/// } /// -/// ![Progress bar drawn with `iced_wgpu`](https://user-images.githubusercontent.com/18618951/71662391-a316c200-2d51-11ea-9cef-52758cab85e3.png) +/// fn view(state: &State) -> Element<'_, Message> { +/// progress_bar(0.0..=100.0, state.progress).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct ProgressBar<'a, Theme = crate::Theme> where From 1595e78b1ad58e09dfa049546f6627dd5f80075b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:05:09 +0200 Subject: [PATCH 33/47] Show `qr_code` doc example in multiple places --- widget/src/helpers.rs | 23 ++++++++++++++++++++++ widget/src/qr_code.rs | 44 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 53286e0a35..4be5045a99 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1290,8 +1290,31 @@ where /// Creates a new [`QRCode`] widget from the given [`Data`]. /// +/// QR codes display information in a type of two-dimensional matrix barcode. +/// /// [`QRCode`]: crate::QRCode /// [`Data`]: crate::qr_code::Data +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::qr_code; +/// +/// struct State { +/// data: qr_code::Data, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// qr_code(&state.data).into() +/// } +/// ``` #[cfg(feature = "qr_code")] pub fn qr_code<'a, Theme>( data: &'a crate::qr_code::Data, diff --git a/widget/src/qr_code.rs b/widget/src/qr_code.rs index e064aadae7..21dee6b158 100644 --- a/widget/src/qr_code.rs +++ b/widget/src/qr_code.rs @@ -1,4 +1,25 @@ -//! Encode and display information in a QR code. +//! QR codes display information in a type of two-dimensional matrix barcode. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::qr_code; +//! +//! struct State { +//! data: qr_code::Data, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! qr_code(&state.data).into() +//! } +//! ``` use crate::canvas; use crate::core::layout; use crate::core::mouse; @@ -18,6 +39,27 @@ const QUIET_ZONE: usize = 2; /// A type of matrix barcode consisting of squares arranged in a grid which /// can be read by an imaging device, such as a camera. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::qr_code; +/// +/// struct State { +/// data: qr_code::Data, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// qr_code(&state.data).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct QRCode<'a, Theme = crate::Theme> where From b778d5cd567679619809b05e672398d3141558fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:14:17 +0200 Subject: [PATCH 34/47] Show `radio` doc example in multiple places --- widget/src/helpers.rs | 59 +++++++++++++++++- widget/src/radio.rs | 136 ++++++++++++++++++++++++++++++------------ 2 files changed, 157 insertions(+), 38 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 4be5045a99..1e9bafa78e 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -832,7 +832,64 @@ where /// Creates a new [`Radio`]. /// -/// [`Radio`]: crate::Radio +/// Radio buttons let users choose a single option from a bunch of options. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::{column, radio}; +/// +/// struct State { +/// selection: Option, +/// } +/// +/// #[derive(Debug, Clone, Copy)] +/// enum Message { +/// RadioSelected(Choice), +/// } +/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// enum Choice { +/// A, +/// B, +/// C, +/// All, +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// let a = radio( +/// "A", +/// Choice::A, +/// state.selection, +/// Message::RadioSelected, +/// ); +/// +/// let b = radio( +/// "B", +/// Choice::B, +/// state.selection, +/// Message::RadioSelected, +/// ); +/// +/// let c = radio( +/// "C", +/// Choice::C, +/// state.selection, +/// Message::RadioSelected, +/// ); +/// +/// let all = radio( +/// "All of the above", +/// Choice::All, +/// state.selection, +/// Message::RadioSelected +/// ); +/// +/// column![a, b, c, all].into() +/// } +/// ``` pub fn radio<'a, Message, Theme, Renderer, V>( label: impl Into, value: V, diff --git a/widget/src/radio.rs b/widget/src/radio.rs index cfa961f38e..300318fde8 100644 --- a/widget/src/radio.rs +++ b/widget/src/radio.rs @@ -1,4 +1,61 @@ -//! Create choices using radio buttons. +//! Radio buttons let users choose a single option from a bunch of options. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::{column, radio}; +//! +//! struct State { +//! selection: Option, +//! } +//! +//! #[derive(Debug, Clone, Copy)] +//! enum Message { +//! RadioSelected(Choice), +//! } +//! +//! #[derive(Debug, Clone, Copy, PartialEq, Eq)] +//! enum Choice { +//! A, +//! B, +//! C, +//! All, +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! let a = radio( +//! "A", +//! Choice::A, +//! state.selection, +//! Message::RadioSelected, +//! ); +//! +//! let b = radio( +//! "B", +//! Choice::B, +//! state.selection, +//! Message::RadioSelected, +//! ); +//! +//! let c = radio( +//! "C", +//! Choice::C, +//! state.selection, +//! Message::RadioSelected, +//! ); +//! +//! let all = radio( +//! "All of the above", +//! Choice::All, +//! state.selection, +//! Message::RadioSelected +//! ); +//! +//! column![a, b, c, all].into() +//! } +//! ``` use crate::core::alignment; use crate::core::border::{self, Border}; use crate::core::event::{self, Event}; @@ -18,54 +75,59 @@ use crate::core::{ /// /// # Example /// ```no_run -/// # type Radio<'a, Message> = -/// # iced_widget::Radio<'a, Message, iced_widget::Theme, iced_widget::renderer::Renderer>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// # use iced_widget::column; -/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] -/// pub enum Choice { -/// A, -/// B, -/// C, -/// All, +/// use iced::widget::{column, radio}; +/// +/// struct State { +/// selection: Option, /// } /// /// #[derive(Debug, Clone, Copy)] -/// pub enum Message { +/// enum Message { /// RadioSelected(Choice), /// } /// -/// let selected_choice = Some(Choice::A); +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// enum Choice { +/// A, +/// B, +/// C, +/// All, +/// } /// -/// let a = Radio::new( -/// "A", -/// Choice::A, -/// selected_choice, -/// Message::RadioSelected, -/// ); +/// fn view(state: &State) -> Element<'_, Message> { +/// let a = radio( +/// "A", +/// Choice::A, +/// state.selection, +/// Message::RadioSelected, +/// ); /// -/// let b = Radio::new( -/// "B", -/// Choice::B, -/// selected_choice, -/// Message::RadioSelected, -/// ); +/// let b = radio( +/// "B", +/// Choice::B, +/// state.selection, +/// Message::RadioSelected, +/// ); /// -/// let c = Radio::new( -/// "C", -/// Choice::C, -/// selected_choice, -/// Message::RadioSelected, -/// ); +/// let c = radio( +/// "C", +/// Choice::C, +/// state.selection, +/// Message::RadioSelected, +/// ); /// -/// let all = Radio::new( -/// "All of the above", -/// Choice::All, -/// selected_choice, -/// Message::RadioSelected -/// ); +/// let all = radio( +/// "All of the above", +/// Choice::All, +/// state.selection, +/// Message::RadioSelected +/// ); /// -/// let content = column![a, b, c, all]; +/// column![a, b, c, all].into() +/// } /// ``` #[allow(missing_debug_implementations)] pub struct Radio<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> From 24fcc57873bdf2605c9df26d240d67d8e26873ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:19:54 +0200 Subject: [PATCH 35/47] Show `rule` doc example in multiple places --- widget/src/helpers.rs | 34 ++++++++++++++++++++++++++++++++-- widget/src/rule.rs | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 1e9bafa78e..40a724527e 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1149,7 +1149,22 @@ pub fn vertical_space() -> Space { /// Creates a horizontal [`Rule`] with the given height. /// -/// [`Rule`]: crate::Rule +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::horizontal_rule; +/// +/// #[derive(Clone)] +/// enum Message { +/// // ..., +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// horizontal_rule(2).into() +/// } +/// ``` pub fn horizontal_rule<'a, Theme>(height: impl Into) -> Rule<'a, Theme> where Theme: rule::Catalog + 'a, @@ -1159,7 +1174,22 @@ where /// Creates a vertical [`Rule`] with the given width. /// -/// [`Rule`]: crate::Rule +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::vertical_rule; +/// +/// #[derive(Clone)] +/// enum Message { +/// // ..., +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// vertical_rule(2).into() +/// } +/// ``` pub fn vertical_rule<'a, Theme>(width: impl Into) -> Rule<'a, Theme> where Theme: rule::Catalog + 'a, diff --git a/widget/src/rule.rs b/widget/src/rule.rs index bbcd577e5d..92199ca9bf 100644 --- a/widget/src/rule.rs +++ b/widget/src/rule.rs @@ -1,4 +1,21 @@ -//! Display a horizontal or vertical rule for dividing content. +//! Rules divide space horizontally or vertically. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::horizontal_rule; +//! +//! #[derive(Clone)] +//! enum Message { +//! // ..., +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! horizontal_rule(2).into() +//! } +//! ``` use crate::core; use crate::core::border; use crate::core::layout; @@ -10,6 +27,23 @@ use crate::core::{ }; /// Display a horizontal or vertical rule for dividing content. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::horizontal_rule; +/// +/// #[derive(Clone)] +/// enum Message { +/// // ..., +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// horizontal_rule(2).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Rule<'a, Theme = crate::Theme> where From 94f0e0a2125faae7ea331f2edba99dd44b28a41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:30:12 +0200 Subject: [PATCH 36/47] Show `scrollable` doc example in multiple places --- widget/src/helpers.rs | 22 ++++++++++++++++++++- widget/src/scrollable.rs | 42 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 40a724527e..9854c0bf5d 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -681,7 +681,27 @@ where /// Creates a new [`Scrollable`] with the provided content. /// -/// [`Scrollable`]: crate::Scrollable +/// Scrollables let users navigate an endless amount of content with a scrollbar. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{column, scrollable, vertical_space}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// scrollable(column![ +/// "Scroll me!", +/// vertical_space().height(3000), +/// "You did it!", +/// ]).into() +/// } +/// ``` pub fn scrollable<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Scrollable<'a, Message, Theme, Renderer> diff --git a/widget/src/scrollable.rs b/widget/src/scrollable.rs index a56101661c..01638a48d0 100644 --- a/widget/src/scrollable.rs +++ b/widget/src/scrollable.rs @@ -1,4 +1,24 @@ -//! Navigate an endless amount of content with a scrollbar. +//! Scrollables let users navigate an endless amount of content with a scrollbar. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::{column, scrollable, vertical_space}; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! scrollable(column![ +//! "Scroll me!", +//! vertical_space().height(3000), +//! "You did it!", +//! ]).into() +//! } +//! ``` use crate::container; use crate::core::border::{self, Border}; use crate::core::event::{self, Event}; @@ -24,6 +44,26 @@ pub use operation::scrollable::{AbsoluteOffset, RelativeOffset}; /// A widget that can vertically display an infinite amount of content with a /// scrollbar. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{column, scrollable, vertical_space}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// scrollable(column![ +/// "Scroll me!", +/// vertical_space().height(3000), +/// "You did it!", +/// ]).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Scrollable< 'a, From 10fa40a85f09921c015fb2632aa34b9ef26d13cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:42:21 +0200 Subject: [PATCH 37/47] Show `slider` doc example in multiple places --- widget/src/helpers.rs | 62 +++++++++++++++++++++++++++++++++-- widget/src/slider.rs | 60 ++++++++++++++++++++++++++++----- widget/src/vertical_slider.rs | 58 ++++++++++++++++++++++++++++---- 3 files changed, 162 insertions(+), 18 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 9854c0bf5d..a8da2a320d 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -969,7 +969,36 @@ where /// Creates a new [`Slider`]. /// -/// [`Slider`]: crate::Slider +/// Sliders let users set a value by moving an indicator. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::slider; +/// +/// struct State { +/// value: f32, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// ValueChanged(f32), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// slider(0.0..=100.0, state.value, Message::ValueChanged).into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ValueChanged(value) => { +/// state.value = value; +/// } +/// } +/// } +/// ``` pub fn slider<'a, T, Message, Theme>( range: std::ops::RangeInclusive, value: T, @@ -985,7 +1014,36 @@ where /// Creates a new [`VerticalSlider`]. /// -/// [`VerticalSlider`]: crate::VerticalSlider +/// Sliders let users set a value by moving an indicator. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::vertical_slider; +/// +/// struct State { +/// value: f32, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// ValueChanged(f32), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ValueChanged(value) => { +/// state.value = value; +/// } +/// } +/// } +/// ``` pub fn vertical_slider<'a, T, Message, Theme>( range: std::ops::RangeInclusive, value: T, diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 15514afe0a..9477958d3d 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -1,4 +1,33 @@ -//! Display an interactive selector of a single value from a range of values. +//! Sliders let users set a value by moving an indicator. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::slider; +//! +//! struct State { +//! value: f32, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! ValueChanged(f32), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! slider(0.0..=100.0, state.value, Message::ValueChanged).into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::ValueChanged(value) => { +//! state.value = value; +//! } +//! } +//! } +//! ``` use crate::core::border::{self, Border}; use crate::core::event::{self, Event}; use crate::core::keyboard; @@ -25,19 +54,32 @@ use std::ops::RangeInclusive; /// /// # Example /// ```no_run -/// # type Slider<'a, T, Message> = iced_widget::Slider<'a, Message, T>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// #[derive(Clone)] -/// pub enum Message { -/// SliderChanged(f32), +/// use iced::widget::slider; +/// +/// struct State { +/// value: f32, /// } /// -/// let value = 50.0; +/// #[derive(Debug, Clone)] +/// enum Message { +/// ValueChanged(f32), +/// } /// -/// Slider::new(0.0..=100.0, value, Message::SliderChanged); -/// ``` +/// fn view(state: &State) -> Element<'_, Message> { +/// slider(0.0..=100.0, state.value, Message::ValueChanged).into() +/// } /// -/// ![Slider drawn by Coffee's renderer](https://github.com/hecrj/coffee/blob/bda9818f823dfcb8a7ad0ff4940b4d4b387b5208/images/ui/slider.png?raw=true) +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ValueChanged(value) => { +/// state.value = value; +/// } +/// } +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Slider<'a, T, Message, Theme = crate::Theme> where diff --git a/widget/src/vertical_slider.rs b/widget/src/vertical_slider.rs index a75ba49c3f..18633474e2 100644 --- a/widget/src/vertical_slider.rs +++ b/widget/src/vertical_slider.rs @@ -1,4 +1,33 @@ -//! Display an interactive selector of a single value from a range of values. +//! Sliders let users set a value by moving an indicator. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::slider; +//! +//! struct State { +//! value: f32, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! ValueChanged(f32), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! slider(0.0..=100.0, state.value, Message::ValueChanged).into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::ValueChanged(value) => { +//! state.value = value; +//! } +//! } +//! } +//! ``` use std::ops::RangeInclusive; pub use crate::slider::{ @@ -29,16 +58,31 @@ use crate::core::{ /// /// # Example /// ```no_run -/// # type VerticalSlider<'a, T, Message> = iced_widget::VerticalSlider<'a, T, Message>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// #[derive(Clone)] -/// pub enum Message { -/// SliderChanged(f32), +/// use iced::widget::vertical_slider; +/// +/// struct State { +/// value: f32, /// } /// -/// let value = 50.0; +/// #[derive(Debug, Clone)] +/// enum Message { +/// ValueChanged(f32), +/// } /// -/// VerticalSlider::new(0.0..=100.0, value, Message::SliderChanged); +/// fn view(state: &State) -> Element<'_, Message> { +/// vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ValueChanged(value) => { +/// state.value = value; +/// } +/// } +/// } /// ``` #[allow(missing_debug_implementations)] pub struct VerticalSlider<'a, T, Message, Theme = crate::Theme> From 9773631354aa1af354647fbdbdd8111da2816afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 05:45:40 +0200 Subject: [PATCH 38/47] Show `svg` doc example in multiple places --- widget/src/helpers.rs | 18 ++++++++++++++++++ widget/src/svg.rs | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index a8da2a320d..146393dce3 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -1341,8 +1341,26 @@ pub fn image(handle: impl Into) -> crate::Image { /// Creates a new [`Svg`] widget from the given [`Handle`]. /// +/// Svg widgets display vector graphics in your application. +/// /// [`Svg`]: crate::Svg /// [`Handle`]: crate::svg::Handle +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::svg; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// svg("tiger.svg").into() +/// } +/// ``` #[cfg(feature = "svg")] pub fn svg<'a, Theme>( handle: impl Into, diff --git a/widget/src/svg.rs b/widget/src/svg.rs index bec0090fb4..8d57265a7a 100644 --- a/widget/src/svg.rs +++ b/widget/src/svg.rs @@ -1,4 +1,20 @@ -//! Display vector graphics in your application. +//! Svg widgets display vector graphics in your application. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::svg; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! svg("tiger.svg").into() +//! } +//! ``` use crate::core::layout; use crate::core::mouse; use crate::core::renderer; @@ -19,6 +35,22 @@ pub use crate::core::svg::Handle; /// /// [`Svg`] images can have a considerable rendering cost when resized, /// specially when they are complex. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::svg; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// svg("tiger.svg").into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Svg<'a, Theme = crate::Theme> where From 6ad7c7d3080816d37b17f1f6f5af5d8761983fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:10:44 +0200 Subject: [PATCH 39/47] Show `text` doc examples in multiple places --- core/src/widget/text.rs | 46 +++++++++++++++++++++++++++++++++++++++-- widget/src/helpers.rs | 46 +++++++++++++++++++++++++++++------------ widget/src/text.rs | 22 +++++++++++++++++++- 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index d8d6e4c6ba..8b02f8c238 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -1,4 +1,25 @@ -//! Write some text for your users to read. +//! Text widgets display information through writing. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub fn text(t: T) -> iced_core::widget::Text<'static, iced_core::Theme, ()> { unimplemented!() } } +//! # pub use iced_core::color; } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>; +//! use iced::widget::text; +//! use iced::color; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! text("Hello, this is iced!") +//! .size(20) +//! .color(color!(0x0000ff)) +//! .into() +//! } +//! ``` use crate::alignment; use crate::layout; use crate::mouse; @@ -13,7 +34,28 @@ use crate::{ pub use text::{LineHeight, Shaping, Wrapping}; -/// A paragraph of text. +/// A bunch of text. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub fn text(t: T) -> iced_core::widget::Text<'static, iced_core::Theme, ()> { unimplemented!() } } +/// # pub use iced_core::color; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_core::Element<'a, Message, iced_core::Theme, ()>; +/// use iced::widget::text; +/// use iced::color; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text("Hello, this is iced!") +/// .size(20) +/// .color(color!(0x0000ff)) +/// .into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Text<'a, Theme, Renderer> where diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 146393dce3..142d64d6aa 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -81,7 +81,6 @@ macro_rules! stack { /// /// ```no_run /// # mod iced { -/// # pub struct Element(pub std::marker::PhantomData); /// # pub mod widget { /// # macro_rules! text { /// # ($($arg:tt)*) => {unimplemented!()} @@ -89,22 +88,23 @@ macro_rules! stack { /// # pub(crate) use text; /// # } /// # } -/// # struct Example; -/// # enum Message {} -/// use iced::Element; +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>; /// use iced::widget::text; /// -/// impl Example { -/// fn view(&self) -> Element { -/// let simple = text!("Hello, world!"); +/// enum Message { +/// // ... +/// } +/// +/// fn view(_state: &State) -> Element { +/// let simple = text!("Hello, world!"); /// -/// let keyword = text!("Hello, {}", "world!"); +/// let keyword = text!("Hello, {}", "world!"); /// -/// let planet = "Earth"; -/// let local_variable = text!("Hello, {planet}!"); -/// // ... -/// # iced::Element(std::marker::PhantomData) -/// } +/// let planet = "Earth"; +/// let local_variable = text!("Hello, {planet}!"); +/// // ... +/// # unimplemented!() /// } /// ``` #[macro_export] @@ -758,6 +758,26 @@ where } /// Creates a new [`Text`] widget with the provided content. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>; +/// use iced::widget::text; +/// use iced::color; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text("Hello, this is iced!") +/// .size(20) +/// .color(color!(0x0000ff)) +/// .into() +/// } +/// ``` pub fn text<'a, Theme, Renderer>( text: impl text::IntoFragment<'a>, ) -> Text<'a, Theme, Renderer> diff --git a/widget/src/text.rs b/widget/src/text.rs index 9bf7fce41c..c22434342a 100644 --- a/widget/src/text.rs +++ b/widget/src/text.rs @@ -5,6 +5,26 @@ pub use crate::core::text::{Fragment, Highlighter, IntoFragment, Span}; pub use crate::core::widget::text::*; pub use rich::Rich; -/// A paragraph. +/// A bunch of text. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::text; +/// use iced::color; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text("Hello, this is iced!") +/// .size(20) +/// .color(color!(0x0000ff)) +/// .into() +/// } +/// ``` pub type Text<'a, Theme = crate::Theme, Renderer = crate::Renderer> = crate::core::widget::Text<'a, Theme, Renderer>; From 184ebebfe12c9ea68b91a0a5db59f8b599b5bc5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:14:56 +0200 Subject: [PATCH 40/47] Show `text_editor` example in multiple places --- widget/src/helpers.rs | 34 +++++++++++++++++++- widget/src/text_editor.rs | 66 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 142d64d6aa..ca401a8985 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -975,7 +975,39 @@ where /// Creates a new [`TextEditor`]. /// -/// [`TextEditor`]: crate::TextEditor +/// Text editors display a multi-line text input for text editing. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::text_editor; +/// +/// struct State { +/// content: text_editor::Content, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// Edit(text_editor::Action) +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text_editor(&state.content) +/// .placeholder("Type something here...") +/// .on_action(Message::Edit) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::Edit(action) => { +/// state.content.perform(action); +/// } +/// } +/// } +/// ``` pub fn text_editor<'a, Message, Theme, Renderer>( content: &'a text_editor::Content, ) -> TextEditor<'a, core::text::highlighter::PlainText, Message, Theme, Renderer> diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index 1df97962a2..5979531896 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -1,4 +1,36 @@ -//! Display a multi-line text input for text editing. +//! Text editors display a multi-line text input for text editing. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::text_editor; +//! +//! struct State { +//! content: text_editor::Content, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! Edit(text_editor::Action) +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! text_editor(&state.content) +//! .placeholder("Type something here...") +//! .on_action(Message::Edit) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::Edit(action) => { +//! state.content.perform(action); +//! } +//! } +//! } +//! ``` use crate::core::alignment; use crate::core::clipboard::{self, Clipboard}; use crate::core::event::{self, Event}; @@ -27,6 +59,38 @@ use std::sync::Arc; pub use text::editor::{Action, Edit, Motion}; /// A multi-line text input. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::text_editor; +/// +/// struct State { +/// content: text_editor::Content, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// Edit(text_editor::Action) +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text_editor(&state.content) +/// .placeholder("Type something here...") +/// .on_action(Message::Edit) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::Edit(action) => { +/// state.content.perform(action); +/// } +/// } +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct TextEditor< 'a, From e0c55cbb19a6362b6a86bf71031ecaa26d673e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:18:00 +0200 Subject: [PATCH 41/47] Show `text_input` doc example in multiple places --- widget/src/helpers.rs | 33 ++++++++++++++++++++- widget/src/text_input.rs | 64 ++++++++++++++++++++++++++++++++-------- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index ca401a8985..cf8c05206d 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -960,7 +960,38 @@ where /// Creates a new [`TextInput`]. /// -/// [`TextInput`]: crate::TextInput +/// Text inputs display fields that can be filled with text. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::text_input; +/// +/// struct State { +/// content: String, +/// } +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// ContentChanged(String) +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// text_input("Type something here...", &state.content) +/// .on_input(Message::ContentChanged) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ContentChanged(content) => { +/// state.content = content; +/// } +/// } +/// } +/// ``` pub fn text_input<'a, Message, Theme, Renderer>( placeholder: &str, value: &str, diff --git a/widget/src/text_input.rs b/widget/src/text_input.rs index 3032dd1353..5bbf76f59a 100644 --- a/widget/src/text_input.rs +++ b/widget/src/text_input.rs @@ -1,6 +1,35 @@ -//! Display fields that can be filled with text. +//! Text inputs display fields that can be filled with text. //! -//! A [`TextInput`] has some local [`State`]. +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::text_input; +//! +//! struct State { +//! content: String, +//! } +//! +//! #[derive(Debug, Clone)] +//! enum Message { +//! ContentChanged(String) +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! text_input("Type something here...", &state.content) +//! .on_input(Message::ContentChanged) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::ContentChanged(content) => { +//! state.content = content; +//! } +//! } +//! } +//! ``` mod editor; mod value; @@ -38,23 +67,34 @@ use crate::runtime::Action; /// /// # Example /// ```no_run -/// # pub type TextInput<'a, Message> = iced_widget::TextInput<'a, Message>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # +/// use iced::widget::text_input; +/// +/// struct State { +/// content: String, +/// } +/// /// #[derive(Debug, Clone)] /// enum Message { -/// TextInputChanged(String), +/// ContentChanged(String) /// } /// -/// let value = "Some text"; +/// fn view(state: &State) -> Element<'_, Message> { +/// text_input("Type something here...", &state.content) +/// .on_input(Message::ContentChanged) +/// .into() +/// } /// -/// let input = TextInput::new( -/// "This is the placeholder...", -/// value, -/// ) -/// .on_input(Message::TextInputChanged) -/// .padding(10); +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::ContentChanged(content) => { +/// state.content = content; +/// } +/// } +/// } /// ``` -/// ![Text input drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/text_input.png?raw=true) #[allow(missing_debug_implementations)] pub struct TextInput< 'a, From 22fbb9c2213892ae7981d5946b177a8846c4399e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:22:09 +0200 Subject: [PATCH 42/47] Show `toggler` doc example in multiple places --- widget/src/helpers.rs | 33 ++++++++++++++++++++++- widget/src/toggler.rs | 62 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index cf8c05206d..ec4f226566 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -947,7 +947,38 @@ where /// Creates a new [`Toggler`]. /// -/// [`Toggler`]: crate::Toggler +/// Togglers let users make binary choices by toggling a switch. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// # +/// use iced::widget::toggler; +/// +/// struct State { +/// is_checked: bool, +/// } +/// +/// enum Message { +/// TogglerToggled(bool), +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// toggler(state.is_checked) +/// .label("Toggle me!") +/// .on_toggle(Message::TogglerToggled) +/// .into() +/// } +/// +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::TogglerToggled(is_checked) => { +/// state.is_checked = is_checked; +/// } +/// } +/// } +/// ``` pub fn toggler<'a, Message, Theme, Renderer>( is_checked: bool, ) -> Toggler<'a, Message, Theme, Renderer> diff --git a/widget/src/toggler.rs b/widget/src/toggler.rs index 1c425dc194..3b41208195 100644 --- a/widget/src/toggler.rs +++ b/widget/src/toggler.rs @@ -1,4 +1,35 @@ -//! Show toggle controls using togglers. +//! Togglers let users make binary choices by toggling a switch. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! # +//! use iced::widget::toggler; +//! +//! struct State { +//! is_checked: bool, +//! } +//! +//! enum Message { +//! TogglerToggled(bool), +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//! toggler(state.is_checked) +//! .label("Toggle me!") +//! .on_toggle(Message::TogglerToggled) +//! .into() +//! } +//! +//! fn update(state: &mut State, message: Message) { +//! match message { +//! Message::TogglerToggled(is_checked) => { +//! state.is_checked = is_checked; +//! } +//! } +//! } +//! ``` use crate::core::alignment; use crate::core::event; use crate::core::layout; @@ -16,19 +47,34 @@ use crate::core::{ /// A toggler widget. /// /// # Example -/// /// ```no_run -/// # type Toggler<'a, Message> = iced_widget::Toggler<'a, Message>; +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # -/// pub enum Message { +/// use iced::widget::toggler; +/// +/// struct State { +/// is_checked: bool, +/// } +/// +/// enum Message { /// TogglerToggled(bool), /// } /// -/// let is_toggled = true; +/// fn view(state: &State) -> Element<'_, Message> { +/// toggler(state.is_checked) +/// .label("Toggle me!") +/// .on_toggle(Message::TogglerToggled) +/// .into() +/// } /// -/// Toggler::new(is_toggled) -/// .label("Toggle me!") -/// .on_toggle(Message::TogglerToggled); +/// fn update(state: &mut State, message: Message) { +/// match message { +/// Message::TogglerToggled(is_checked) => { +/// state.is_checked = is_checked; +/// } +/// } +/// } /// ``` #[allow(missing_debug_implementations)] pub struct Toggler< From 4e38992636dded5868e74e5630a5da72bb4e5f93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:27:54 +0200 Subject: [PATCH 43/47] Show `tooltip` doc example in multiple places --- widget/src/helpers.rs | 25 +++++++++++++++++++++-- widget/src/tooltip.rs | 46 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index ec4f226566..817d437cad 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -743,8 +743,29 @@ where /// Creates a new [`Tooltip`] for the provided content with the given /// [`Element`] and [`tooltip::Position`]. /// -/// [`Tooltip`]: crate::Tooltip -/// [`tooltip::Position`]: crate::tooltip::Position +/// Tooltips display a hint of information over some element when hovered. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{container, tooltip}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(_state: &State) -> Element<'_, Message> { +/// tooltip( +/// "Hover me to display the tooltip!", +/// container("This is the tooltip contents!") +/// .padding(10) +/// .style(container::rounded_box), +/// tooltip::Position::Bottom, +/// ).into() +/// } +/// ``` pub fn tooltip<'a, Message, Theme, Renderer>( content: impl Into>, tooltip: impl Into>, diff --git a/widget/src/tooltip.rs b/widget/src/tooltip.rs index 39f2e07de0..e98f4da7ea 100644 --- a/widget/src/tooltip.rs +++ b/widget/src/tooltip.rs @@ -1,4 +1,26 @@ -//! Display a widget over another. +//! Tooltips display a hint of information over some element when hovered. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::{container, tooltip}; +//! +//! enum Message { +//! // ... +//! } +//! +//! fn view(_state: &State) -> Element<'_, Message> { +//! tooltip( +//! "Hover me to display the tooltip!", +//! container("This is the tooltip contents!") +//! .padding(10) +//! .style(container::rounded_box), +//! tooltip::Position::Bottom, +//! ).into() +//! } +//! ``` use crate::container; use crate::core::event::{self, Event}; use crate::core::layout::{self, Layout}; @@ -13,6 +35,28 @@ use crate::core::{ }; /// An element to display a widget over another. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{container, tooltip}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(_state: &State) -> Element<'_, Message> { +/// tooltip( +/// "Hover me to display the tooltip!", +/// container("This is the tooltip contents!") +/// .padding(10) +/// .style(container::rounded_box), +/// tooltip::Position::Bottom, +/// ).into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Tooltip< 'a, From cda1369c790cac27dce90abaead2bca940047ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:38:48 +0200 Subject: [PATCH 44/47] Write doc examples for `rich_text` widget --- widget/src/helpers.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 817d437cad..e17ef424f7 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -117,6 +117,31 @@ macro_rules! text { /// Creates some [`Rich`] text with the given spans. /// /// [`Rich`]: text::Rich +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::font; +/// use iced::widget::{rich_text, span}; +/// use iced::{color, Font}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// rich_text![ +/// span("I am red!").color(color!(0xff0000)), +/// " ", +/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), +/// ] +/// .size(20) +/// .into() +/// } +/// ``` #[macro_export] macro_rules! rich_text { () => ( @@ -823,6 +848,31 @@ where /// Creates a new [`Rich`] text widget with the provided spans. /// /// [`Rich`]: text::Rich +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::font; +/// use iced::widget::{rich_text, span}; +/// use iced::{color, Font}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// rich_text([ +/// span("I am red!").color(color!(0xff0000)), +/// span(" "), +/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), +/// ]) +/// .size(20) +/// .into() +/// } +/// ``` pub fn rich_text<'a, Link, Theme, Renderer>( spans: impl AsRef<[text::Span<'a, Link, Renderer::Font>]> + 'a, ) -> text::Rich<'a, Link, Theme, Renderer> @@ -837,7 +887,35 @@ where /// Creates a new [`Span`] of text with the provided content. /// +/// A [`Span`] is a fragment of some [`Rich`] text. +/// /// [`Span`]: text::Span +/// [`Rich`]: text::Rich +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::font; +/// use iced::widget::{rich_text, span}; +/// use iced::{color, Font}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// rich_text![ +/// span("I am red!").color(color!(0xff0000)), +/// " ", +/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), +/// ] +/// .size(20) +/// .into() +/// } +/// ``` pub fn span<'a, Link, Font>( text: impl text::IntoFragment<'a>, ) -> text::Span<'a, Link, Font> { From 31c42c1d02d6a76dedaa780e6832a23765c8aef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:49:22 +0200 Subject: [PATCH 45/47] Write doc examples for `column` and `row` --- widget/src/column.rs | 21 +++++++++++ widget/src/helpers.rs | 84 ++++++++++++++++++++++++++++++++++++++++--- widget/src/row.rs | 21 +++++++++++ 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/widget/src/column.rs b/widget/src/column.rs index d3ea4cf7e3..fc4653b916 100644 --- a/widget/src/column.rs +++ b/widget/src/column.rs @@ -12,6 +12,27 @@ use crate::core::{ }; /// A container that distributes its contents vertically. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{button, column}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// column![ +/// "I am on top!", +/// button("I am in the center!"), +/// "I am below.", +/// ].into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Column<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> { diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index e17ef424f7..52290a54d5 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -31,7 +31,28 @@ use std::ops::RangeInclusive; /// Creates a [`Column`] with the given children. /// -/// [`Column`]: crate::Column +/// Columns distribute their children vertically. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{button, column}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// column![ +/// "I am on top!", +/// button("I am in the center!"), +/// "I am below.", +/// ].into() +/// } +/// ``` #[macro_export] macro_rules! column { () => ( @@ -44,7 +65,28 @@ macro_rules! column { /// Creates a [`Row`] with the given children. /// -/// [`Row`]: crate::Row +/// Rows distribute their children horizontally. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{button, row}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// row![ +/// "I am to the left!", +/// button("I am in the middle!"), +/// "I am to the right!", +/// ].into() +/// } +/// ``` #[macro_export] macro_rules! row { () => ( @@ -208,6 +250,24 @@ where } /// Creates a new [`Column`] with the given children. +/// +/// Columns distribute their children vertically. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{column, text}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// column((0..5).map(|i| text!("Item {i}").into())).into() +/// } +/// ``` pub fn column<'a, Message, Theme, Renderer>( children: impl IntoIterator>, ) -> Column<'a, Message, Theme, Renderer> @@ -248,9 +308,25 @@ where keyed::Column::with_children(children) } -/// Creates a new [`Row`] with the given children. +/// Creates a new [`Row`] from an iterator. /// -/// [`Row`]: crate::Row +/// Rows distribute their children horizontally. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{row, text}; +/// +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// row((0..5).map(|i| text!("Item {i}").into())).into() +/// } +/// ``` pub fn row<'a, Message, Theme, Renderer>( children: impl IntoIterator>, ) -> Row<'a, Message, Theme, Renderer> diff --git a/widget/src/row.rs b/widget/src/row.rs index 85af912f07..fbb3f06676 100644 --- a/widget/src/row.rs +++ b/widget/src/row.rs @@ -12,6 +12,27 @@ use crate::core::{ }; /// A container that distributes its contents horizontally. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::{button, row}; +/// +/// #[derive(Debug, Clone)] +/// enum Message { +/// // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +/// row![ +/// "I am to the left!", +/// button("I am in the middle!"), +/// "I am to the right!", +/// ].into() +/// } +/// ``` #[allow(missing_debug_implementations)] pub struct Row<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> { spacing: f32, From 1f8dc1f3dda25c699b94c653d5d569f4142e9b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 06:56:19 +0200 Subject: [PATCH 46/47] Fix `mouse_area` not notifying of mouse move events --- widget/src/mouse_area.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/src/mouse_area.rs b/widget/src/mouse_area.rs index d255ac999e..7330874ad7 100644 --- a/widget/src/mouse_area.rs +++ b/widget/src/mouse_area.rs @@ -316,7 +316,7 @@ fn update( let cursor_position = cursor.position(); let bounds = layout.bounds(); - if state.cursor_position != cursor_position && state.bounds != bounds { + if state.cursor_position != cursor_position || state.bounds != bounds { let was_hovered = state.is_hovered; state.is_hovered = cursor.is_over(layout.bounds()); From bf3b6f100df7b1585dfac88da432bc29784ed534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Thu, 19 Sep 2024 07:05:51 +0200 Subject: [PATCH 47/47] Bump version to `0.13.1` :tada: --- CHANGELOG.md | 20 +++++++++++++++++++- Cargo.toml | 24 ++++++++++++------------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6addcc699f..fff7d3417f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.1] - 2024-09-19 +### Added +- Some `From` trait implementations for `text_input::Id`. [#2582](https://github.com/iced-rs/iced/pull/2582) +- Custom `Executor` support for `Application` and `Daemon`. [#2580](https://github.com/iced-rs/iced/pull/2580) +- `rust-version` metadata to `Cargo.toml`. [#2579](https://github.com/iced-rs/iced/pull/2579) +- Widget examples to API reference. [#2587](https://github.com/iced-rs/iced/pull/2587) + +### Fixed +- Inverted scrolling direction with trackpad in `scrollable`. [#2583](https://github.com/iced-rs/iced/pull/2583) +- `scrollable` transactions when `on_scroll` is not set. [#2584](https://github.com/iced-rs/iced/pull/2584) +- Incorrect text color styling in `text_editor` widget. [#2586](https://github.com/iced-rs/iced/pull/2586) + +Many thanks to... +- @dcampbell24 +- @lufte +- @mtkennerly + ## [0.13.0] - 2024-09-18 ### Added - Introductory chapters to the [official guide book](https://book.iced.rs/). @@ -971,7 +988,8 @@ Many thanks to... ### Added - First release! :tada: -[Unreleased]: https://github.com/iced-rs/iced/compare/0.13.0...HEAD +[Unreleased]: https://github.com/iced-rs/iced/compare/0.13.1...HEAD +[0.13.1]: https://github.com/iced-rs/iced/compare/0.13.0...0.13.1 [0.13.0]: https://github.com/iced-rs/iced/compare/0.12.1...0.13.0 [0.12.1]: https://github.com/iced-rs/iced/compare/0.12.0...0.12.1 [0.12.0]: https://github.com/iced-rs/iced/compare/0.10.0...0.12.0 diff --git a/Cargo.toml b/Cargo.toml index df087fdfe3..52cd4c4921 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -117,7 +117,7 @@ members = [ ] [workspace.package] -version = "0.13.0" +version = "0.13.1" authors = ["Héctor Ramón Jiménez "] edition = "2021" license = "MIT" @@ -128,17 +128,17 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"] rust-version = "1.80" [workspace.dependencies] -iced = { version = "0.13.0", path = "." } -iced_core = { version = "0.13.0", path = "core" } -iced_futures = { version = "0.13.0", path = "futures" } -iced_graphics = { version = "0.13.0", path = "graphics" } -iced_highlighter = { version = "0.13.0", path = "highlighter" } -iced_renderer = { version = "0.13.0", path = "renderer" } -iced_runtime = { version = "0.13.0", path = "runtime" } -iced_tiny_skia = { version = "0.13.0", path = "tiny_skia" } -iced_wgpu = { version = "0.13.0", path = "wgpu" } -iced_widget = { version = "0.13.0", path = "widget" } -iced_winit = { version = "0.13.0", path = "winit" } +iced = { version = "0.13", path = "." } +iced_core = { version = "0.13", path = "core" } +iced_futures = { version = "0.13", path = "futures" } +iced_graphics = { version = "0.13", path = "graphics" } +iced_highlighter = { version = "0.13", path = "highlighter" } +iced_renderer = { version = "0.13", path = "renderer" } +iced_runtime = { version = "0.13", path = "runtime" } +iced_tiny_skia = { version = "0.13", path = "tiny_skia" } +iced_wgpu = { version = "0.13", path = "wgpu" } +iced_widget = { version = "0.13", path = "widget" } +iced_winit = { version = "0.13", path = "winit" } async-std = "1.0" bitflags = "2.0"