• Stars
    star
    2,329
  • Rank 19,770 (Top 0.4 %)
  • Language
    Rust
  • License
    MIT License
  • Created almost 8 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust

Relm

Asynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust.

This library is in beta stage: it has not been thoroughly tested and its API may change at any time.

CI Relm Tutorial blueviolet relm rust documentation blue relm relm:matrix relm Donate Patreon orange

Requirements

Since relm is based on GTK+, you need this library on your system in order to use it.

See this page for information on how to install GTK+.

Usage

First, add this to your Cargo.toml:

gtk = "^0.16.0"
relm = "^0.24.0"
relm-derive = "^0.24.0"

Next, add this to your crate:

use relm::{connect, Relm, Update, Widget};
use gtk::prelude::*;
use gtk::{Window, Inhibit, WindowType};
use relm_derive::Msg;

Then, create your model:

struct Model {
    // …
}

The model contains the data related to a Widget. It may be updated by the Widget::update function.

Create your message enum:

#[derive(Msg)]
enum Msg {
    // …
    Quit,
}

Messages are sent to Widget::update to indicate that an event happened. The model can be updated when an event is received.

Create a struct which represents a Widget which contains the GTK+ widgets (in this case, the main window of the application) and the model:

struct Win {
    // …
    model: Model,
    window: Window,
}

To make this struct a relm Widget that can be shown by the library, implement the Update and Widget traits:

impl Update for Win {
    // Specify the model used for this widget.
    type Model = Model;
    // Specify the model parameter used to init the model.
    type ModelParam = ();
    // Specify the type of the messages sent to the update function.
    type Msg = Msg;

    // Return the initial model.
    fn model(_: &Relm<Self>, _: ()) -> Model {
        Model {
        }
    }

    // The model may be updated when a message is received.
    // Widgets may also be updated in this function.
    fn update(&mut self, event: Msg) {
        match event {
            Msg::Quit => gtk::main_quit(),
        }
    }
}

impl Widget for Win {
    // Specify the type of the root widget.
    type Root = Window;

    // Return the root widget.
    fn root(&self) -> Self::Root {
        self.window.clone()
    }

    // Create the widgets.
    fn view(relm: &Relm<Self>, model: Self::Model) -> Self {
        // GTK+ widgets are used normally within a `Widget`.
        let window = Window::new(WindowType::Toplevel);

        // Connect the signal `delete_event` to send the `Quit` message.
        connect!(relm, window, connect_delete_event(_, _), return (Some(Msg::Quit), Inhibit(false)));
        // There is also a `connect!()` macro for GTK+ events that do not need a
        // value to be returned in the callback.

        window.show_all();

        Win {
            model,
            window,
        }
    }
}

Finally, show this Widget by calling Win::run():

fn main() {
    Win::run(()).unwrap();
}

#[widget] attribute

A #[widget] attribute is provided to simplify the creation of a widget.

This attribute does the following:

  • Provide a view! macro to create the widget with a declarative syntax.

  • Automatically create the fn root(), type Msg, type Model, type ModelParam and type Root items.

  • Automatically insert the call to Widget::set_property() in the update() function when assigning to an attribute of the model.

  • Automatically create the Widget struct.

  • Update and Widget traits can be implemented at once.

To use this attribute, add the following code:

use relm_derive::widget;

Here is an example using this attribute:

#[derive(Msg)]
pub enum Msg {
    Decrement,
    Increment,
    Quit,
}

pub struct Model {
    counter: u32,
}

#[widget]
impl Widget for Win {
    fn model() -> Model {
        Model {
            counter: 0,
        }
    }

    fn update(&mut self, event: Msg) {
        match event {
            // A call to self.label1.set_text() is automatically inserted by the
            // attribute every time the model.counter attribute is updated.
            Msg::Decrement => self.model.counter -= 1,
            Msg::Increment => self.model.counter += 1,
            Msg::Quit => gtk::main_quit(),
        }
    }

    view! {
        gtk::Window {
            gtk::Box {
                orientation: Vertical,
                gtk::Button {
                    // By default, an event with one paramater is assumed.
                    clicked => Msg::Increment,
                    // Hence, the previous line is equivalent to:
                    // clicked(_) => Increment,
                    label: "+",
                },
                gtk::Label {
                    // Bind the text property of this Label to the counter attribute
                    // of the model.
                    // Every time the counter attribute is updated, the text property
                    // will be updated too.
                    text: &self.model.counter.to_string(),
                },
                gtk::Button {
                    clicked => Msg::Decrement,
                    label: "-",
                },
            },
            // Use a tuple when you want to both send a message and return a value to
            // the GTK+ callback.
            delete_event(_, _) => (Msg::Quit, Inhibit(false)),
        }
    }
}
Note
The struct Win is now automatically created by the attribute, as are the function root() and the associated types Model, ModelParam, Msg and Container. You can still provide the method and the associated types if needed, but you cannot create the struct.
Warning
The #[widget] makes the generated struct public: hence, the corresponding model and message types must be public too.
Warning

Your program might be slower when using this attribute because the code generation is simple. For instance, the following code

fn update(&mut self, event: Msg) {
    for _ in 0..100 {
        self.model.counter += 1;
    }
}

will generate this function:

fn update(&mut self, event: Msg) {
    for _ in 0..100 {
        self.model.counter += 1;
        self.label1.set_text(&self.model.counter.to_string());
    }
}
Warning

Also, the set_property() calls are currently only inserted when assigning to an attribute of the model. For instance, the following code

fn update(&mut self, event: Msg) {
    self.model.text.push_str("Text");
}

will not work as expected.

Please use the following variation if needed.

fn update(&mut self, event: Msg) {
    self.model.text += "Text";
}

For more information about how you can use relm, you can take a look at the examples.

Donations

If you appreciate this project and want new features to be implemented, please support me on Patreon.

become a patron button

More Repositories

1

tql

TQL is a compile-time Rust ORM
Rust
378
star
2

titanium

A keyboard-driven web browser written in Rust
Rust
211
star
3

tiger-rs

Rust implementation of the projects from the book Modern Compiler Implementation in ML
Rust
126
star
4

vim-licenses

Vim Plugin that Provides Commands to Add Licenses at the Top of the Buffer
Vim Script
54
star
5

mg

Minimal UI library based on relm (GTK+), written in Rust.
Rust
39
star
6

uncbv

CBV archive extractor written in Rust
Rust
32
star
7

asciidoctor-rs

Parser for asciidoctor written in Rust
Rust
24
star
8

servo-gtk

Servo binding for gtk-rs
Rust
22
star
9

dbus-macros-rs

Convenient macros to use the dbus crate
Rust
11
star
10

libgccjit-patches

Patches awaiting review for libgccjit
8
star
11

vte-rs

VTE bindings and wrappers for Rust
Rust
7
star
12

secret-rs

Rust binding for libsecret
Rust
5
star
13

ces.js

Cascading Event Sheet
JavaScript
4
star
14

futures-glib-rs

Rust
4
star
15

huffman-rs

Huffman is a library to decode huffman-encoded data
Rust
3
star
16

llvm-sys.rs

Rust bindings to LLVM's C API
Rust
3
star
17

vte-sys-rs

Vte FFI crate for Rust
Rust
3
star
18

des-rs

Parallel Data Encryption Standard (DES) algorithm implemented in Rust
Rust
3
star
19

gdbus-rs

GDBus bindings and wrappers for Rust
Rust
3
star
20

.dotfiles

Shell
2
star
21

rlvm

Rust wrapper for LLVM
Rust
2
star
22

async-io-rs

Rust
2
star
23

iold

Async IO library for Rust
Rust
2
star
24

mg-settings

Parse config files.
Rust
2
star
25

libgepub-rs

Rust binding for libgepub
Rust
2
star
26

password-store-rs

gopass Rust wrapper library.
Rust
2
star
27

gtksourceview-rs

GtkSourceView bindings and wrappers for Rust
Rust
2
star
28

uncbv-cpp

CBV Archive Extractor
C++
2
star
29

cef-rs

Rust
1
star
30

down-for-everyone-or-just-me

Firefox add-on to check wether a website is down or not when Firefox cannot load a page
JavaScript
1
star
31

rterm

Minimalist terminal written in Rust
Rust
1
star
32

ocjit

OCaml binding to libjit
OCaml
1
star
33

rustystage

CLI management software to manage music from a Sony Walkman (alternative to SonicStage)
Rust
1
star
34

statusbar

My i3 status bar written in Rust
Rust
1
star
35

fnf

CSS
1
star
36

c--

An interpreter for a subset of the C programming language written in OCaml
OCaml
1
star
37

lock-free-queue

Rust
1
star