Skip to main content

iced/
lib.rs

1//! **toddy-iced** is a vendored fork of [iced](https://github.com/iced-rs/iced)
2//! maintained for the [Toddy](https://github.com/toddy-ui/toddy) project.
3//! See the [repository](https://github.com/toddy-ui/toddy-iced) for what's
4//! different from upstream.
5//!
6//! ---
7//!
8//! iced is a cross-platform GUI library focused on simplicity and type-safety.
9//! Inspired by [Elm].
10//!
11//! [Elm]: https://elm-lang.org/
12//!
13//! # Disclaimer
14//! iced is __experimental__ software. If you expect the documentation to hold your hand
15//! as you learn the ropes, you are in for a frustrating experience.
16//!
17//! The library leverages Rust to its full extent: ownership, borrowing, lifetimes, futures,
18//! streams, first-class functions, trait bounds, closures, and more. This documentation
19//! is not meant to teach you any of these. Far from it, it will assume you have __mastered__
20//! all of them.
21//!
22//! Furthermore—just like Rust—iced is very unforgiving. It will not let you easily cut corners.
23//! The type signatures alone can be used to learn how to use most of the library.
24//! Everything is connected.
25//!
26//! Therefore, iced is easy to learn for __advanced__ Rust programmers; but plenty of patient
27//! beginners have learned it and had a good time with it. Since it leverages a lot of what
28//! Rust has to offer in a type-safe way, it can be a great way to discover Rust itself.
29//!
30//! If you don't like the sound of that, you expect to be spoonfed, or you feel frustrated
31//! and struggle to use the library; then I recommend you to wait patiently until [the book]
32//! is finished.
33//!
34//! [the book]: https://book.iced.rs
35//!
36//! # The Pocket Guide
37//! Start by calling [`run`]:
38//!
39//! ```no_run,standalone_crate
40//! pub fn main() -> iced::Result {
41//!     iced::run(update, view)
42//! }
43//! # fn update(state: &mut (), message: ()) {}
44//! # fn view(state: &()) -> iced::Element<'_, ()> { iced::widget::text("").into() }
45//! ```
46//!
47//! Define an `update` function to __change__ your state:
48//!
49//! ```standalone_crate
50//! fn update(counter: &mut u64, message: Message) {
51//!     match message {
52//!         Message::Increment => *counter += 1,
53//!     }
54//! }
55//! # #[derive(Clone)]
56//! # enum Message { Increment }
57//! ```
58//!
59//! Define a `view` function to __display__ your state:
60//!
61//! ```standalone_crate
62//! use iced::widget::{button, text};
63//! use iced::Element;
64//!
65//! fn view(counter: &u64) -> Element<'_, Message> {
66//!     button(text(counter)).on_press(Message::Increment).into()
67//! }
68//! # #[derive(Clone)]
69//! # enum Message { Increment }
70//! ```
71//!
72//! And create a `Message` enum to __connect__ `view` and `update` together:
73//!
74//! ```standalone_crate
75//! #[derive(Debug, Clone)]
76//! enum Message {
77//!     Increment,
78//! }
79//! ```
80//!
81//! ## Custom State
82//! You can define your own struct for your state:
83//!
84//! ```standalone_crate
85//! #[derive(Default)]
86//! struct Counter {
87//!     value: u64,
88//! }
89//! ```
90//!
91//! But you have to change `update` and `view` accordingly:
92//!
93//! ```standalone_crate
94//! # struct Counter { value: u64 }
95//! # #[derive(Clone)]
96//! # enum Message { Increment }
97//! # use iced::widget::{button, text};
98//! # use iced::Element;
99//! fn update(counter: &mut Counter, message: Message) {
100//!     match message {
101//!         Message::Increment => counter.value += 1,
102//!     }
103//! }
104//!
105//! fn view(counter: &Counter) -> Element<'_, Message> {
106//!     button(text(counter.value)).on_press(Message::Increment).into()
107//! }
108//! ```
109//!
110//! ## Widgets and Elements
111//! The `view` function must return an [`Element`]. An [`Element`] is just a generic [`widget`].
112//!
113//! The [`widget`] module contains a bunch of functions to help you build
114//! and use widgets.
115//!
116//! Widgets are configured using the builder pattern:
117//!
118//! ```standalone_crate
119//! # struct Counter { value: u64 }
120//! # #[derive(Clone)]
121//! # enum Message { Increment }
122//! use iced::widget::{button, column, text};
123//! use iced::Element;
124//!
125//! fn view(counter: &Counter) -> Element<'_, Message> {
126//!     column![
127//!         text(counter.value).size(20),
128//!         button("Increment").on_press(Message::Increment),
129//!     ]
130//!     .spacing(10)
131//!     .into()
132//! }
133//! ```
134//!
135//! A widget can be turned into an [`Element`] by calling `into`.
136//!
137//! Widgets and elements are generic over the message type they produce. The
138//! [`Element`] returned by `view` must have the same `Message` type as
139//! your `update`.
140//!
141//! ## Layout
142//! There is no unified layout system in iced. Instead, each widget implements
143//! its own layout strategy.
144//!
145//! Building your layout will often consist in using a combination of
146//! [rows], [columns], and [containers]:
147//!
148//! ```standalone_crate
149//! # struct State;
150//! # enum Message {}
151//! use iced::widget::{column, container, row};
152//! use iced::{Fill, Element};
153//!
154//! fn view(state: &State) -> Element<'_, Message> {
155//!     container(
156//!         column![
157//!             "Top",
158//!             row!["Left", "Right"].spacing(10),
159//!             "Bottom"
160//!         ]
161//!         .spacing(10)
162//!     )
163//!     .padding(10)
164//!     .center_x(Fill)
165//!     .center_y(Fill)
166//!     .into()
167//! }
168//! ```
169//!
170//! Rows and columns lay out their children horizontally and vertically,
171//! respectively. [Spacing] can be easily added between elements.
172//!
173//! Containers position or align a single widget inside their bounds.
174//!
175//! [rows]: widget::Row
176//! [columns]: widget::Column
177//! [containers]: widget::Container
178//! [Spacing]: widget::Column::spacing
179//!
180//! ## Sizing
181//! The width and height of widgets can generally be defined using a [`Length`].
182//!
183//! - [`Fill`] will make the widget take all the available space in a given axis.
184//! - [`Shrink`] will make the widget use its intrinsic size.
185//!
186//! Most widgets use a [`Shrink`] sizing strategy by default, but will inherit
187//! a [`Fill`] strategy from their children.
188//!
189//! A fixed numeric [`Length`] in [`Pixels`] can also be used:
190//!
191//! ```standalone_crate
192//! # struct State;
193//! # enum Message {}
194//! use iced::widget::container;
195//! use iced::Element;
196//!
197//! fn view(state: &State) -> Element<'_, Message> {
198//!     container("I am 300px tall!").height(300).into()
199//! }
200//! ```
201//!
202//! ## Theming
203//! The default [`Theme`] of an application can be changed by defining a `theme`
204//! function and leveraging the [`Application`] builder, instead of directly
205//! calling [`run`]:
206//!
207//! ```no_run,standalone_crate
208//! # struct State;
209//! use iced::Theme;
210//!
211//! pub fn main() -> iced::Result {
212//!     iced::application(new, update, view)
213//!         .theme(theme)
214//!         .run()
215//! }
216//!
217//! fn new() -> State {
218//!     // ...
219//!     # State
220//! }
221//!
222//! fn theme(state: &State) -> Theme {
223//!     Theme::TokyoNight
224//! }
225//! # fn update(state: &mut State, message: ()) {}
226//! # fn view(state: &State) -> iced::Element<'_, ()> { iced::widget::text("").into() }
227//! ```
228//!
229//! The `theme` function takes the current state of the application, allowing the
230//! returned [`Theme`] to be completely dynamic—just like `view`.
231//!
232//! There are a bunch of built-in [`Theme`] variants at your disposal, but you can
233//! also [create your own](Theme::custom).
234//!
235//! ## Styling
236//! As with layout, iced does not have a unified styling system. However, all
237//! of the built-in widgets follow the same styling approach.
238//!
239//! The appearance of a widget can be changed by calling its `style` method:
240//!
241//! ```standalone_crate
242//! # struct State;
243//! # enum Message {}
244//! use iced::widget::container;
245//! use iced::Element;
246//!
247//! fn view(state: &State) -> Element<'_, Message> {
248//!     container("I am a rounded box!").style(container::rounded_box).into()
249//! }
250//! ```
251//!
252//! The `style` method of a widget takes a closure that, given the current active
253//! [`Theme`], returns the widget style:
254//!
255//! ```standalone_crate
256//! # struct State;
257//! # #[derive(Clone)]
258//! # enum Message {}
259//! use iced::widget::button;
260//! use iced::{Element, Theme};
261//!
262//! fn view(state: &State) -> Element<'_, Message> {
263//!     button("I am a styled button!").style(|theme: &Theme, status| {
264//!         let palette = theme.palette();
265//!
266//!         match status {
267//!             button::Status::Active => {
268//!                 button::Style::default()
269//!                    .with_background(palette.success.strong.color)
270//!             }
271//!             _ => button::primary(theme, status),
272//!         }
273//!     })
274//!     .into()
275//! }
276//! ```
277//!
278//! Widgets that can be in multiple different states will also provide the closure
279//! with some [`Status`], allowing you to use a different style for each state.
280//!
281//! You can extract the [`Palette`] colors of a [`Theme`] with the [`palette`] method.
282//!
283//! Most widgets provide styling functions for your convenience in their respective modules;
284//! like [`container::rounded_box`], [`button::primary`], or [`text::danger`].
285//!
286//! [`Status`]: widget::button::Status
287//! [`palette`]: Theme::palette
288//! [`container::rounded_box`]: widget::container::rounded_box
289//! [`button::primary`]: widget::button::primary
290//! [`text::danger`]: widget::text::danger
291//!
292//! ## Concurrent Tasks
293//! The `update` function can _optionally_ return a [`Task`].
294//!
295//! A [`Task`] can be leveraged to perform asynchronous work, like running a
296//! future or a stream:
297//!
298//! ```standalone_crate
299//! # #[derive(Clone)]
300//! # struct Weather;
301//! use iced::Task;
302//!
303//! struct State {
304//!     weather: Option<Weather>,
305//! }
306//!
307//! enum Message {
308//!    FetchWeather,
309//!    WeatherFetched(Weather),
310//! }
311//!
312//! fn update(state: &mut State, message: Message) -> Task<Message> {
313//!     match message {
314//!         Message::FetchWeather => Task::perform(
315//!             fetch_weather(),
316//!             Message::WeatherFetched,
317//!         ),
318//!         Message::WeatherFetched(weather) => {
319//!             state.weather = Some(weather);
320//!
321//!             Task::none()
322//!        }
323//!     }
324//! }
325//!
326//! async fn fetch_weather() -> Weather {
327//!     // ...
328//!     # unimplemented!()
329//! }
330//! ```
331//!
332//! Tasks can also be used to interact with the iced runtime. Some modules
333//! expose functions that create tasks for different purposes—like [changing
334//! window settings](window#functions), [focusing a widget](widget::operation::focus_next), or
335//! [querying its visible bounds](widget::selector::find).
336//!
337//! Like futures and streams, tasks expose [a monadic interface](Task::then)—but they can also be
338//! [mapped](Task::map), [chained](Task::chain), [batched](Task::batch), [canceled](Task::abortable),
339//! and more.
340//!
341//! ## Passive Subscriptions
342//! Applications can subscribe to passive sources of data—like time ticks or runtime events.
343//!
344//! You will need to define a `subscription` function and use the [`Application`] builder:
345//!
346//! ```no_run,standalone_crate
347//! # struct State;
348//! use iced::window;
349//! use iced::{Size, Subscription};
350//!
351//! #[derive(Debug, Clone)]
352//! enum Message {
353//!     WindowResized(Size),
354//! }
355//!
356//! pub fn main() -> iced::Result {
357//!     iced::application(new, update, view)
358//!         .subscription(subscription)
359//!         .run()
360//! }
361//!
362//! fn subscription(state: &State) -> Subscription<Message> {
363//!     window::resize_events().map(|(_id, size)| Message::WindowResized(size))
364//! }
365//! # fn new() -> State { State }
366//! # fn update(state: &mut State, message: Message) {}
367//! # fn view(state: &State) -> iced::Element<'_, Message> { iced::widget::text("").into() }
368//! ```
369//!
370//! A [`Subscription`] is [a _declarative_ builder of streams](Subscription#the-lifetime-of-a-subscription)
371//! that are not allowed to end on their own. Only the `subscription` function
372//! dictates the active subscriptions—just like `view` fully dictates the
373//! visible widgets of your user interface, at every moment.
374//!
375//! As with tasks, some modules expose convenient functions that build a [`Subscription`] for you—like
376//! [`time::every`] which can be used to listen to time, or [`keyboard::listen`] which will notify you
377//! of any keyboard events. But you can also create your own with [`Subscription::run`] and [`run_with`].
378//!
379//! [`run_with`]: Subscription::run_with
380//!
381//! ## Scaling Applications
382//! The `update`, `view`, and `Message` triplet composes very nicely.
383//!
384//! A common pattern is to leverage this composability to split an
385//! application into different screens:
386//!
387//! ```standalone_crate
388//! # mod contacts {
389//! #     use iced::{Element, Task};
390//! #     pub struct Contacts;
391//! #     impl Contacts {
392//! #         pub fn update(&mut self, message: Message) -> Action { unimplemented!() }
393//! #         pub fn view(&self) -> Element<Message> { unimplemented!() }
394//! #     }
395//! #     #[derive(Debug, Clone)]
396//! #     pub enum Message {}
397//! #     pub enum Action { None, Run(Task<Message>), Chat(()) }
398//! # }
399//! # mod conversation {
400//! #     use iced::{Element, Task};
401//! #     pub struct Conversation;
402//! #     impl Conversation {
403//! #         pub fn new(contact: ()) -> (Self, Task<Message>) { unimplemented!() }
404//! #         pub fn update(&mut self, message: Message) -> Task<Message> { unimplemented!() }
405//! #         pub fn view(&self) -> Element<Message> { unimplemented!() }
406//! #     }
407//! #     #[derive(Debug, Clone)]
408//! #     pub enum Message {}
409//! # }
410//! use contacts::Contacts;
411//! use conversation::Conversation;
412//!
413//! use iced::{Element, Task};
414//!
415//! struct State {
416//!     screen: Screen,
417//! }
418//!
419//! enum Screen {
420//!     Contacts(Contacts),
421//!     Conversation(Conversation),
422//! }
423//!
424//! enum Message {
425//!    Contacts(contacts::Message),
426//!    Conversation(conversation::Message)
427//! }
428//!
429//! fn update(state: &mut State, message: Message) -> Task<Message> {
430//!     match message {
431//!         Message::Contacts(message) => {
432//!             if let Screen::Contacts(contacts) = &mut state.screen {
433//!                 let action = contacts.update(message);
434//!
435//!                 match action {
436//!                     contacts::Action::None => Task::none(),
437//!                     contacts::Action::Run(task) => task.map(Message::Contacts),
438//!                     contacts::Action::Chat(contact) => {
439//!                         let (conversation, task) = Conversation::new(contact);
440//!
441//!                         state.screen = Screen::Conversation(conversation);
442//!
443//!                         task.map(Message::Conversation)
444//!                     }
445//!                  }
446//!             } else {
447//!                 Task::none()    
448//!             }
449//!         }
450//!         Message::Conversation(message) => {
451//!             if let Screen::Conversation(conversation) = &mut state.screen {
452//!                 conversation.update(message).map(Message::Conversation)
453//!             } else {
454//!                 Task::none()    
455//!             }
456//!         }
457//!     }
458//! }
459//!
460//! fn view(state: &State) -> Element<'_, Message> {
461//!     match &state.screen {
462//!         Screen::Contacts(contacts) => contacts.view().map(Message::Contacts),
463//!         Screen::Conversation(conversation) => conversation.view().map(Message::Conversation),
464//!     }
465//! }
466//! ```
467//!
468//! The `update` method of a screen can return an `Action` enum that can be leveraged by the parent to
469//! execute a task or transition to a completely different screen altogether. The variants of `Action` can
470//! have associated data. For instance, in the example above, the `Conversation` screen is created when
471//! `Contacts::update` returns an `Action::Chat` with the selected contact.
472//!
473//! Effectively, this approach lets you "tell a story" to connect different screens together in a type safe
474//! way.
475//!
476//! Furthermore, functor methods like [`Task::map`], [`Element::map`], and [`Subscription::map`] make composition
477//! seamless.
478#![doc(
479    html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/bdf0430880f5c29443f5f0a0ae4895866dfef4c6/docs/logo.svg"
480)]
481#![cfg_attr(docsrs, feature(doc_cfg))]
482use iced_widget::graphics;
483use iced_widget::renderer;
484use iced_winit as shell;
485use iced_winit::core;
486use iced_winit::program;
487use iced_winit::runtime;
488
489pub use iced_futures::futures;
490pub use iced_futures::stream;
491
492#[cfg(not(any(
493    target_arch = "wasm32",
494    feature = "thread-pool",
495    feature = "tokio",
496    feature = "smol"
497)))]
498compile_error!(
499    "No futures executor has been enabled! You must enable an \
500    executor feature.\n\
501    Available options: thread-pool, tokio, or smol."
502);
503
504#[cfg(all(
505    target_family = "unix",
506    not(target_os = "macos"),
507    not(feature = "wayland"),
508    not(feature = "x11"),
509))]
510compile_error!(
511    "No Unix display server backend has been enabled. You must enable a \
512    display server feature.\n\
513    Available options: x11, wayland."
514);
515
516#[cfg(feature = "highlighter")]
517pub use iced_highlighter as highlighter;
518
519#[cfg(feature = "wgpu")]
520pub use iced_renderer::wgpu::wgpu;
521
522mod error;
523
524pub mod application;
525pub mod daemon;
526pub mod time;
527pub mod window;
528
529#[cfg(feature = "advanced")]
530pub mod advanced;
531
532pub use crate::core::alignment;
533pub use crate::core::animation;
534pub use crate::core::border;
535pub use crate::core::color;
536pub use crate::core::gradient;
537pub use crate::core::padding;
538pub use crate::core::theme;
539pub use crate::core::{
540    Alignment, Animation, Background, Border, Color, ContentFit, Degrees, Function, Gradient,
541    Length, Never, Padding, Pixels, Point, Radians, Rectangle, Rotation, Settings, Shadow, Size,
542    Theme, Transformation, Vector, never,
543};
544pub use crate::program::Preset;
545pub use crate::program::message;
546pub use crate::runtime::exit;
547pub use iced_futures::Subscription;
548
549#[cfg(feature = "a11y")]
550#[cfg_attr(docsrs, doc(cfg(feature = "a11y")))]
551pub use crate::runtime::announce;
552
553pub use Alignment::Center;
554pub use Length::{Fill, FillPortion, Shrink};
555pub use alignment::Horizontal::{Left, Right};
556pub use alignment::Vertical::{Bottom, Top};
557
558pub mod debug {
559    //! Debug your applications.
560    pub use iced_debug::{Span, time, time_with};
561}
562
563pub mod task {
564    //! Create runtime tasks.
565    pub use crate::runtime::task::{Handle, Task};
566
567    #[cfg(feature = "sipper")]
568    pub use crate::runtime::task::{Never, Sipper, Straw, sipper, stream};
569}
570
571pub mod clipboard {
572    //! Access the clipboard.
573    pub use crate::core::clipboard::{Content, Error, Kind};
574    pub use crate::runtime::clipboard::{read, read_files, read_html, read_text, write};
575
576    #[cfg(feature = "image")]
577    pub use crate::core::clipboard::Image;
578
579    #[cfg(feature = "image")]
580    pub use crate::runtime::clipboard::read_image;
581}
582
583pub mod executor {
584    //! Choose your preferred executor to power your application.
585    pub use iced_futures::Executor;
586    pub use iced_futures::backend::default::Executor as Default;
587}
588
589pub mod font {
590    //! Load and use fonts.
591    pub use crate::core::font::*;
592    pub use crate::runtime::font::*;
593}
594
595pub mod event {
596    //! Handle events of a user interface.
597    pub use crate::core::event::{Event, Status};
598    pub use iced_futures::event::{listen, listen_raw, listen_with};
599}
600
601pub mod keyboard {
602    //! Listen and react to keyboard events.
603    pub use crate::core::keyboard::key;
604    pub use crate::core::keyboard::{Event, Key, Location, Modifiers};
605    pub use iced_futures::keyboard::listen;
606}
607
608pub mod mouse {
609    //! Listen and react to mouse events.
610    pub use crate::core::mouse::{Button, Cursor, Event, Interaction, ScrollDelta};
611}
612
613pub mod system {
614    //! Retrieve system information.
615    pub use crate::runtime::system::{theme, theme_changes};
616
617    #[cfg(feature = "sysinfo")]
618    pub use crate::runtime::system::{Information, information};
619}
620
621pub mod overlay {
622    //! Display interactive elements on top of other widgets.
623
624    /// A generic overlay.
625    ///
626    /// This is an alias of an [`overlay::Element`] with a default `Renderer`.
627    ///
628    /// [`overlay::Element`]: crate::core::overlay::Element
629    pub type Element<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> =
630        crate::core::overlay::Element<'a, Message, Theme, Renderer>;
631
632    pub use iced_widget::overlay::*;
633}
634
635pub mod touch {
636    //! Listen and react to touch events.
637    pub use crate::core::touch::{Event, Finger};
638}
639
640#[allow(hidden_glob_reexports)]
641pub mod widget {
642    //! Use the built-in widgets or create your own.
643    pub use iced_runtime::widget::*;
644    pub use iced_widget::*;
645
646    #[cfg(feature = "image")]
647    pub mod image {
648        //! Images display raster graphics in different formats (PNG, JPG, etc.).
649        pub use iced_runtime::image::{Allocation, Error, allocate};
650        pub use iced_widget::image::*;
651    }
652
653    // We hide the re-exported modules by `iced_widget`
654    mod core {}
655    mod graphics {}
656    mod renderer {}
657}
658
659pub use application::Application;
660pub use daemon::Daemon;
661pub use error::Error;
662pub use event::Event;
663pub use executor::Executor;
664pub use font::Font;
665pub use program::Program;
666pub use renderer::Renderer;
667pub use task::Task;
668pub use window::Window;
669
670#[doc(inline)]
671pub use application::application;
672#[doc(inline)]
673pub use daemon::daemon;
674
675/// A generic widget.
676///
677/// This is an alias of an `iced_native` element with a default `Renderer`.
678pub type Element<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> =
679    crate::core::Element<'a, Message, Theme, Renderer>;
680
681/// The result of running an iced program.
682pub type Result = std::result::Result<(), Error>;
683
684/// Runs a basic iced application with default [`Settings`] given its update
685/// and view logic.
686///
687/// This is equivalent to chaining [`application()`] with [`Application::run`].
688///
689/// # Example
690/// ```no_run,standalone_crate
691/// use iced::widget::{button, column, text, Column};
692///
693/// pub fn main() -> iced::Result {
694///     iced::run(update, view)
695/// }
696///
697/// #[derive(Debug, Clone)]
698/// enum Message {
699///     Increment,
700/// }
701///
702/// fn update(value: &mut u64, message: Message) {
703///     match message {
704///         Message::Increment => *value += 1,
705///     }
706/// }
707///
708/// fn view(value: &u64) -> Column<Message> {
709///     column![
710///         text(value),
711///         button("+").on_press(Message::Increment),
712///     ]
713/// }
714/// ```
715pub fn run<State, Message, Theme, Renderer>(
716    update: impl application::UpdateFn<State, Message> + 'static,
717    view: impl for<'a> application::ViewFn<'a, State, Message, Theme, Renderer> + 'static,
718) -> Result
719where
720    State: Default + 'static,
721    Message: Send + message::MaybeDebug + message::MaybeClone + 'static,
722    Theme: theme::Base + 'static,
723    Renderer: program::Renderer + 'static,
724{
725    application(State::default, update, view).run()
726}