Relm4

CI Matrix Relm4 on crates.io Relm4 docs Relm4 book Minimum Rust version 1.54

An idiomatic GUI library inspired by Elm and based on gtk4-rs. Relm4 is a new version of relm that's built from scratch and is compatible with GTK4 and libadwaita.

Why Relm4

We believe that GUI development should be easy, productive and delightful.
The gtk4-rs crate already provides everything you need to write modern, beautiful and cross-platform applications. Built on top of this foundation, Relm4 makes developing more idiomatic, simpler and faster and enables you to become productive in just a few hours.

Our goals

Documentation

Dependencies

Relm4 depends on GTK4: How to install GTK4.

Ecosystem

Relm4 has two crates that extend the core functionality:

Add this to your Cargo.toml:

toml gtk = { version = "0.3", package = "gtk4" } relm4 = "0.2" relm4-macros = "0.2" relm4-components = "0.2"

Features

The relm4 crate has two feature flags:

Examples

Several example applications are available at relm4-examples/.

📸 Screenshots from the example apps

A simple counter app

Simple app screenshot light Simple app screenshot dark

```rust use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt}; use relm4::{send, AppUpdate, Model, RelmApp, Sender, WidgetPlus, Widgets};

[derive(Default)]

struct AppModel { counter: u8, }

enum AppMsg { Increment, Decrement, }

impl Model for AppModel { type Msg = AppMsg; type Widgets = AppWidgets; type Components = (); }

impl AppUpdate for AppModel { fn update(&mut self, msg: AppMsg, components: &(), _sender: Sender) -> bool { match msg { AppMsg::Increment => { self.counter = self.counter.wrappingadd(1); } AppMsg::Decrement => { self.counter = self.counter.wrapping_sub(1); } } true } }

[relm4_macros::widget]

impl Widgetstitle: Some("Simple app"), setdefaultwidth: 300, setdefaultheight: 100, setchild = Some(&gtk::Box) { setorientation: gtk::Orientation::Vertical, setmarginall: 5, setspacing: 5,

            append = &gtk::Button {
                set_label: "Increment",
                connect_clicked(sender) => move |_| {
                    send!(sender, AppMsg::Increment);
                },
            },
            append = &gtk::Button {
                set_label: "Decrement",
                connect_clicked(sender) => move |_| {
                    send!(sender, AppMsg::Decrement);
                },
            },
            append = &gtk::Label {
                set_margin_all: 5,
                set_label: watch! { &format!("Counter: {}", model.counter) },
            }
        },
    }
}

}

fn main() { let model = AppModel::default(); let app = RelmApp::new(model); app.run(); }

```

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Feedback and contributions are highly appreciated!