relm 0.14.6

Asynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust
Documentation
= Relm

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

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

image:https://img.shields.io/travis/antoyo/relm/master.svg[link="https://travis-ci.org/antoyo/relm"]
image:https://img.shields.io/appveyor/ci/antoyo/relm/master.svg[link="https://ci.appveyor.com/project/antoyo/relm"]
//image:https://img.shields.io/coveralls/antoyo/relm.svg[link="https://coveralls.io/github/antoyo/relm"]
image:https://img.shields.io/crates/v/relm.svg[link="https://crates.io/crates/relm"]
image:https://img.shields.io/badge/rust-documentation-blue.svg[link="https://docs.rs/relm/"]
image:https://img.shields.io/crates/d/relm.svg[link="https://crates.io/crates/relm"]
image:https://img.shields.io/gitter/room/relm-rs/Lobby.svg[link="https://gitter.im/relm-rs/Lobby"]
image:https://img.shields.io/crates/l/relm.svg[link="LICENSE"]

== Requirements

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

See http://gtk-rs.org/docs-src/requirements[this page] for information on how to install GTK+.

== Usage

First, add this to you `Cargo.toml`:

[source,toml]
----
gtk = "^0.3.0"
relm = "^0.11.0"
relm-derive = "^0.11.0"
----

Next, add this to your crate:

[source,rust]
----
extern crate gtk;
#[macro_use]
extern crate relm;
#[macro_use]
extern crate relm_derive;

use relm::{Relm, Widget};
----

Then, create your model:

[source,rust]
----
struct Model {
    // …
}
----

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

Create your message `enum`:

[source,rust]
----
#[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:

[source,rust]
----
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:

[source,rust]
----
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.
    // Futures and streams can be connected to send a message when a value is ready.
    fn update(&mut self, event: Msg) {
        match event {
            Msg::SomeEvent => {
                let future = create_future();
                relm.connect_exec_ignore_err(future, SomeEvent);
            },
            Msg::Quit => gtk::main_quit(),
        }
    }

    // The next method is optional.
    // Futures and streams can be connected when the `Widget` is created in the
    // `subscriptions()` method.
    // fn subscriptions(&mut self, relm: &Relm<Self>) {
    //     let stream = Interval::new(Duration::from_secs(1));
    //     relm.connect_exec_ignore_err(stream, Tick);
    // }
}

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: window,
        }
    }
}
----

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

[source,rust]
----
fn main() {
    Win::run(()).unwrap();
}
----

=== `#[widget]` attribute

For the nightly users, 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`.
 * Both traits can be implemented at once.

To be able to use this attribute, you need to add the `relm-attributes` crate in your `Cargo.toml`:

[source,toml]
----
relm-attributes = "^0.11.0"
----

and to add the following code:

[source,rust]
----
#![feature(proc_macro)]

extern crate relm_attributes;

use relm_attributes::widget;
----

Here is an example using this attribute:

[source,rust]
----
#[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 => 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 => Decrement,
                    label: "-",
                },
            },
            // Use a tuple when you want to both send a message and return a value to
            // the GTK+ callback.
            delete_event(_, _) => (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`.

[NOTE]
====
To benefit from better error messages, enable the following features:

 * relm/unstable
 * relm-attributes/unstable
 * relm-derive/unstable

To do so, add the following lines to your `Cargo.toml`:

[source,toml]
----
[features]
default = ["relm/unstable", "relm-attributes/unstable", "relm-derive/unstable"]
----
====

[NOTE]
====
It is possible to use this syntax from stable Rust.

To do so, you need to replace the following:

[source, rust]
----
#[widget]
impl Widget for Win {
}
----

by:

[source, rust]
----
#[widget]
relm_widget! {
    impl Widget for Win {
    }
}
----
====

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
[source,rust]
----
fn update(&mut self, event: Msg, model: &mut Model) {
    for _ in 0..100 {
        model.counter += 1;
    }
}
----
will generate this function:
[source,rust]
----
fn update(&mut self, event: Msg, model: &mut Model) {
    for _ in 0..100 {
        model.counter += 1;
        self.label1.set_text(&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
[source,rust]
----
fn update(&mut self, event: Msg, model: &mut Model) {
    model.text.push_str("Text");
}
----
will not work as expected.

Please use the following variation if needed.
[source,rust]
----
fn update(&mut self, event: Msg, model: &mut Model) {
    model.text += "Text";
}
----
====

For more information about how you can use relm, you can take a look at the https://github.com/antoyo/relm/tree/master/examples[examples].

== Projects using `relm`

 * https://github.com/sanpii/yellow-pitaya[Yellow Pitaya]
 * https://github.com/juchiast/gameoflife[Game of Life]
 * https://github.com/sebasmagri/rusty-sounds[Rusty Sounds]
 * https://github.com/etrombly/country_parser[Country Parser]
 * https://github.com/niklasf/rust-chessground[Chessground]
 * https://github.com/sanpii/effitask[Effitask]

If you want to add your project to this list, please https://github.com/antoyo/relm/pulls[create a pull request].