{"id":13439649,"url":"https://github.com/antoyo/relm","last_synced_at":"2025-05-14T01:03:05.770Z","repository":{"id":17628759,"uuid":"81523566","full_name":"antoyo/relm","owner":"antoyo","description":"Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust","archived":false,"fork":false,"pushed_at":"2024-04-19T11:46:46.000Z","size":1497,"stargazers_count":2451,"open_issues_count":57,"forks_count":80,"subscribers_count":39,"default_branch":"master","last_synced_at":"2025-04-10T03:44:59.477Z","etag":null,"topics":["hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antoyo.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"antoyo","patreon":"antoyo"}},"created_at":"2017-02-10T03:45:15.000Z","updated_at":"2025-04-09T08:47:25.000Z","dependencies_parsed_at":"2024-04-19T12:47:07.530Z","dependency_job_id":"3e668bb7-9722-4640-acdd-8e8033baef43","html_url":"https://github.com/antoyo/relm","commit_stats":{"total_commits":827,"total_committers":43,"mean_commits":"19.232558139534884","dds":"0.16444981862152352","last_synced_commit":"585b202d3179f19271a85e7703ec977d22a502a8"},"previous_names":[],"tags_count":247,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoyo%2Frelm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoyo%2Frelm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoyo%2Frelm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antoyo%2Frelm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antoyo","download_url":"https://codeload.github.com/antoyo/relm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253486837,"owners_count":21916142,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest"],"created_at":"2024-07-31T03:01:15.927Z","updated_at":"2025-05-14T01:03:05.726Z","avatar_url":"https://github.com/antoyo.png","language":"Rust","funding_links":["https://github.com/sponsors/antoyo","https://patreon.com/antoyo","https://www.patreon.com/antoyo"],"categories":["Libraries","Rust","库 Libraries","库","hacktoberfest"],"sub_categories":["GUI","GUI GUI","图形用户界面 GUI"],"readme":"= Relm\n\nAsynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust.\n\n*This library is in beta stage: it has not been thoroughly tested and its API may change at any time.*\n\nimage:https://img.shields.io/github/workflow/status/antoyo/relm/CI[link=\"https://github.com/antoyo/relm/actions\"]\nimage:https://img.shields.io/badge/Relm-Tutorial-blueviolet[link=\"https://relm.antoyo.xyz/documentation/tutorial/\"]\nimage:https://img.shields.io/crates/v/relm.svg[link=\"https://crates.io/crates/relm\"]\nimage:https://img.shields.io/badge/rust-documentation-blue.svg[link=\"https://docs.rs/relm/\"]\nimage:https://img.shields.io/crates/d/relm.svg[link=\"https://crates.io/crates/relm\"]\nimage:https://img.shields.io/matrix/relm:matrix.org?logo=matrix[link=\"https://matrix.to/#/#relm:matrix.org?via=matrix.org\"]\nimage:https://img.shields.io/crates/l/relm.svg[link=\"LICENSE\"]\nimage:https://img.shields.io/badge/Donate-Patreon-orange.svg[link=\"https://www.patreon.com/antoyo\"]\n\n== Requirements\n\nSince relm is based on GTK+, you need this library on your system in order to use it.\n\nSee https://www.gtk.org/docs/installations/[this page] for information on how to install GTK+.\n\n== Usage\n\nFirst, add this to your `Cargo.toml`:\n\n[source,toml]\n----\ngtk = \"^0.16.0\"\nrelm = \"^0.24.0\"\nrelm-derive = \"^0.24.0\"\n----\n\nNext, add this to your crate:\n\n[source,rust]\n----\nuse relm::{connect, Relm, Update, Widget};\nuse gtk::prelude::*;\nuse gtk::{Window, Inhibit, WindowType};\nuse relm_derive::Msg;\n----\n\nThen, create your model:\n\n[source,rust]\n----\nstruct Model {\n    // …\n}\n----\n\nThe model contains the data related to a `Widget`. It may be updated by the `Widget::update` function.\n\nCreate your message `enum`:\n\n[source,rust]\n----\n#[derive(Msg)]\nenum Msg {\n    // …\n    Quit,\n}\n----\n\nMessages are sent to `Widget::update` to indicate that an event happened. The model can be updated when an event is received.\n\nCreate a `struct` which represents a `Widget` which contains the GTK+ widgets (in this case, the main window of the application) and the model:\n\n[source,rust]\n----\nstruct Win {\n    // …\n    model: Model,\n    window: Window,\n}\n----\n\nTo make this `struct` a relm `Widget` that can be shown by the library, implement the `Update` and `Widget` traits:\n\n[source,rust]\n----\nimpl Update for Win {\n    // Specify the model used for this widget.\n    type Model = Model;\n    // Specify the model parameter used to init the model.\n    type ModelParam = ();\n    // Specify the type of the messages sent to the update function.\n    type Msg = Msg;\n\n    // Return the initial model.\n    fn model(_: \u0026Relm\u003cSelf\u003e, _: ()) -\u003e Model {\n        Model {\n        }\n    }\n\n    // The model may be updated when a message is received.\n    // Widgets may also be updated in this function.\n    fn update(\u0026mut self, event: Msg) {\n        match event {\n            Msg::Quit =\u003e gtk::main_quit(),\n        }\n    }\n}\n\nimpl Widget for Win {\n    // Specify the type of the root widget.\n    type Root = Window;\n\n    // Return the root widget.\n    fn root(\u0026self) -\u003e Self::Root {\n        self.window.clone()\n    }\n\n    // Create the widgets.\n    fn view(relm: \u0026Relm\u003cSelf\u003e, model: Self::Model) -\u003e Self {\n        // GTK+ widgets are used normally within a `Widget`.\n        let window = Window::new(WindowType::Toplevel);\n\n        // Connect the signal `delete_event` to send the `Quit` message.\n        connect!(relm, window, connect_delete_event(_, _), return (Some(Msg::Quit), Inhibit(false)));\n        // There is also a `connect!()` macro for GTK+ events that do not need a\n        // value to be returned in the callback.\n\n        window.show_all();\n\n        Win {\n            model,\n            window,\n        }\n    }\n}\n----\n\nFinally, show this `Widget` by calling `Win::run()`:\n\n[source,rust]\n----\nfn main() {\n    Win::run(()).unwrap();\n}\n----\n\n=== `#[widget]` attribute\n\nA `#[widget]` attribute is provided to simplify the creation of a widget.\n\nThis attribute does the following:\n\n * Provide a `view!` macro to create the widget with a declarative syntax.\n * Automatically create the `fn root()`, `type Msg`, `type Model`, `type ModelParam` and `type Root` items.\n * Automatically insert the call to `Widget::set_property()` in the `update()` function when assigning to an attribute of the model.\n * Automatically create the `Widget` `struct`.\n * `Update` and `Widget` traits can be implemented at once.\n\nTo use this attribute, add the following code:\n\n[source,rust]\n----\nuse relm_derive::widget;\n----\n\nHere is an example using this attribute:\n\n[source,rust]\n----\n#[derive(Msg)]\npub enum Msg {\n    Decrement,\n    Increment,\n    Quit,\n}\n\npub struct Model {\n    counter: u32,\n}\n\n#[widget]\nimpl Widget for Win {\n    fn model() -\u003e Model {\n        Model {\n            counter: 0,\n        }\n    }\n\n    fn update(\u0026mut self, event: Msg) {\n        match event {\n            // A call to self.label1.set_text() is automatically inserted by the\n            // attribute every time the model.counter attribute is updated.\n            Msg::Decrement =\u003e self.model.counter -= 1,\n            Msg::Increment =\u003e self.model.counter += 1,\n            Msg::Quit =\u003e gtk::main_quit(),\n        }\n    }\n\n    view! {\n        gtk::Window {\n            gtk::Box {\n                orientation: Vertical,\n                gtk::Button {\n                    // By default, an event with one paramater is assumed.\n                    clicked =\u003e Msg::Increment,\n                    // Hence, the previous line is equivalent to:\n                    // clicked(_) =\u003e Increment,\n                    label: \"+\",\n                },\n                gtk::Label {\n                    // Bind the text property of this Label to the counter attribute\n                    // of the model.\n                    // Every time the counter attribute is updated, the text property\n                    // will be updated too.\n                    text: \u0026self.model.counter.to_string(),\n                },\n                gtk::Button {\n                    clicked =\u003e Msg::Decrement,\n                    label: \"-\",\n                },\n            },\n            // Use a tuple when you want to both send a message and return a value to\n            // the GTK+ callback.\n            delete_event(_, _) =\u003e (Msg::Quit, Inhibit(false)),\n        }\n    }\n}\n----\n\nNOTE: The `struct Win` is now automatically created by the attribute, as are the function `root()` and the associated types `Model`, `ModelParam`, `Msg` and `Container`.\nYou can still provide the method and the associated types if needed, but you cannot create the `struct`.\n\nWARNING: The `#[widget]` makes the generated `struct` public: hence, the corresponding model and message types must be public too.\n\n[WARNING]\n====\nYour program might be slower when using this attribute because the code generation is simple.\nFor instance, the following code\n[source,rust]\n----\nfn update(\u0026mut self, event: Msg) {\n    for _ in 0..100 {\n        self.model.counter += 1;\n    }\n}\n----\nwill generate this function:\n[source,rust]\n----\nfn update(\u0026mut self, event: Msg) {\n    for _ in 0..100 {\n        self.model.counter += 1;\n        self.label1.set_text(\u0026self.model.counter.to_string());\n    }\n}\n----\n====\n\n[WARNING]\n====\nAlso, the `set_property()` calls are currently only inserted when assigning to an attribute of the model.\nFor instance, the following code\n[source,rust]\n----\nfn update(\u0026mut self, event: Msg) {\n    self.model.text.push_str(\"Text\");\n}\n----\nwill not work as expected.\n\nPlease use the following variation if needed.\n[source,rust]\n----\nfn update(\u0026mut self, event: Msg) {\n    self.model.text += \"Text\";\n}\n----\n====\n\nFor more information about how you can use relm, you can take a look at the https://github.com/antoyo/relm/tree/master/relm-examples/[examples].\n\n== Donations\n\nIf you appreciate this project and want new features to be\nimplemented, please support me on Patreon.\n\nimage:https://c5.patreon.com/external/logo/become_a_patron_button.png[link=\"https://www.patreon.com/antoyo\"]\n\n== Projects using `relm`\n\n * https://github.com/sanpii/yellow-pitaya[Yellow Pitaya]: A desktop interface for the redpitaya hardware oscilloscope.\n * https://github.com/juchiast/gameoflife[Game of Life]: Conway's Game of Life Simulator\n * https://github.com/etrombly/country_parser[Country Parser]: Parses Google location history and displays timeline of countries visited\n * https://github.com/niklasf/rust-chessground[Chessground]: An experimental chessboard widget\n * https://github.com/sanpii/effitask[Effitask]: Graphical task manager, based on the todo.txt format\n * https://github.com/knack-supply/curve-tracer[KS Curve Tracer]: A companion app for AD2 curve tracer\n * https://github.com/emmanueltouzery/cigale[Cigale]: Tool to prepare the timesheet of the tasks you did at work\n * https://github.com/emmanueltouzery/projectpad2[Projectpad]: Manage secret credentials and server information as a software developer or sysadmin.\n * https://github.com/crrodger/timezoners[TimezoneRS]: A GUI application to visually see the time in different time zones\n * https://github.com/Schmiddiii/Tubefeeder[Tubefeeder] / https://gitlab.com/schmiddi-on-mobile/pipeline[Pipeline]: Watch YouTube, LBRY, and PeerTube videos in one place.\n * https://github.com/emmanueltouzery/hotwire[Hotwire]: Study network traffic of a few popular protocols in a simple way\n * https://mzte.de/git/LordMZTE/gue[gue]: GUI for controlling phillips hue lights\n * https://github.com/mycitadel/mycitadel-desktop[MyCitadel Wallet]: MyCitadel Cryptocurrency Wallet app\n\nIf you want to add your project to this list, please https://github.com/antoyo/relm/pulls[create a pull request].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoyo%2Frelm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantoyo%2Frelm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantoyo%2Frelm/lists"}