Expand description
iced is a cross-platform GUI library focused on simplicity and type-safety. Inspired by Elm.
§Disclaimer
iced is experimental software. If you expect the documentation to hold your hand as you learn the ropes, you are in for a frustrating experience.
The library leverages Rust to its full extent: ownership, borrowing, lifetimes, futures, streams, first-class functions, trait bounds, closures, and more. This documentation is not meant to teach you any of these. Far from it, it will assume you have mastered all of them.
Furthermore—just like Rust—iced is very unforgiving. It will not let you easily cut corners. The type signatures alone can be used to learn how to use most of the library. Everything is connected.
Therefore, iced is easy to learn for advanced Rust programmers; but plenty of patient beginners have learned it and had a good time with it. Since it leverages a lot of what Rust has to offer in a type-safe way, it can be a great way to discover Rust itself.
If you don’t like the sound of that, you expect to be spoonfed, or you feel frustrated and struggle to use the library; then I recommend you to wait patiently until the book is finished.
§The Pocket Guide
Start by calling run:
pub fn main() -> iced::Result {
iced::run(update, view)
}Define an update function to change your state:
fn update(counter: &mut u64, message: Message) {
match message {
Message::Increment => *counter += 1,
}
}Define a view function to display your state:
use iced::widget::{button, text};
use iced::Element;
fn view(counter: &u64) -> Element<'_, Message> {
button(text(counter)).on_press(Message::Increment).into()
}And create a Message enum to connect view and update together:
#[derive(Debug, Clone)]
enum Message {
Increment,
}§Custom State
You can define your own struct for your state:
#[derive(Default)]
struct Counter {
value: u64,
}But you have to change update and view accordingly:
fn update(counter: &mut Counter, message: Message) {
match message {
Message::Increment => counter.value += 1,
}
}
fn view(counter: &Counter) -> Element<'_, Message> {
button(text(counter.value)).on_press(Message::Increment).into()
}§Widgets and Elements
The view function must return an Element. An Element is just a generic widget.
The widget module contains a bunch of functions to help you build
and use widgets.
Widgets are configured using the builder pattern:
use iced::widget::{button, column, text};
use iced::Element;
fn view(counter: &Counter) -> Element<'_, Message> {
column![
text(counter.value).size(20),
button("Increment").on_press(Message::Increment),
]
.spacing(10)
.into()
}A widget can be turned into an Element by calling into.
Widgets and elements are generic over the message type they produce. The
Element returned by view must have the same Message type as
your update.
§Layout
There is no unified layout system in iced. Instead, each widget implements its own layout strategy.
Building your layout will often consist in using a combination of rows, columns, and containers:
use iced::widget::{column, container, row};
use iced::{Fill, Element};
fn view(state: &State) -> Element<'_, Message> {
container(
column![
"Top",
row!["Left", "Right"].spacing(10),
"Bottom"
]
.spacing(10)
)
.padding(10)
.center_x(Fill)
.center_y(Fill)
.into()
}Rows and columns lay out their children horizontally and vertically, respectively. Spacing can be easily added between elements.
Containers position or align a single widget inside their bounds.
§Sizing
The width and height of widgets can generally be defined using a Length.
Fillwill make the widget take all the available space in a given axis.Shrinkwill make the widget use its intrinsic size.
Most widgets use a Shrink sizing strategy by default, but will inherit
a Fill strategy from their children.
A fixed numeric Length in Pixels can also be used:
use iced::widget::container;
use iced::Element;
fn view(state: &State) -> Element<'_, Message> {
container("I am 300px tall!").height(300).into()
}§Theming
The default Theme of an application can be changed by defining a theme
function and leveraging the Application builder, instead of directly
calling run:
use iced::Theme;
pub fn main() -> iced::Result {
iced::application(new, update, view)
.theme(theme)
.run()
}
fn new() -> State {
// ...
}
fn theme(state: &State) -> Theme {
Theme::TokyoNight
}The theme function takes the current state of the application, allowing the
returned Theme to be completely dynamic—just like view.
There are a bunch of built-in Theme variants at your disposal, but you can
also create your own.
§Styling
As with layout, iced does not have a unified styling system. However, all of the built-in widgets follow the same styling approach.
The appearance of a widget can be changed by calling its style method:
use iced::widget::container;
use iced::Element;
fn view(state: &State) -> Element<'_, Message> {
container("I am a rounded box!").style(container::rounded_box).into()
}The style method of a widget takes a closure that, given the current active
Theme, returns the widget style:
use iced::widget::button;
use iced::{Element, Theme};
fn view(state: &State) -> Element<'_, Message> {
button("I am a styled button!").style(|theme: &Theme, status| {
let palette = theme.extended_palette();
match status {
button::Status::Active => {
button::Style::default()
.with_background(palette.success.strong.color)
}
_ => button::primary(theme, status),
}
})
.into()
}Widgets that can be in multiple different states will also provide the closure
with some Status, allowing you to use a different style for each state.
You can extract the Palette colors of a Theme with the palette or
extended_palette methods.
Most widgets provide styling functions for your convenience in their respective modules;
like container::rounded_box, button::primary, or text::danger.
§Concurrent Tasks
The update function can optionally return a Task.
A Task can be leveraged to perform asynchronous work, like running a
future or a stream:
use iced::Task;
struct State {
weather: Option<Weather>,
}
enum Message {
FetchWeather,
WeatherFetched(Weather),
}
fn update(state: &mut State, message: Message) -> Task<Message> {
match message {
Message::FetchWeather => Task::perform(
fetch_weather(),
Message::WeatherFetched,
),
Message::WeatherFetched(weather) => {
state.weather = Some(weather);
Task::none()
}
}
}
async fn fetch_weather() -> Weather {
// ...
}Tasks can also be used to interact with the iced runtime. Some modules expose functions that create tasks for different purposes—like changing window settings, focusing a widget, or querying its visible bounds.
Like futures and streams, tasks expose a monadic interface—but they can also be mapped, chained, batched, canceled, and more.
§Passive Subscriptions
Applications can subscribe to passive sources of data—like time ticks or runtime events.
You will need to define a subscription function and use the Application builder:
use iced::window;
use iced::{Size, Subscription};
#[derive(Debug, Clone)]
enum Message {
WindowResized(Size),
}
pub fn main() -> iced::Result {
iced::application(new, update, view)
.subscription(subscription)
.run()
}
fn subscription(state: &State) -> Subscription<Message> {
window::resize_events().map(|(_id, size)| Message::WindowResized(size))
}A Subscription is a declarative builder of streams
that are not allowed to end on their own. Only the subscription function
dictates the active subscriptions—just like view fully dictates the
visible widgets of your user interface, at every moment.
As with tasks, some modules expose convenient functions that build a Subscription for you—like
time::every which can be used to listen to time, or keyboard::on_key_press which will notify you
of any key presses. But you can also create your own with Subscription::run and run_with.
§Scaling Applications
The update, view, and Message triplet composes very nicely.
A common pattern is to leverage this composability to split an application into different screens:
use contacts::Contacts;
use conversation::Conversation;
use iced::{Element, Task};
struct State {
screen: Screen,
}
enum Screen {
Contacts(Contacts),
Conversation(Conversation),
}
enum Message {
Contacts(contacts::Message),
Conversation(conversation::Message)
}
fn update(state: &mut State, message: Message) -> Task<Message> {
match message {
Message::Contacts(message) => {
if let Screen::Contacts(contacts) = &mut state.screen {
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()
}
}
Message::Conversation(message) => {
if let Screen::Conversation(conversation) = &mut state.screen {
conversation.update(message).map(Message::Conversation)
} else {
Task::none()
}
}
}
}
fn view(state: &State) -> Element<'_, Message> {
match &state.screen {
Screen::Contacts(contacts) => contacts.view().map(Message::Contacts),
Screen::Conversation(conversation) => conversation.view().map(Message::Conversation),
}
}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.
Re-exports§
pub use application::Application;pub use daemon::Daemon;pub use iced_futures::futures;pub use iced_highlighter as highlighter;highlighterpub use iced_renderer::wgpu::wgpu;wgpupub use Alignment::Center;pub use Length::Fill;pub use Length::FillPortion;pub use Length::Shrink;pub use alignment::Horizontal::Left;pub use alignment::Horizontal::Right;pub use alignment::Vertical::Bottom;pub use alignment::Vertical::Top;
Modules§
- advanced
advanced - Leverage advanced concepts like custom widgets.
- alignment
- Align and position widgets.
- animation
- Animate your applications.
- application
- Create and run iced applications step by step.
- border
- Draw lines around containers.
- clipboard
- Access the clipboard.
- daemon
- Create and run daemons that run in the background.
- debug
- Debug your applications.
- event
- Handle events of a user interface.
- executor
- Choose your preferred executor to power your application.
- font
- Load and use fonts.
- gradient
- Colors that transition progressively.
- keyboard
- Listen and react to keyboard events.
- message
- Traits for the message type of a
Program. - mouse
- Listen and react to mouse events.
- overlay
- Display interactive elements on top of other widgets.
- padding
- Space stuff around the perimeter.
- stream
- Create asynchronous streams of data.
- system
- Retrieve system information.
- task
- Create runtime tasks.
- theme
- Use the built-in theme and styles.
- time
- Listen and react to time.
- touch
- Listen and react to touch events.
- widget
- Use the built-in widgets or create your own.
- window
- Configure the window of your application in native platforms.
Macros§
Structs§
- Animation
- The animation of some particular state.
- Border
- A border.
- Color
- A color in the
sRGBcolor space. - Degrees
- Degrees
- Font
- A font.
- Padding
- An amount of space to pad for each side of a box
- Pixels
- An amount of logical pixels.
- Point
- A 2D point.
- Preset
- A specific boot strategy for a
Program. - Radians
- Radians
- Rectangle
- An axis-aligned rectangle.
- Settings
- The settings of an iced program.
- Shadow
- A shadow.
- Size
- An amount of space in 2 dimensions.
- Subscription
- A request to listen to external events.
- Task
- A set of concurrent actions to be performed by the iced runtime.
- Transformation
- A 2D transformation matrix.
- Vector
- A 2D vector.
Enums§
- Alignment
- Alignment on the axis of a container.
- Background
- The background of some element.
- Content
Fit - The strategy used to fit the contents of a widget to its bounding box.
- Error
- An error that occurred while running an application.
- Event
- A user interface event.
- Gradient
- A fill which transitions colors progressively along a direction, either linearly, radially (TBD), or conically (TBD).
- Length
- The strategy used to fill space in a specific dimension.
- Rotation
- The strategy used to rotate the content.
- Theme
- A built-in theme.
Traits§
- Executor
- A type that can run futures.
- Function
- A trait extension for binary functions (
Fn(A, B) -> O). - Program
- An interactive, native, cross-platform, multi-windowed application.
Functions§
- application
- Creates an iced
Applicationgiven its boot, update, and view logic. - daemon
- Creates an iced
Daemongiven its boot, update, and view logic. - exit
- Creates a
Taskthat exits the iced runtime. - never
- A function that can never be called.
- run
- Runs a basic iced application with default
Settingsgiven its update and view logic.