1use std::convert::identity;
2use std::time::Duration;
3
4use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
5use relm4::{
6 Component, ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent, Worker,
7 WorkerController,
8};
9
10struct AsyncHandler;
11
12#[derive(Debug)]
13enum AsyncHandlerMsg {
14 DelayedIncrement,
15 DelayedDecrement,
16}
17
18struct App {
19 counter: u8,
20 worker: WorkerController<AsyncHandler>,
21}
22
23#[derive(Debug)]
24enum AppMsg {
25 Increment,
26 Decrement,
27}
28
29impl Worker for AsyncHandler {
30 type Init = ();
31 type Input = AsyncHandlerMsg;
32 type Output = AppMsg;
33
34 fn init(_init: Self::Init, _sender: ComponentSender<Self>) -> Self {
35 Self
36 }
37
38 fn update(&mut self, msg: AsyncHandlerMsg, sender: ComponentSender<Self>) {
43 std::thread::sleep(Duration::from_secs(1));
44
45 match msg {
46 AsyncHandlerMsg::DelayedIncrement => sender.output(AppMsg::Increment).unwrap(),
47 AsyncHandlerMsg::DelayedDecrement => sender.output(AppMsg::Decrement).unwrap(),
48 }
49 }
50}
51
52#[relm4::component]
53impl SimpleComponent for App {
54 type Init = ();
55 type Input = AppMsg;
56 type Output = ();
57
58 view! {
59 gtk::Window {
60 set_title: Some("Worker Counter"),
61 set_default_size: (300, 100),
62
63 gtk::Box {
64 set_orientation: gtk::Orientation::Vertical,
65 set_margin_all: 5,
66 set_spacing: 5,
67
68 gtk::Button {
69 set_label: "Increment",
70 connect_clicked[sender = model.worker.sender().clone()] => move |_| {
71 sender.send(AsyncHandlerMsg::DelayedIncrement).unwrap();
72 },
73 },
74 gtk::Button::with_label("Decrement") {
75 connect_clicked[sender = model.worker.sender().clone()] => move |_| {
76 sender.send(AsyncHandlerMsg::DelayedDecrement).unwrap();
77 },
78 },
79 gtk::Label {
80 set_margin_all: 5,
81 #[watch]
82 set_label: &format!("Counter: {}", model.counter),
83 },
84 },
85 }
86 }
87
88 fn init(
89 _: Self::Init,
90 root: Self::Root,
91 sender: ComponentSender<Self>,
92 ) -> ComponentParts<Self> {
93 let model = App {
94 counter: 0,
95 worker: AsyncHandler::builder()
96 .detach_worker(())
97 .forward(sender.input_sender(), identity),
98 };
99
100 let widgets = view_output!();
101
102 ComponentParts { model, widgets }
103 }
104
105 fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
106 match msg {
107 AppMsg::Increment => {
108 self.counter = self.counter.wrapping_add(1);
109 }
110 AppMsg::Decrement => {
111 self.counter = self.counter.wrapping_sub(1);
112 }
113 }
114 }
115}
116
117fn main() {
118 let app = RelmApp::new("relm4.example.worker");
119 app.run::<App>(());
120}