non_blocking_sync/
non_blocking_sync.rs1use std::time::Duration;
2
3use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
4use relm4::{Component, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt};
5
6struct App {
7 counter: u8,
8}
9
10#[derive(Debug)]
11enum Msg {
12 Increment,
13 Decrement,
14}
15
16#[relm4::component]
17impl Component for App {
18 type Init = ();
19 type Input = ();
20 type Output = ();
21 type CommandOutput = Msg;
22 type Widgets = AppWidgets;
23
24 view! {
25 gtk::Window {
26 set_title: Some("Async Counter"),
27 set_default_size: (300, 100),
28
29 gtk::Box {
30 set_orientation: gtk::Orientation::Vertical,
31 set_margin_all: 5,
32 set_spacing: 5,
33
34 gtk::Button {
35 set_label: "Increment",
36 connect_clicked[sender] => move |_| {
38 sender.spawn_oneshot_command(|| {
39 std::thread::sleep(Duration::from_secs(1));
40 Msg::Increment
41 })
42 },
43 },
44
45 gtk::Button::with_label("Decrement") {
46 connect_clicked[sender] => move |_| {
47 sender.spawn_oneshot_command(|| {
48 std::thread::sleep(Duration::from_secs(1));
49 Msg::Decrement
50 })
51 },
52 },
53
54 gtk::Label {
55 set_margin_all: 5,
56 #[watch]
57 set_label: &format!("Counter: {}", model.counter),
58 },
59 },
60 }
61 }
62
63 fn init(
64 _: Self::Init,
65 root: Self::Root,
66 sender: ComponentSender<Self>,
67 ) -> ComponentParts<Self> {
68 let model = App { counter: 0 };
69
70 let widgets = view_output!();
71
72 ComponentParts { model, widgets }
73 }
74
75 fn update_cmd(
76 &mut self,
77 msg: Self::CommandOutput,
78 _sender: ComponentSender<Self>,
79 _root: &Self::Root,
80 ) {
81 match msg {
82 Msg::Increment => {
83 self.counter = self.counter.wrapping_add(1);
84 }
85 Msg::Decrement => {
86 self.counter = self.counter.wrapping_sub(1);
87 }
88 }
89 }
90}
91
92fn main() {
93 let app = RelmApp::new("relm4.example.non_blocking_async");
94 app.run::<App>(());
95}