pub struct Connector<C: Component> { /* private fields */ }
Expand description
Contains the post-launch input sender and output receivers with the root widget.
The receiver can be separated from the Connector
by choosing a method for handling it.
Implementations§
Source§impl<C: Component> Connector<C>
impl<C: Component> Connector<C>
Sourcepub fn forward<X: 'static, F: Fn(C::Output) -> X + 'static>(
self,
sender_: &Sender<X>,
transform: F,
) -> Controller<C>
pub fn forward<X: 'static, F: Fn(C::Output) -> X + 'static>( self, sender_: &Sender<X>, transform: F, ) -> Controller<C>
Forwards output events to the designated sender.
Examples found in repository?
examples/message_broker.rs (line 193)
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 }
More examples
examples/transient_dialog.rs (line 113)
101 fn init(
102 _init: Self::Init,
103 root: Self::Root,
104 sender: ComponentSender<Self>,
105 ) -> ComponentParts<Self> {
106 // We don't have access to the parent window from here
107 // but we can just use the button to set the transient window for the dialog.
108 // Relm4 will get the window later by calling [`WidgetExt::root()`]
109 // on the button once all widgets are connected.
110 let dialog = Dialog::builder()
111 .transient_for(&root)
112 .launch_with_broker((), &DIALOG_BROKER)
113 .forward(sender.input_sender(), identity);
114
115 let model = Button { dialog };
116 let widgets = view_output!();
117 ComponentParts { model, widgets }
118 }
119
120 fn update(&mut self, _msg: Self::Input, _sender: ComponentSender<Self>) {}
121}
122
123#[derive(Debug)]
124enum AppMsg {}
125
126struct App {
127 button: Controller<Button>,
128}
129
130#[relm4::component]
131impl SimpleComponent for App {
132 type Init = ();
133 type Input = AppMsg;
134 type Output = ();
135
136 view! {
137 main_window = gtk::ApplicationWindow {
138 set_default_size: (500, 250),
139 set_child: Some(model.button.widget()),
140 }
141 }
142
143 fn init(
144 _init: Self::Init,
145 root: Self::Root,
146 sender: ComponentSender<Self>,
147 ) -> ComponentParts<Self> {
148 let button = Button::builder()
149 .launch(())
150 .forward(sender.input_sender(), identity);
151 let model = App { button };
152 let widgets = view_output!();
153 ComponentParts { model, widgets }
154 }
examples/components.rs (line 184)
177 fn init(
178 _: Self::Init,
179 root: Self::Root,
180 sender: ComponentSender<Self>,
181 ) -> ComponentParts<Self> {
182 let header = Header::builder()
183 .launch(())
184 .forward(sender.input_sender(), identity);
185 let dialog = Dialog::builder()
186 .transient_for(&root)
187 .launch(DialogInit {
188 text: "Do you want to close before saving?".to_string(),
189 secondary_text: Some("All unsaved changes will be lost".to_string()),
190 accept_text: "Close".to_string(),
191 cancel_text: "Cancel".to_string(),
192 })
193 .forward(sender.input_sender(), identity);
194
195 let model = App {
196 mode: AppMode::View,
197 header,
198 dialog,
199 };
200 let widgets = view_output!();
201
202 ComponentParts { model, widgets }
203 }
examples/drop_sub_components.rs (lines 75-78)
62 fn update_with_view(
63 &mut self,
64 widgets: &mut Self::Widgets,
65 message: Self::Input,
66 sender: ComponentSender<Self>,
67 root: &Self::Root,
68 ) {
69 widgets.container.remove_all();
70 match message {
71 Msg::ShowInitialScreen => {
72 let controller =
73 InitialScreen::builder()
74 .launch(())
75 .forward(sender.input_sender(), |msg| match msg {
76 InitialScreenOutput::ShowSubScreen1 => Msg::ShowSubScreen1,
77 InitialScreenOutput::ShowSubScreen2 => Msg::ShowSubScreen2,
78 });
79 widgets.container.append(controller.widget());
80 self.mode = Some(AppMode::Initial(controller));
81 }
82 Msg::ShowSubScreen1 => {
83 let controller = SubScreen1::builder()
84 .launch(())
85 .forward(sender.input_sender(), |_| Msg::ShowInitialScreen);
86 widgets.container.append(controller.widget());
87 self.mode = Some(AppMode::SubScreen1(controller));
88 }
89 Msg::ShowSubScreen2 => {
90 let controller = SubScreen2::builder()
91 .launch(())
92 .forward(sender.input_sender(), |_| Msg::ShowInitialScreen);
93 widgets.container.append(controller.widget());
94 self.mode = Some(AppMode::SubScreen2(controller));
95 }
96 }
97 root.set_default_size(400, 300);
98 }
Sourcepub fn connect_receiver<F: FnMut(&mut Sender<C::Input>, C::Output) + 'static>(
self,
func: F,
) -> Controller<C>
pub fn connect_receiver<F: FnMut(&mut Sender<C::Input>, C::Output) + 'static>( self, func: F, ) -> Controller<C>
Given a mutable closure, captures the receiver for handling.
Examples found in repository?
examples/settings_list.rs (lines 29-68)
18fn main() {
19 gtk::Application::builder()
20 .application_id("org.relm4.SettingsListExample")
21 .launch(|_app, window| {
22 // Initialize a component's root widget
23 let mut component = App::builder()
24 // Attach the root widget to the given window.
25 .attach_to(&window)
26 // Start the component service with an initial parameter
27 .launch("Settings List Demo".into())
28 // Attach the returned receiver's messages to this closure.
29 .connect_receiver(move |sender, message| match message {
30 Output::Clicked(id) => {
31 eprintln!("ID {id} Clicked");
32
33 match id {
34 0 => xdg_open("https://github.com/Relm4/Relm4".into()),
35 1 => xdg_open("https://docs.rs/relm4/".into()),
36 2 => {
37 sender.send(Input::Clear).unwrap();
38 }
39 _ => (),
40 }
41 }
42
43 Output::Reload => {
44 sender
45 .send(Input::AddSetting {
46 description: "Browse GitHub Repository".into(),
47 button: "GitHub".into(),
48 id: 0,
49 })
50 .unwrap();
51
52 sender
53 .send(Input::AddSetting {
54 description: "Browse Documentation".into(),
55 button: "Docs".into(),
56 id: 1,
57 })
58 .unwrap();
59
60 sender
61 .send(Input::AddSetting {
62 description: "Clear List".into(),
63 button: "Clear".into(),
64 id: 2,
65 })
66 .unwrap();
67 }
68 });
69
70 // Keep runtime alive after the component is dropped
71 component.detach_runtime();
72
73 println!("parent is {:?}", component.widget().toplevel_window());
74 });
75}
Sourcepub fn detach(self) -> Controller<C>
pub fn detach(self) -> Controller<C>
Ignore outputs from the component and finish the builder.
Sourcepub fn into_stream(self) -> ComponentStream<C>
pub fn into_stream(self) -> ComponentStream<C>
Convert his type into a Stream
that yields output events
as futures.
Examples found in repository?
examples/message_stream.rs (line 149)
141 fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, root: &Self::Root) {
142 match msg {
143 AppMsg::StartSearch => {
144 self.searching = true;
145
146 let stream = Dialog::builder()
147 .transient_for(root)
148 .launch(())
149 .into_stream();
150 sender.oneshot_command(async move {
151 // Use the component as stream
152 let result = stream.recv_one().await;
153
154 if let Some(search) = result {
155 let response =
156 reqwest::get(format!("https://duckduckgo.com/lite/?q={search}"))
157 .await
158 .unwrap();
159 let response_text = response.text().await.unwrap();
160
161 // Extract the url of the first search result.
162 if let Some(url) = response_text.split("<a rel=\"nofollow\" href=\"").nth(1)
163 {
164 let url = url.split('\"').next().unwrap().replace("amp;", "");
165 Some(format!("https:{url}"))
166 } else {
167 None
168 }
169 } else {
170 None
171 }
172 });
173 }
174 }
175 }
Trait Implementations§
Source§impl<C: Component> ComponentController<C> for Connector<C>
impl<C: Component> ComponentController<C> for Connector<C>
Source§fn state(&self) -> &StateWatcher<C>
fn state(&self) -> &StateWatcher<C>
Provides access to the state of a component.
Source§fn detach_runtime(&mut self)
fn detach_runtime(&mut self)
Dropping this type will usually stop the runtime of the component.
With this method you can give the runtime a static lifetime.
In other words, dropping the controller or connector will not stop
the runtime anymore, instead it will run until the app is closed.
Auto Trait Implementations§
impl<C> Freeze for Connector<C>
impl<C> !RefUnwindSafe for Connector<C>
impl<C> !Send for Connector<C>
impl<C> !Sync for Connector<C>
impl<C> Unpin for Connector<C>
impl<C> !UnwindSafe for Connector<C>
Blanket Implementations§
Source§impl<C> AsyncPosition<()> for C
impl<C> AsyncPosition<()> for C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more