Struct Connector

Source
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>

Source

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
Hide additional 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    }
Source

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}
Source

pub fn detach(self) -> Controller<C>

Ignore outputs from the component and finish the builder.

Source

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>

Source§

fn sender(&self) -> &Sender<C::Input>

Provides access to the component’s sender.
Source§

fn state(&self) -> &StateWatcher<C>

Provides access to the state of a component.
Source§

fn widget(&self) -> &C::Root

Returns the root widget of the component.
Source§

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.
Source§

fn emit(&self, event: C::Input)

Emits an input to the component.
Source§

fn model(&self) -> Ref<'_, C>

Returns a reference to the Component.
Source§

fn widgets(&self) -> Ref<'_, C::Widgets>

Returns a reference to the Component::Widgets.
Source§

impl<C> Debug for Connector<C>
where C: Component + Debug, C::Widgets: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<C> Freeze for Connector<C>
where <C as Component>::Root: Freeze,

§

impl<C> !RefUnwindSafe for Connector<C>

§

impl<C> !Send for Connector<C>

§

impl<C> !Sync for Connector<C>

§

impl<C> Unpin for Connector<C>
where <C as Component>::Root: Unpin,

§

impl<C> !UnwindSafe for Connector<C>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<C> AsyncPosition<()> for C

Source§

fn position(_index: usize)

Returns the position. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<C, I> Position<(), I> for C

Source§

fn position(&self, _index: &I)

Returns the position. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more