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

Related tags

GUI hacktoberfest
Overview

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.9.0"
relm = "^0.21.0"
relm-derive = "^0.21.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

Comments
  • compilation errors are reported on the

    compilation errors are reported on the "widget" annotation not at the correct location

    I'm not sure whether that one is in fact fixable, but it is quite annoying when I hit it (which is relatively often). I get compilation errors like that:

    error[E0282]: type annotations needed
       --> projectpad/src/widgets/server_item_list_item.rs:112:1
        |
    112 | #[widget]
        | ^^^^^^^^^ this method call resolves to `&T`
        |
        = note: type must be known at this point
    

    So the error is reported on the #[widget] annotation and not at the real location of the error. It can get very annoying, sometimes I had errors like "types don't match" (without any extra info) reported at this location :(

    But due to macro use i'm not sure whether it's fixable in relm. If you're not aware of this issue and need a small reproduction, I'll try to produce one.

    bug 
    opened by emmanueltouzery 23
  • libgtkflow with relm?

    libgtkflow with relm?

    https://github.com/grindhold/libgtkflow would be really nice to use with relm. How can I? I will do whatever work necessary but I don't know where to start.

    opened by lf94 19
  • Think about how to avoid having to write wrapper methods for gtk properties of relm widget

    Think about how to avoid having to write wrapper methods for gtk properties of relm widget

    For instance, the following:

    View {
        visible: self.model.visible,
    }
    

    requires to write a set_visible() method calling the set_visible() method from gtk.

    Might be possible by calling Widget::root().

    easy 
    opened by antoyo 14
  • "Clicked" on Label

    How would one detect clicks on Label? There's no connect_clicked and there isn't one in the EventBox either.

    Is there another widget I could use to detect the button press on a Label?

    opened by MGlolenstine 12
  • Question: how to update model from outside widget and update widget afterward?

    Question: how to update model from outside widget and update widget afterward?

    Hi, I'm trying to write an app with Relm and I think I understand well the different examples but they all show the case when the model is created by the widget.

    I have data read from the hard drive that I want to display and I'm wondering how to inject them in the widget and make the widget refresh

    Thank you for any insight :)

    question 
    opened by Geobert 12
  • refs #25: ability to set the widget style class through the view DSL

    refs #25: ability to set the widget style class through the view DSL

    I've wanted this feature in relm for a while, in my relm apps i have a bunch of get_style_context().add_class() calls in my init_view implementations.

    The new style_class attribute must enable to specify multiple style classes for a widget.. currently I made it that you must repeat the attribute multiple times in the DSL. We could also change it so that the user can type #[style_class=("destructive-action", "linked")]. Let me know if you'd prefer that.

    I also had to handle style classes specially in the Attributes struct, because with a Map of attributes, we couldn't list multiple times the style_class attribute. Again other approaches are possible, if you'd rather I do it another way, let me know!

    opened by emmanueltouzery 11
  • Using Hyper and Relm? (http examples broken)

    Using Hyper and Relm? (http examples broken)

    Is it possible to use Hyper with Relm? The example in relm-easyfibers appears to be outdated as the Relm.handle() method seems to be gone, apparently from moving from tokio to futures-glib. Is the a current working solution to Http futures from Relm? I need to be able to call some Http endpoints and update the Relm UI with the results.

    opened by iBelieve 9
  • multithread example fails with BorrowMutErr

    multithread example fails with BorrowMutErr

    I recently tried to write a gui that uses a background worker thread. It exploded on startup with a BorrowMutErr. The minimal example in relm also has exactly the same problem.

    thread 'main' panicked at 'already borrowed: BorrowMutError', libcore/result.rs:945:5
    stack backtrace:
       0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
                 at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
       1: std::sys_common::backtrace::print
                 at libstd/sys_common/backtrace.rs:71
                 at libstd/sys_common/backtrace.rs:59
       2: std::panicking::default_hook::{{closure}}
                 at libstd/panicking.rs:211
       3: std::panicking::default_hook
                 at libstd/panicking.rs:227
       4: std::panicking::rust_panic_with_hook
                 at libstd/panicking.rs:463
       5: std::panicking::begin_panic_fmt
                 at libstd/panicking.rs:350
       6: rust_begin_unwind
                 at libstd/panicking.rs:328
       7: core::panicking::panic_fmt
                 at libcore/panicking.rs:71
       8: core::result::unwrap_failed
                 at /checkout/src/libcore/macros.rs:26
       9: <core::result::Result<T, E>>::expect
                 at /checkout/src/libcore/result.rs:809
      10: <core::cell::RefCell<T>>::borrow_mut
                 at /checkout/src/libcore/cell.rs:816
      11: relm_core::<impl relm_core::source::SourceFuncs for core::cell::RefCell<relm_core::ChannelData<MSG>>>::prepare
                 at /home/eric/.cargo/registry/src/github.com-1ecc6299db9ec823/relm-core-0.14.4/src/lib.rs:110
      12: relm_core::source::prepare
                 at /home/eric/.cargo/registry/src/github.com-1ecc6299db9ec823/relm-core-0.14.4/src/source.rs:85
      13: g_main_context_prepare
      14: <unknown>
      15: g_main_loop_run
      16: gtk_main
      17: gtk::auto::functions::main
                 at /home/eric/.cargo/registry/src/github.com-1ecc6299db9ec823/gtk-0.4.1/src/auto/functions.rs:273
      18: relm::run
                 at /home/eric/.cargo/registry/src/github.com-1ecc6299db9ec823/relm-0.14.4/src/lib.rs:391
      19: relm::widget::Widget::run
                 at /home/eric/.cargo/registry/src/github.com-1ecc6299db9ec823/relm-0.14.4/src/widget.rs:63
      20: test_relm_multithread::main
                 at src/main.rs:99
      21: std::rt::lang_start::{{closure}}
                 at /checkout/src/libstd/rt.rs:74
      22: std::panicking::try::do_call
                 at libstd/rt.rs:59
                 at libstd/panicking.rs:310
      23: __rust_maybe_catch_panic
                 at libpanic_unwind/lib.rs:105
      24: std::rt::lang_start_internal
                 at libstd/panicking.rs:289
                 at libstd/panic.rs:374
                 at libstd/rt.rs:58
      25: std::rt::lang_start
                 at /checkout/src/libstd/rt.rs:74
      26: main
      27: __libc_start_main
      28: _start
    
    opened by estokes 8
  • Passing messages upwards

    Passing messages upwards

    I have been able to follow the examples with nested Relm widgets. I am building the views by passing data downwards, in that the parent model has all of the data, and creates sub-models/sub-widgets to accomplish more and more specific GUI tasks, though the highest parent still owns all the model data.

    However, not all of the messages are handled inside a widget. I'd like to pass messages upwards to their parents. Is it possible to generate a message inside a widget that propagates upwards to the parent? Then I can have the parent mutate the child data causing a view update.

    This data-down/actions-up pattern was very helpful in the Ember.js world for composing complex interfaces. If I'm way off base, and there's a more Rustic/Relmy way to approach this, let me know.

    question 
    opened by superlou 8
  • [RFC] Planning the transition to GTK4 (relm4)

    [RFC] Planning the transition to GTK4 (relm4)

    I'm currently working on an app using relm and GTK3 but I'd like to port it to GTK4 before finishing the UI. And since several other people expressed interest in GTK4 support (#256) I tried to hack into relm to get it working with the soon to be released gtk4-rs.

    Unfortunately there have been changes that prevent an easy transition to GTK4 for relm. Most importantly, the ContainerExt trait which is used a lot by relm doesn't exist any longer. This isn't an issue of gtk4-rs but rather GTK4 removed the Container type. Consequently this means that all layout containers have different interfaces now.

    The question is, what's the best way to integrate GTK4 into relm, especially regarding the view macro? I had the following ideas:

    1. Use a crate to implement an abstraction trait for all layout containers. That'd be quite a lot of work and even implementing a simple add_child() method isn't straightforward for some containers.

    2. Follow the new GTK4 design and embrace different container interfaces. Here's an example of how a view macro could look like with this approach:

    view! {
    #[name="main_window"]
    gtk::Window {
        // calls set_titlebar() on main_window
        titlebar:
            #[name="titlebar"]
            gtk::HeaderBar {
                // calls pack_end() on titlebar
                pack_end: gtk::Button {
                        clicked => Msg::Clicked,
                    },
                // calls pack_start() on titlebar
                pack_start:
                    #[name="hello_button"]
                    gtk::Button {
                        label: "Hello!",
                    },
    
                title_widget:
                    // calls set_title_widget() on titlebar
                    #[name="title"]
                    gtk::Box {
                        // calls append() on title
                        append:
                            #[name="title_label_1"]
                            gtk::Label {
                                label: "Title 1",
                            },
    
                        append:
                            #[name="title_label_2"]
                            gtk::Label {
                                label: "Title 2",
                            },
                    },
            },
    
        // calls set_child() on main_window
        child:
            #[name="app"]
            gtk::Grid {
                // calls attach() on app
                attach: 
                    (gtk::Label {
                        label: "Grid label",
                    }, 1, 1, 2, 1),
                /* ... other UI elements ... */
    
            },
    }
    }
    

    I prefer the second idea because it's more idiomatic GTK. Yet with my limited experience with proc macros and GTK I don't know whether it can be implemented like that and if there is a better solution. That's why I'd love to hear what you guys think about this :)

    P.S. Here's the link to the current documentation of gtk4-rs

    opened by AaronErhardt 7
  • 7GUI examples

    7GUI examples

    I have implemented the tasks of 7GUI in relm. These implementations could probably still be improved, but are working. I have not implemented every minor detail of the task (e.g. Editing a cell with right click instead of double click in the spreadsheet example), but in the React/MobX/Typescript version of the 7GUIs creator, such details might also be incorrect (e.g. Editing a cell with a single instead of a double click).

    I have tried documenting my code, mainly in the first examples, but these probably still have incorrect spelling or grammar and should be corrected.

    The only minor problem I still have is the directory structure. As I have put all tasks in a 7gui folder, these examples cannot be executed using cargo run --example in the relm-examples folder. They must be executed using cargo run in the folder of the example.

    opened by Schmiddiii 7
  • Nested view! macros use inner view as outer root

    Nested view! macros use inner view as outer root

    I have the following code:

    #[widget]
    impl Widget for MyWidget {
    	// ...
    	view! {
    		gtk::Box {
    			orientation: Orientation::Horizontal,
    			spacing: 10,
    
    			// ...
    
    			gtk::ToolButton {
    				hexpand: false,
    				clicked => Msg::Delete,
    				icon_widget: view! {
    					gtk::Image {
    						icon_name: Some("edit-delete"),
    						icon_size: IconSize::Button
    					}
    				}
    			}
    		}
    	}
    }
    

    At runtime, the entire widget is not rendered, and instead I see this message on the terminal:

    (myapp:104508): Gtk-WARNING **: 19:28:54.676: Attempting to add a widget with type GtkImage to a container of type GtkBox, but the widget is already inside a container of type GtkButton, please remove the widget from its existing container first.

    The macro outputs the following code, which I believe is wrong:

    impl Widget for MyWidget {
        // ...
        type Root = gtk::Image;
        fn root(&self) -> Self::Root {
            self.widgets.gtkimage1.clone()
        }
    }
    

    The widget is added inside a gtk::Box in another widget, but what I believe is happening is that only the image in the inner view! macro is being added, instead of the outer view! macro.

    opened by msrd0 0
  • Compilation error when using non-Copy types in messages

    Compilation error when using non-Copy types in messages

    Whenever I have a message type that is non-Copy, e.g.

    #[derive(Msg)]
    pub enum Msg {
        MyEvent(String)
    }
    

    Then I cannot use this message, or otherwise I get a compilation error:

    use my_widget::{MyWidget, Msg::MyEvent as MyWidgetMyEvent};
    
    view! {
        // ...
        MyWidget() {
            MyWidgetMyEvent(foo) => Msg::MyEvent(foo)
        }
        // ...
    }
    

    The error message is

    error[E0507]: cannot move out of `msg` as enum variant `MyEvent` which is behind a shared reference
       --> src/ui/mod.rs:XXX:Y
        |
    XXX |                 MyWidget() {
        |                 ^^^^^^^^ help: consider removing the `&`: `$message`
    ...
    XXX |                     MyWidgetMyEvent(foo) => Msg::MyEvent(foo)
        |                                     ---  data moved here
    

    This is impossible to fix in user code, using e.g. Msg::MyEvent(foo.clone()) or Msg::MyEvent((&*foo).into()) produces the exact same error message. The problem is within the macro-generated code that produces &MyWidgetMyEvent(foo). I believe this could be fixed by emiting &MyWidgetMyEvent(ref foo), but I haven't tested that.

    opened by msrd0 7
  • extract widget macro parsing from expansion

    extract widget macro parsing from expansion

    This commit separates the parsing step from the expansion step in the widget macro. It makes it clearer which items are required vs optional, and improves the error messages.

    opened by euclio 0
  • How does one use relm with a TextView?

    How does one use relm with a TextView?

    I just went through the mini tutorial in the README.md, and I really like this library to provide structure to my GTK-rs applications, but I need to use a gtk::TextView and when I tried to make it work with the view! macro it failed.

    Code:

    pub struct Model{
        file_contents: String,
        // … more things
    }
    
    //in view!
    gtk::TextView{
        text: {
            let text_buffer = TextBuffer::new(None);
            text_buffer.set_text(self.model.file_contents);
            Some(text_buffer)
        }
    }
    

    Error:

    error: expected identifier
      --> src/main.rs:60:25
       |
    60 |                         let text_buffer = TextBuffer::new(None);
       |                         ^^^
    

    Versions of my dependencies:

    [dependencies]
    relm = "0.21.0"
    relm-derive = "0.21.0"
    gtk = "0.9.2"
    

    MCVE (might have some other trivial errors and isn't complete (I wanted to make a trivial notepad clone to try out the library), but it demonstrates the issue):

    use std::path::PathBuf;
    use gtk::Orientation;
    use relm_derive::{widget, Msg};
    use relm::Widget;
    use gtk::prelude::*;
    
    #[derive(Msg)]
    pub enum Msg{
        OpenButton,
        OpenFile,
        SaveButton
    }
    
    pub struct Model{
        path: Option<PathBuf>,
        file_contents: String
    }
    
    #[widget]
    impl Widget for Win{
    
        fn model() -> Model{
            Model{
                path: None,
                file_contents: "".into()
            }
        }
    
        fn update(&mut self, event: Msg) {
            match event{
                Msg::OpenButton => {},
                Msg::OpenFile => {},
                Msg::SaveButton => {}
            }
        }
    
        view!{
            gtk::Window {
                gtk::Box {
                    orientation: Orientation::Vertical,
                    gtk::Box {
                        orientation: Orientation::Horizontal,
                        gtk::Button {
                            clicked => Msg::OpenButton,
                            label: "Open"
                        },
                        gtk::Button {
                            clicked => Msg::SaveButton,
                            label: "Save"
                        },
                        gtk::Label {
                            text: match &self.model.path {
                                Some(path) => &path.into_os_string().into_string().unwrap_or("Improper OS string in path".into()),
                                None => "File Not Saved".into()
                            }
                        }
                    },
                    gtk::TextView{
                        text: {
                            let text_buffer = TextBuffer::new(None);
                            text_buffer.set_text(self.model.file_contents);
                            Some(text_buffer)
                        }
                    }
                }
            }
        }
    
    }
    
    
    fn main() {
        Win::run(()).unwrap();
    }
    

    I assume that this means that the view! macro doesn't support blocks, but given this, I don't see how I can use a gtk::TextView.

    opened by john01dav 2
  • relm's event don't work when in a busy loop in the gtk GUI thread even if calling process_events

    relm's event don't work when in a busy loop in the gtk GUI thread even if calling process_events

    see reproduction here: https://github.com/emmanueltouzery/relm_process_events

    the code adds 100k rows in a gtk treeview. It does so through a busy loop in the gtk GUI thread. BUT it doesn't freeze the GUI thread because it regularly calls:

                    while gtk::events_pending() {
                        gtk::main_iteration();
                    }
    

    however that is not enough apparently to enable relm's event processing. It seems relm components' update() methods are called only after such a busy loop. In this repro, I listen to double clicks on grid rows. When there is such a double click, I make a println!()... this works during the busy loop:

    [src/main.rs:46] i = 65398 [src/main.rs:46] i = 65399 [src/main.rs:46] i = 65400 emitting relm event [src/main.rs:46] i = 65401 [src/main.rs:46] i = 65402

    however the update() itself, that should be called as a result of the stream().emit() being invoked, is not invoked until after the busy loop finishes:

        fn update(&mut self, event: Msg) {
            dbg!(event);
        }
    

    [src/main.rs:46] i = 99997 [src/main.rs:46] i = 99998 [src/main.rs:46] i = 99999 emitting relm event [src/main.rs:69] event = RowClicked emitting relm event [src/main.rs:69] event = RowClicked emitting relm event [src/main.rs:69] event = RowClicked

    opened by emmanueltouzery 1
Owner
null
A cross-platform GUI library for Rust, inspired by Elm

Iced A cross-platform GUI library for Rust focused on simplicity and type-safety. Inspired by Elm. Features Simple, easy-to-use, batteries-included AP

Héctor Ramón 17.5k Jan 2, 2023
A cross-platform GUI library for Rust, inspired by Elm

Iced A cross-platform GUI library for Rust focused on simplicity and type-safety. Inspired by Elm. Features Simple, easy-to-use, batteries-included AP

null 17.5k Dec 28, 2022
Simple GTK Rust Fuzzer which aims to test all available classes and functions in GTK.

Gtk Rust Fuzzer Simple GTK Rust Fuzzer which aims to test all available classes and functions in GTK. It finds bugs inside GTK functions, GTK exported

Rafał Mikrut 8 Nov 19, 2022
A GUI for NordVPN on Linux that maintains feature parity with the official clients, written with Rust and GTK.

Viking for NordVPN This project aims to provide a fully usable and feature-complete graphical interface for NordVPN on Linux. While it attempts to clo

Jacob Birkett 2 Oct 23, 2022
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.

libui: a portable GUI library for C This README is being written. Status It has come to my attention that I have not been particularly clear about how

Pietro Gagliardi 10.4k Dec 31, 2022
Highly customizable finder with high performance. Written in Rust and uses GTK

Findex Highly customizable finder with high performance. Written in Rust and uses GTK Installation Automatic Binary Clone from https://aur.archlinux.o

MD Gaziur Rahman Noor 442 Jan 1, 2023
GTK 4 front-end to ChatGPT completions written in Rust

ChatGPT GUI Building git clone [email protected]:teunissenstefan/chatgpt-gui.git cd chatgpt-gui cargo build --release Todo Connect insert_text to only al

Stefan Teunissen 6 Mar 12, 2023
A Rust library to parse Blueprint files and convert them into GTK UI files

?? gtk-ui-builder A Rust library to parse Blueprint files and convert them into GTK UI files Inspired by the Blueprint project Example 1 - blueprints

Observer KRypt0n_ 5 Oct 22, 2022
GUI based tool to sort and categorize images written in Rust

ImageSieve GUI based tool to sort out images based on similarity, categorize them according to their creation date and archive them in a target folder

Florian Fetz 67 Dec 14, 2022
Provides Rust bindings for GTK libraries

The gtk-rs organization aims to provide safe Rust binding over GObject-based libraries

null 431 Dec 30, 2022
Rust bindings and wrappers for GLib, GDK 3, GTK+ 3 and Cairo.

THIS REPOSITORY IS DEPRECATED SEE: https://github.com/rust-gnome rgtk Rust bindings and wrappers for GLib, GDK 3, GTK+ 3 and Cairo. Building rgtk expe

Jeremy Letang 124 Jul 10, 2022
Provides Rust bindings for GTK libraries

gtk3-rs The gtk-rs organization aims to provide safe Rust binding over GObject-based libraries. You can find more about it on https://gtk-rs.org. This

null 431 Dec 30, 2022
Graphical font editor (GTK + Rust)

gerb *gerb ʰ-: reconstructed Proto-Indo-European root, meaning to carve gerb: a WIP font editor in gtk3 and rust Introduction gerb is an experimental,

Manos Pitsidianakis 40 Jan 1, 2023
A powerful color picker and formatter, built with GTK and Rust

Eyedropper A powerful color picker and formatter. More screenshots Features Pick a Color Enter a color in Hex-Format Parse RGBA/ARGB Hex-Colors View c

Jonathan 108 Dec 24, 2022
Reactive components in rust, designed to make GTK more manageable

gflux gflux is a tiny experimental reactive component system for rust, designed to make GTK more manageable. gflux: is about 300 lines of code contain

Brian Vincent 3 Aug 20, 2023
A simple GUI version of the pH calibration tool written in egui, based on the eframe template.

caliphui A simple GUI version of the pH calibration tool written in egui, based on the eframe template. Usage Native binaries are provided under relea

Peter Dunne 0 Dec 29, 2021
An example of searching iBeacon using gtk-rs and btleplug.

Beacon Searcher Screenshot Compile & Run Install GTK 3 dev packages: macOS: $ brew install gtk+3 $ brew install gnome-icon-theme Debian / Ubuntu: $ s

Ling, Wei-Cheng 0 Dec 21, 2021
Test bed for gtk-rs-core experiments

Rust GObject Experiments class macro #[gobject::class(final)] mod obj { #[derive(Default)] pub struct MyObj { #[property(get, set)]

Jason Francis 2 May 28, 2022
An easy-to-use, 2D GUI library written entirely in Rust.

Conrod An easy-to-use, 2D GUI library written entirely in Rust. Guide What is Conrod? A Brief Summary Screenshots and Videos Feature Overview Availabl

PistonDevelopers 3.3k Jan 1, 2023