Giter VIP home page Giter VIP logo

relm's Introduction

Relm

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

Relm only works on nightly since it depends on the feature conservative_impl_trait.

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

master master relm rust documentation blue relm relm

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 you Cargo.toml:

relm = "0.5.0"

Next, add this to your crate:

extern crate gtk;
#[macro_use]
extern crate relm;
#[macro_use]
extern crate relm_derive;

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

Then, create your model:

#[derive(Clone)]
struct Model {
    // …
}

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

Create your message enum:

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

Messages are sent to both Widget::update and Widget::update_command 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):

struct Win {
    // …
    window: Window,
}

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

impl Widget for Win {
    type Model = Model;
    type Msg = Msg;
    type Root = Window;

    // Return the initial model.
    fn model() -> Model {
        Model {
        }
    }

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

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

    // Create the widgets.
    fn view(relm: &RemoteRelm<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(_, _) (Some(Quit), Inhibit(false)));
        // There is also a `connect!()` macro for GTK+ events that does not need a
        // value to be returned in the callback.
        window.show_all();
        Win {
            window: window,
        }
    }

    // The next methods are optional.

    // Futures and streams can be connected to send a message when a value is ready.
    // However, since the tokio event loop runs in another thread, they cannot be
    // connected in the `update` function which is ran in the main thread.
    // Thus, they must be added in the `update_command()` method which is ran in
    // the tokio thread.
    // fn update_command(relm: &Relm<Msg>, event: Msg, model: &mut Model) {
    //     match event {
    //         SomeEvent => {
    //             let future = create_future();
    //             relm.connect_exec_ignore_err(future, SomeEvent);
    //         },
    //     }
    // }

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

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

fn main() {
    relm::run::<Win>().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 container(), type Msg, type Model 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.

Here is an example using this attribute:

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

    fn update(&mut self, event: Msg, model: &mut Model) {
        match event {
            // A call to self.label1.set_text() is automatically inserted by the
            // attribute every time the model.counter attribute is updated.
            Decrement => model.counter -= 1,
            Increment => model.counter += 1,
            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: &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 container() and the types Model, Msg and Container. You can still provide the method and the 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, model: &mut Model) {
    for _ in 0..100 {
        model.counter += 1;
    }
}

will generate this function:

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

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.

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 examples.

relm's People

Contributors

antoyo avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.