message_broker/
message_broker.rs1#![allow(deprecated)]
4
5use std::convert::identity;
6
7use gtk::prelude::{BoxExt, ButtonExt, DialogExt, GtkWindowExt, ToggleButtonExt, WidgetExt};
8use relm4::gtk::prelude::Cast;
9use relm4::{
10 Component, ComponentController, ComponentParts, ComponentSender, Controller, MessageBroker,
11 RelmApp, SimpleComponent,
12};
13
14static HEADER_BROKER: MessageBroker<bool> = MessageBroker::new();
15
16struct Header(bool);
17
18#[relm4::component]
19impl SimpleComponent for Header {
20 type Init = ();
21 type Input = bool;
22 type Output = AppMsg;
23
24 view! {
25 gtk::HeaderBar {
26 #[wrap(Some)]
27 set_title_widget = >k::Box {
28 add_css_class: relm4::css::LINKED,
29 append: group = >k::ToggleButton {
30 set_label: "View",
31 set_active: true,
32 #[watch]
33 set_has_frame: model.0,
34 connect_toggled[sender] => move |btn| {
35 if btn.is_active() {
36 sender.output(AppMsg::SetMode(AppMode::View)).unwrap();
37 }
38 },
39 },
40 gtk::ToggleButton {
41 set_label: "Edit",
42 set_group: Some(&group),
43 #[watch]
44 set_has_frame: model.0,
45 connect_toggled[sender] => move |btn| {
46 if btn.is_active() {
47 sender.output(AppMsg::SetMode(AppMode::Edit)).unwrap();
48 }
49 },
50 },
51 gtk::ToggleButton {
52 set_group: Some(&group),
53 set_label: "Export",
54 #[watch]
55 set_has_frame: model.0,
56 connect_toggled[sender] => move |btn| {
57 if btn.is_active() {
58 sender.output(AppMsg::SetMode(AppMode::Export)).unwrap();
59 }
60 },
61 },
62 }
63 }
64 }
65
66 fn init(
67 _init: Self::Init,
68 root: Self::Root,
69 sender: ComponentSender<Self>,
70 ) -> ComponentParts<Self> {
71 let model = Header(false);
72 let widgets = view_output!();
73
74 ComponentParts { model, widgets }
75 }
76
77 fn update(&mut self, input: Self::Input, _sender: ComponentSender<Self>) {
78 self.0 = input;
79 }
80}
81
82struct Dialog {
83 hidden: bool,
84}
85
86#[derive(Debug)]
87enum DialogMsg {
88 Show,
89 Accept,
90 Cancel,
91}
92
93#[relm4::component]
94impl SimpleComponent for Dialog {
95 type Init = gtk::Window;
96 type Input = DialogMsg;
97 type Output = AppMsg;
98
99 view! {
100 dialog = gtk::MessageDialog {
101 set_transient_for: Some(&parent_window),
102 set_modal: true,
103 set_text: Some("Do you want frames around the header buttons?"),
104 add_button: ("Yes", gtk::ResponseType::Accept),
105 add_button: ("No", gtk::ResponseType::Cancel),
106
107 #[watch]
108 set_visible: !model.hidden,
109
110 connect_response[sender] => move |_, resp| {
111 sender.input(if resp == gtk::ResponseType::Accept {
112 HEADER_BROKER.send(true);
115 DialogMsg::Accept
116 } else {
117 HEADER_BROKER.send(false);
118 DialogMsg::Cancel
119 });
120 }
121 }
122 }
123
124 fn init(
125 parent_window: Self::Init,
126 root: Self::Root,
127 sender: ComponentSender<Self>,
128 ) -> ComponentParts<Self> {
129 let model = Dialog { hidden: true };
130
131 let widgets = view_output!();
132
133 ComponentParts { model, widgets }
134 }
135
136 fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
137 match msg {
138 DialogMsg::Show => self.hidden = false,
139 DialogMsg::Cancel | DialogMsg::Accept => self.hidden = true,
140 }
141 }
142}
143
144#[derive(Debug)]
145enum AppMode {
146 View,
147 Edit,
148 Export,
149}
150
151#[derive(Debug)]
152enum AppMsg {
153 SetMode(AppMode),
154 ShowDialog,
155}
156
157struct App {
158 mode: AppMode,
159 dialog: Controller<Dialog>,
160 header: Controller<Header>,
161}
162
163#[relm4::component]
164impl SimpleComponent for App {
165 type Init = ();
166 type Input = AppMsg;
167 type Output = ();
168
169 view! {
170 main_window = gtk::ApplicationWindow {
171 set_default_size: (500, 250),
172 set_titlebar: Some(model.header.widget()),
173
174 #[wrap(Some)]
175 set_child = >k::Label {
176 #[watch]
177 set_label: &format!("Placeholder for {:?}", model.mode),
178 },
179 gtk::Button {
180 set_label: "Change header style",
181 connect_clicked => AppMsg::ShowDialog,
182 }
183 }
184 }
185
186 fn init(
187 _init: Self::Init,
188 root: Self::Root,
189 sender: ComponentSender<Self>,
190 ) -> ComponentParts<Self> {
191 let header = Header::builder()
192 .launch_with_broker((), &HEADER_BROKER)
193 .forward(sender.input_sender(), identity);
194
195 let dialog = Dialog::builder()
196 .launch(root.clone().upcast())
197 .forward(sender.input_sender(), identity);
198
199 let model = App {
200 mode: AppMode::View,
201 header,
202 dialog,
203 };
204
205 let widgets = view_output!();
206
207 ComponentParts { model, widgets }
208 }
209
210 fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
211 match msg {
212 AppMsg::SetMode(mode) => {
213 self.mode = mode;
214 }
215 AppMsg::ShowDialog => {
216 self.dialog.emit(DialogMsg::Show);
217 }
218 }
219 }
220}
221
222fn main() {
223 let app = RelmApp::new("relm4.example.message_broker");
224 app.run::<App>(());
225}