widget_template/
widget_template.rs

1use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
2use relm4::{
3    ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent, WidgetTemplate,
4};
5
6#[relm4::widget_template]
7impl WidgetTemplate for MyBox {
8    view! {
9        gtk::Box {
10            set_margin_all: 10,
11            // Make the boxes visible
12            inline_css: "border: 2px solid blue",
13        }
14    }
15}
16
17#[relm4::widget_template]
18impl WidgetTemplate for MySpinner {
19    view! {
20        gtk::Spinner {
21            set_spinning: true,
22        }
23    }
24}
25
26#[relm4::widget_template]
27impl WidgetTemplate for MyWindow {
28    view! {
29        gtk::Window {
30            set_title: Some("Widget template"),
31            set_default_width: 300,
32            set_default_height: 100,
33        }
34    }
35}
36
37#[relm4::widget_template]
38impl WidgetTemplate for CustomBox {
39    view! {
40        gtk::Box {
41            set_orientation: gtk::Orientation::Vertical,
42            set_margin_all: 5,
43            set_spacing: 5,
44
45            #[template]
46            MyBox {
47                #[template]
48                MySpinner,
49
50                #[template]
51                MyBox {
52                    #[template]
53                    MySpinner,
54
55                    #[template]
56                    MyBox {
57                        #[template]
58                        MySpinner,
59
60                        // Deeply nested!
61                        #[name = "child_label"]
62                        gtk::Label {
63                            set_label: "This is a test",
64                        }
65                    }
66                }
67            }
68        }
69    }
70}
71
72#[derive(Default)]
73struct AppModel {
74    counter: u8,
75}
76
77#[derive(Debug)]
78enum AppMsg {
79    Increment,
80    Decrement,
81}
82
83#[relm4::component]
84impl SimpleComponent for AppModel {
85    type Init = u8;
86    type Input = AppMsg;
87    type Output = ();
88
89    view! {
90        #[template]
91        MyWindow {
92            #[template]
93            CustomBox {
94                #[template_child]
95                child_label {
96                    #[watch]
97                    set_label: &format!("Counter: {}", model.counter),
98                },
99                gtk::Button {
100                    set_label: "Increment",
101                    connect_clicked[sender] => move |_| {
102                        sender.input(AppMsg::Increment);
103                    },
104                },
105                gtk::Button {
106                    set_label: "Decrement",
107                    connect_clicked[sender] => move |_| {
108                        sender.input(AppMsg::Decrement);
109                    },
110                },
111            },
112        }
113    }
114
115    fn init(
116        counter: Self::Init,
117        root: Self::Root,
118        sender: ComponentSender<Self>,
119    ) -> ComponentParts<Self> {
120        let model = Self { counter };
121
122        let widgets = view_output!();
123
124        ComponentParts { model, widgets }
125    }
126
127    fn update(&mut self, msg: AppMsg, _sender: ComponentSender<Self>) {
128        match msg {
129            AppMsg::Increment => {
130                self.counter = self.counter.wrapping_add(1);
131            }
132            AppMsg::Decrement => {
133                self.counter = self.counter.wrapping_sub(1);
134            }
135        }
136    }
137}
138
139fn main() {
140    let app = RelmApp::new("relm4.example.widget_template");
141    app.run::<AppModel>(0);
142}