declarative

A proc-macro library for creating complex reactive views declaratively and quickly.
To use it, add to your Cargo.toml:
[dependencies.declarative]
version = '0.1'
features = ['builder-mode']
features = ['gtk-rs']
To learn how to use this macro, it is best to clone this repository, read the source code of the examples in alphabetical order and run them like this:
cargo run --features gtk-rs --example EXAMPLE_NAME
The examples depend on gtk-rs, so you should familiarize yourself with gtk-rs a bit before:
https://gtk-rs.org/gtk4-rs/stable/latest/book/
Application example
In the following I manually implement the Elm pattern. The macro does not require any specific pattern.

use declarative::{builder_mode, clone};
use gtk::{glib, prelude::*};
#[derive(Debug)]
enum Msg { Increase, Decrease }
struct State { count: i32 }
fn update_state(state: &mut State, msg: Msg) {
match msg {
Msg::Increase => state.count = state.count.wrapping_add(1),
Msg::Decrease => state.count = state.count.wrapping_sub(1),
}
}
#[declarative::view {
gtk::ApplicationWindow window !{
application: app
title: "My Application"
gtk::HeaderBar #titlebar(&#) { }
gtk::Box #child(&#) !{
orientation: gtk::Orientation::Vertical
spacing: 6
margin_top: 6
margin_bottom: 6
margin_start: 6
margin_end: 6 #..
gtk::Label #append(&#) {
'bind! set_label: &format!("The count is: {}", state.count)
}
gtk::Button::with_label("Increase") #append(&#) {
connect_clicked: clone! {
sender; move |_| send!(Msg::Increase => sender)
}
}
gtk::Button::with_label("Decrease") #append(&#) {
connect_clicked: move |_| send!(Msg::Decrease => sender)
}
'binding update_view = move |state: &State| bindings!()
}
}
}]
fn window(app: >k::Application) -> gtk::ApplicationWindow {
let mut state = State { count: 0 };
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
expand_view_here! { }
receiver.attach(None, move |msg| {
update_state(&mut state, msg);
update_view(&state);
glib::Continue(true)
});
window
}
fn main() -> glib::ExitCode {
let app = gtk::Application::default();
app.connect_activate(move |app| window(app).present());
app.run()
}
macro_rules! send {
($expr:expr => $sender:ident) => {
$sender.send($expr).unwrap_or_else(
move |error| glib::g_critical!("example", "{error}")
)
};
}
use send;
To execute, run:
cargo run --features gtk-rs --example readme
License
Licensed under either of
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.