nrelm 0.1.0

An idiomatic GUI library inspired by Elm and based on gtk3-rs
<h1>
  <a href="https://gitlab.com/NeoRelm/NeoRelm">
    <img src="assets/Relm_logo_with_text.png" width="200" alt="NeoRelm">
  </a>
</h1>

[![Pipeline](https://gitlab.com/NeoRelm/NeoRelm/badges/main/pipeline.svg)](https://gitlab.com/NeoRelm/NeoRelm/-/pipelines)
[![NeoRelm on crates.io](https://img.shields.io/crates/v/nrelm.svg)](https://crates.io/crates/nrelm)
[![NeoRelm docs](https://img.shields.io/badge/rust-documentation-blue)](https://docs.rs/nrelm/)
![Minimum Rust version 1.93](https://img.shields.io/badge/rustc-1.93+-06a096.svg)
[![dependency status](https://deps.rs/repo/gitlab/NeoRelm/NeoRelm/status.svg)](https://deps.rs/repo/gitlab/NeoRelm/NeoRelm)

An idiomatic GUI library inspired by [Elm](https://elm-lang.org/) and based on [gtk3-rs](https://crates.io/crates/gtk).

**NeoRelm is a GTK3 port of [Relm4](https://gitlab.com/Relm4/Relm4)** (the original
[Relm4](https://gitlab.com/Relm4/Relm4) targets [GTK4](https://www.gtk.org/) and
[libadwaita](https://gitlab.gnome.org/GNOME/libadwaita), while this project backports the same
API and design to [GTK3](https://www.gtk.org/)).
Why? Because gnome keeps deprecating everything in gtk4. Making apps with gtk4 without libadwaita might not be easy in future. And because I wanted to make apps for [XFCE](https://xfce.org).

## Documentation

+ 📜 **[Rust documentation]https://docs.rs/nrelm/**
+ 🌐 **[The repository]https://gitlab.com/NeoRelm/NeoRelm** — including examples and the changelog

## Dependencies

NeoRelm depends on GTK3

## Ecosystem

+ [nrelm-macros]https://crates.io/crates/nrelm-macros - several macros for declarative UI definitions.
+ [nrelm-components]https://crates.io/crates/nrelm-components - a collection of reusable components.
+ [nrelm-icons]https://gitlab.com/NeoRelm/NeoRelm-icons - icons for your application (maintained in its own repository).

Use this in your `Cargo.toml`:

```toml
# Core library
nrelm = "0.1"
# Optional: reusable components
nrelm-components = "0.1"
# Optional: icons (more info at https://gitlab.com/NeoRelm/NeoRelm-icons)
nrelm-icons = "0.1"
```

### Features

The `nrelm` crate has two feature flags:

| Flag     | Purpose                                                                         | Default |
|:---------|:--------------------------------------------------------------------------------|:-------:|
| `macros` | Enable macros by re-exporting [`nrelm-macros`]https://crates.io/crates/nrelm-macros ||
| `css`    | Enable the built-in CSS definitions of [`nrelm-css`]https://crates.io/crates/nrelm-css ||

## Examples

Several example applications are available at [examples/](examples/).

#### [📸 Screenshots from the example apps]assets/screenshots

### A simple counter app

![Simple app screenshot light](assets/screenshots/simple-light.png)
![Simple app screenshot dark](assets/screenshots/simple-dark.png)

```rust
use gtk::prelude::*;
use nrelm::prelude::*;

struct AppModel {
    counter: u8,
}

#[derive(Debug)]
enum AppMsg {
    Increment,
    Decrement,
}

#[nrelm::component]
impl SimpleComponent for AppModel {
    type Init = u8;
    type Input = AppMsg;
    type Output = ();

    view! {
        gtk::Window {
            set_title: "Simple app",
            set_default_size: (300, 100),

            gtk::Box {
                set_orientation: gtk::Orientation::Vertical,
                set_spacing: 5,
                set_margin_all: 5,

                gtk::Button {
                    set_label: "Increment",
                    connect_clicked => AppMsg::Increment,
                },

                gtk::Button {
                    set_label: "Decrement",
                    connect_clicked => AppMsg::Decrement,
                },

                gtk::Label {
                    #[watch]
                    set_label: &format!("Counter: {}", model.counter),
                    set_margin_all: 5,
                }
            }
        }
    }

    // Initialize the component.
    fn init(
        counter: Self::Init,
        root: Self::Root,
        sender: ComponentSender<Self>,
    ) -> ComponentParts<Self> {
        let model = AppModel { counter };

        // Insert the code generation of the view! macro here
        let widgets = view_output!();

        ComponentParts { model, widgets }
    }

    fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
        match msg {
            AppMsg::Increment => {
                self.counter = self.counter.wrapping_add(1);
            }
            AppMsg::Decrement => {
                self.counter = self.counter.wrapping_sub(1);
            }
        }
    }
}

fn main() {
    let app = RelmApp::new("nrelm.example.simple");
    app.run::<AppModel>(0);
}
```

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE]LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT]LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

**Feedback and contributions are highly appreciated!**