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