gladis4 0.1.0

Easily import Glade-generated UI files into Rust code.
use gtk::{
    prelude::*,
    Inhibit, Label, ApplicationWindow,
    Button,
};
use relm4::{send, AppUpdate, Model, RelmApp, Sender, WidgetPlus, Widgets};

use gladis4::Gladis;

struct AppModel {
    counter: i32,
}

enum AppMsg {
    Decrement,
    Increment,
    Quit,
}

// Create the structure that holds the widgets used in the view.
#[derive(Clone, Gladis)]
struct GladisWidgets {
    counter_label: Label,
    minus_button: Button,
    plus_button: Button,
    window: ApplicationWindow,
}

struct Win {
    widgets: GladisWidgets,
}

impl Model for AppModel {
    type Msg = AppMsg;
    type Components = ();
    type Widgets = GladisWidgets;
}

impl AppUpdate for AppModel {
    fn update(&mut self, event: AppMsg, _components: &(), _sender: Sender<AppMsg>) -> bool {
        match event {
            AppMsg::Decrement => {
                self.counter -= 1;
            }
            AppMsg::Increment => {
                self.counter += 1;
            }
            AppMsg::Quit => return false,
        }

        true
    }
}

impl Widgets<AppModel, ()> for GladisWidgets {
    // Specify the type of the root widget.
    type Root = ApplicationWindow;

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

    fn init_view(model: &AppModel, _parent_widgets: &(), sender: Sender<AppMsg>) -> Self {
        let glade_src = include_str!("window.glade");
        let widgets = GladisWidgets::from_string(glade_src).unwrap();

        widgets.window.present();

        let minus_sender = sender.clone();
        widgets.minus_button.connect_clicked(move |_| {
            send!(minus_sender, AppMsg::Decrement)
        });

        let sender = sender.clone();
        widgets.plus_button.connect_clicked(move |_| {
            send!(sender, AppMsg::Increment)
        });
        
        widgets
    }

    fn view(&mut self, model: &AppModel, _sender: Sender<AppMsg>)  {
        self.counter_label.set_text(&model.counter.to_string());
    }
}

fn main() {
    let model = AppModel { counter: 0 };
    let app = RelmApp::new(model);
    app.run();
}

#[cfg(test)]
mod tests {
    use gtk::prelude::LabelExt;

    use gtk_test::assert_text;
    use relm_test::click;

    use crate::Win;

    #[test]
    #[ignore]
    fn label_change() {
        let (_component, _, widgets) = relm::init_test::<Win>(()).expect("init_test failed");
        let plus_button = &widgets.plus_button;
        let minus_button = &widgets.minus_button;
        let label = &widgets.counter_label;

        assert_text!(label, 0);
        click(plus_button);
        assert_text!(label, 1);
        click(plus_button);
        assert_text!(label, 2);
        click(plus_button);
        assert_text!(label, 3);
        click(plus_button);
        assert_text!(label, 4);

        click(minus_button);
        assert_text!(label, 3);
        click(minus_button);
        assert_text!(label, 2);
        click(minus_button);
        assert_text!(label, 1);
        click(minus_button);
        assert_text!(label, 0);
        click(minus_button);
        assert_text!(label, -1);
    }
}