Skip to main content

iced/
lib.rs

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