iced: Elm for Rust
A typed, message-driven toolkit that COSMIC is built on.
iced follows the Elm architecture. Your program is a state type, a Message enum, an update function that applies messages, and a view function that builds widgets from state. Widgets never change state; they emit messages. That makes every state change explicit and easy to follow.
use book_error::Result;
use iced::widget::{button, column, text, Column};
#[derive(Default)]
struct Counter {
value: i64,
}
#[derive(Debug, Clone, Copy)]
enum Message {
Increment,
Decrement,
}
impl Counter {
// The Elm loop: a message comes in, state changes...
fn update(&mut self, message: Message) {
match message {
Message::Increment => self.value += 1,
Message::Decrement => self.value -= 1,
}
}
// ...and the view is rebuilt from state. Widgets emit messages, never mutate.
fn view(&self) -> Column<'_, Message> {
column![
button("+").on_press(Message::Increment),
text(self.value).size(40),
button("-").on_press(Message::Decrement),
]
}
}
fn main() -> Result<()> {
iced::run(Counter::update, Counter::view)?;
Ok(())
} Things that happen outside the UI (timers, sockets, file watchers) arrive as a subscription that turns events into ordinary messages. In iced 0.14 the time::every helper needs an async runtime feature enabled, which is tokio in this project's manifest.
use book_error::Result;
use iced::time::{self, Duration};
use iced::widget::text;
use iced::{Element, Subscription};
struct Clock {
ticks: u64,
}
#[derive(Debug, Clone)]
enum Message {
Tick,
}
impl Clock {
fn update(&mut self, _message: Message) {
self.ticks += 1;
}
fn view(&self) -> Element<'_, Message> {
text(format!("{} seconds", self.ticks)).into()
}
// Anything that happens outside the UI (timers, sockets, file watchers)
// arrives as a Subscription that produces ordinary Messages.
fn subscription(&self) -> Subscription<Message> {
time::every(Duration::from_secs(1)).map(|_| Message::Tick)
}
}
fn main() -> Result<()> {
iced::application(|| Clock { ticks: 0 }, Clock::update, Clock::view)
.subscription(Clock::subscription)
.run()?;
Ok(())
} Underneath, the lockfile shows the stack iced assembles: iced_winit for windows, iced_wgpu for GPU drawing with iced_tiny_skia as a software fallback, and cosmic-text for text. System76's COSMIC desktop is built on a fork of iced. Version 0.14 arrived more than a year after 0.13, and iced has no AccessKit integration yet, unlike egui and Slint.