1#![warn(
3 missing_debug_implementations,
4 rust_2018_idioms,
5 unreachable_pub,
6 unused_qualifications,
7 clippy::cargo,
8 clippy::must_use_candidate,
9 clippy::used_underscore_binding
10)]
11
12use gtk::prelude::{
13 BoxExt, ButtonExt, GridExt, GtkWindowExt, ObjectExt, OrientableExt, ToggleButtonExt, WidgetExt,
14};
15use relm4::{ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
16
17#[tracker::track]
18struct App {
19 value: u8,
20}
21
22#[derive(Debug)]
23enum Msg {
24 Increment,
25 Decrement,
26}
27
28struct AppInit {
29 counter: u8,
30}
31
32#[relm4::component(pub)]
33impl SimpleComponent for App {
34 type Init = AppInit;
35 type Input = Msg;
36 type Output = ();
37 type Widgets = AppWidgets;
40
41 view! {
42 #[root]
43 #[name(main_window)]
44 gtk::Window {
45 set_title: Some("Macro reference example"),
46 set_default_size: (300, 100),
47
48 gtk::Box {
49 set_orientation: gtk::Orientation::Vertical,
50 set_spacing: 5,
51 set_margin_all: 5,
52
53 append: inc_button = >k::Button {
54 set_label: "Increment",
55 set_icon_name?: icon_name,
57 connect_clicked[sender] => move |_| {
58 sender.input(Msg::Increment);
59 }
60 },
61
62 gtk::Button {
63 set_label: "Decrement",
64 connect_clicked => Msg::Decrement,
65 },
66
67 gtk::Grid {
68 attach[1, 1, 1, 1] = >k::Label {
69 set_label: "Count to 10 to see if the tracker works!",
70 #[track(skip_init, counter.value.is_multiple_of(10))]
72 set_label: &format!("Grid works! ({})", counter.value),
73 }
74 },
75
76 #[transition(SlideLeft)]
79 append = if counter.value.is_multiple_of(2) {
80 gtk::Label {
81 set_label: "Value is even",
82 }
83 } else if counter.value.is_multiple_of(3) {
84 gtk::Label {
85 set_label: "Value is dividable by 3",
86 }
87 } else {
88 gtk::Label {
89 set_label: "Value is odd",
90 }
91 },
92
93 #[transition = "SlideRight"]
94 append: match_stack = match counter.value {
95 (0..=2) => {
96 gtk::Label {
97 set_label: "Value is smaller than 3",
98 }
99 },
100 _ => {
101 gtk::Label {
102 set_label: "Value is higher than 2",
103 }
104 },
105 },
106
107 append = >k::Label,
108
109 gtk::Label::builder()
110 .label("Builder pattern works!")
111 .selectable(true)
112 .build(),
113
114 gtk::Label::new(Some("Constructors work!")),
115
116 #[name = "counter_label"]
118 gtk::Label {
119 #[chain(build())]
121 bind_property: ("label", &bind_label, "label"),
122 set_label: "Click the counter so see the value!",
123
124 #[watch(skip_init)]
125 set_label: &format!("Counter: {}", counter.value),
126 #[track]
127 set_margin_all: counter.value.into(),
128 },
129
130 #[name = "bind_label"]
131 gtk::Label {},
132
133 gtk::Stack {
135 add_child = >k::Label {
136 set_label: "placeholder",
137 } -> {
138 set_title: "page title",
140 }
141 },
142
143 gtk::ToggleButton {
144 set_label: "Counter is even",
145 #[watch]
146 #[block_signal(toggle_handler)]
147 set_active: counter.value.is_multiple_of(2),
148
149 connect_toggled[sender] => move |_| {
150 sender.input(Msg::Increment);
151 } @toggle_handler,
152 },
153
154 #[local]
155 local_label -> gtk::Label {
156 set_opacity: 0.7,
157 },
158
159 #[local_ref]
160 local_ref_label -> gtk::Label {
161 set_opacity: 0.7,
162 set_size_request: (40, 40),
163 },
164 }
165 },
166 gtk::Window {
167 set_title: Some("Another window"),
168 set_default_size: (300, 100),
169 set_transient_for: Some(&main_window),
170 set_visible: false,
171 grab_focus: (),
173
174 #[watch]
175 set_visible: counter.value == 42,
176
177 #[name = "my_label_name"]
178 gtk::Label {
179 set_label: "You made it to 42!",
180 }
181 }
182 }
183
184 fn init(
186 init: Self::Init,
187 renamed_root: Self::Root,
188 sender: ComponentSender<Self>,
189 ) -> ComponentParts<Self> {
190 let counter = App {
191 value: init.counter,
192 tracker: 0,
193 };
194
195 let icon_name = rand::random::<bool>().then_some("go-up-symbolic");
197
198 let local_label = gtk::Label::new(Some("local_label"));
199 let local_ref_label_value = gtk::Label::new(Some("local_ref_label"));
200 let local_ref_label = &local_ref_label_value;
201 let widgets = view_output!();
203
204 ComponentParts {
205 model: counter,
206 widgets,
207 }
208 }
209
210 fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
211 self.reset();
212 match msg {
213 Msg::Increment => {
214 self.set_value(self.value.wrapping_add(1));
215 }
216 Msg::Decrement => {
217 self.set_value(self.value.wrapping_sub(1));
218 }
219 }
220 }
221}
222
223fn main() {
224 let app = RelmApp::new("relm4.example.macro_reference");
225 app.run::<App>(AppInit { counter: 0 });
226}