| examples | ||
| src | ||
| .gitignore | ||
| .travis.yml | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
Iced
A simple GUI runtime for Rust, heavily inspired by Elm.
Iced is in a very early stage of development. Many basic features are still missing and there are probably many bugs. Feel free to contribute!
Features
- Simple, easy-to-use API
- Responsive, flexbox-based layouting
- Type-safe, reactive programming model
- Built-in widgets
- Custom widget support
- Renderer-agnostic runtime
Installation
Add iced as a dependency in your Cargo.toml:
iced = "0.1"
Iced moves fast and the master branch can contain breaking changes! If
you want to learn about a specific release, check out the release list.
Overview
Inspired by The Elm Architecture, Iced expects you to split user interfaces into four different concepts:
- State — the state of your application
- Messages — user interactions or meaningful events that you care about
- View logic — a way to display your state as widgets that may produce messages on user interaction
- Update logic — a way to react to messages and update your state
We can build something to see how this works! Let's say we want a simple counter that can be incremented and decremented using two buttons.
We start by modelling the state of our application:
use iced::button;
struct Counter {
// The counter value
value: i32,
// The local state of the two buttons
increment_button: button::State,
decrement_button: button::State,
}
Now that we have state, what are the user interactions we care about? The button presses! These are our messages:
#[derive(Debug, Clone, Copy)]
pub enum Message {
IncrementPressed,
DecrementPressed,
}
Next, let's put it all together in our view logic:
use iced::{Button, Column, Text};
use iced_wgpu::Renderer; // Iced is renderer-agnostic! We need to bring our own!
impl Counter {
fn view(&mut self) -> Column<Message, Renderer> {
// We use a column: a simple vertical layout
Column::new()
.push(
// The increment button. We tell it to produce an
// `IncrementPressed` message when pressed
Button::new(&mut self.increment_button, "+")
.on_press(Message::IncrementPressed),
)
.push(
// We show the value of the counter here
Text::new(&self.value.to_string()).size(50),
)
.push(
// The decrement button. We tell it to produce a
// `DecrementPressed` message when pressed
Button::new(&mut self.decrement_button, "-")
.on_press(Message::DecrementPressed),
)
}
}
Finally, we need to be able to react to the messages and mutate our state accordingly in our update logic:
impl Counter {
// ...
fn update(&mut self, message: Message) {
match message {
Message::IncrementPressed => {
self.value += 1;
}
Message::DecrementPressed => {
self.value -= 1;
}
}
}
}
And that's everything! We just wrote a whole user interface. Iced is now able to:
- Take the result of our view logic and build a user interface.
- Process events from our system and produce messages for our update logic.
- Draw the resulting user interface using our chosen renderer.
Browse the documentation and the examples to learn more!
Gallery
Implementation details
Iced was originally born as an attempt at bringing the simplicity of Elm and The Elm Architecture into Coffee, a 2D game engine I am working on.
Currently, Iced builds upon
Contributing / Feedback
If you want to contribute, you are more than welcome to be a part of the project! Check out the current issues if you want to find something to work on. Try to share you thoughts first! Feel free to open a new issue if you want to discuss new ideas.
Any kind of feedback is welcome! You can open an issue or, if you want to talk,
you can find me (and a bunch of awesome folks) over the #gui-and-ui channel in
the Rust Community Discord. I go by @lone_scientist there.