Struct relm4::component::ComponentBuilder
source · pub struct ComponentBuilder<C: Component> {
pub root: C::Root,
/* private fields */
}
Expand description
A component that is ready for docking and launch.
Fields§
§root: C::Root
The root widget of the component.
Implementations§
source§impl<C: Component> ComponentBuilder<C>
impl<C: Component> ComponentBuilder<C>
sourcepub fn update_root<F: FnOnce(&mut C::Root)>(self, func: F) -> Self
pub fn update_root<F: FnOnce(&mut C::Root)>(self, func: F) -> Self
Configure the root widget before launching.
sourcepub const fn widget(&self) -> &C::Root
pub const fn widget(&self) -> &C::Root
Access the root widget before the component is initialized.
sourcepub fn priority(self, priority: Priority) -> Self
pub fn priority(self, priority: Priority) -> Self
Change the priority at which the messages of this component are handled.
- Use
glib::Priority::HIGH
for high priority event sources. - Use
glib::Priority::LOW
for very low priority background tasks. - Use
glib::Priority::DEFAULT_IDLE
for default priority idle functions. - Use
glib::Priority::HIGH_IDLE
for high priority idle functions.
source§impl<C: Component> ComponentBuilder<C>
impl<C: Component> ComponentBuilder<C>
sourcepub fn attach_to<T: RelmContainerExt<Child = Widget>>(
self,
container: &T
) -> Self
pub fn attach_to<T: RelmContainerExt<Child = Widget>>( self, container: &T ) -> Self
Attach the component’s root widget to a given container.
Examples found in repository?
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
fn main() {
gtk::Application::builder()
.application_id("org.relm4.SettingsListExample")
.launch(|_app, window| {
// Initialize a component's root widget
let mut component = App::builder()
// Attach the root widget to the given window.
.attach_to(&window)
// Start the component service with an initial parameter
.launch("Settings List Demo".into())
// Attach the returned receiver's messages to this closure.
.connect_receiver(move |sender, message| match message {
Output::Clicked(id) => {
eprintln!("ID {id} Clicked");
match id {
0 => xdg_open("https://github.com/Relm4/Relm4".into()),
1 => xdg_open("https://docs.rs/relm4/".into()),
2 => {
sender.send(Input::Clear).unwrap();
}
_ => (),
}
}
Output::Reload => {
sender
.send(Input::AddSetting {
description: "Browse GitHub Repository".into(),
button: "GitHub".into(),
id: 0,
})
.unwrap();
sender
.send(Input::AddSetting {
description: "Browse Documentation".into(),
button: "Docs".into(),
id: 1,
})
.unwrap();
sender
.send(Input::AddSetting {
description: "Clear List".into(),
button: "Clear".into(),
id: 2,
})
.unwrap();
}
});
// Keep runtime alive after the component is dropped
component.detach_runtime();
println!("parent is {:?}", component.widget().toplevel_window());
});
}
source§impl<C: Component> ComponentBuilder<C>
impl<C: Component> ComponentBuilder<C>
sourcepub fn transient_for(self, widget: impl AsRef<Widget>) -> Self
pub fn transient_for(self, widget: impl AsRef<Widget>) -> Self
Set the component’s root widget transient for a given window.
This function doesn’t require a gtk::Window
as parameter,
but instead uses RelmWidgetExt::toplevel_window()
to retrieve the toplevel
window of any gtk::Widget
.
Therefore, you don’t have to pass a window to every component.
If the root widget is a native dialog, such as gtk::FileChooserNative
,
you should use transient_for_native
instead.
Examples found in repository?
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
// We don't have access to the parent window from here
// but we can just use the button to set the transient window for the dialog.
// Relm4 will get the window later by calling [`WidgetExt::root()`]
// on the button once all widgets are connected.
let dialog = Dialog::builder()
.transient_for(&root)
.launch_with_broker((), &DIALOG_BROKER)
.forward(sender.input_sender(), identity);
let model = Button { dialog };
let widgets = view_output!();
ComponentParts { model, widgets }
}
More examples
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
fn init(
_: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let header = Header::builder()
.launch(())
.forward(sender.input_sender(), identity);
let dialog = Dialog::builder()
.transient_for(&root)
.launch(DialogInit {
text: "Do you want to close before saving?".to_string(),
secondary_text: Some("All unsaved changes will be lost".to_string()),
accept_text: "Close".to_string(),
cancel_text: "Cancel".to_string(),
})
.forward(sender.input_sender(), identity);
let model = App {
mode: AppMode::View,
header,
dialog,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, root: &Self::Root) {
match msg {
AppMsg::StartSearch => {
self.searching = true;
let stream = Dialog::builder()
.transient_for(root)
.launch(())
.into_stream();
sender.oneshot_command(async move {
// Use the component as stream
let result = stream.recv_one().await;
if let Some(search) = result {
let response =
reqwest::get(format!("https://duckduckgo.com/lite/?q={search}"))
.await
.unwrap();
let response_text = response.text().await.unwrap();
// Extract the url of the first search result.
if let Some(url) = response_text.split("<a rel=\"nofollow\" href=\"").nth(1)
{
let url = url.split('\"').next().unwrap().replace("amp;", "");
Some(format!("https:{url}"))
} else {
None
}
} else {
None
}
});
}
}
}
source§impl<C: Component> ComponentBuilder<C>
impl<C: Component> ComponentBuilder<C>
sourcepub fn transient_for_native(self, widget: impl AsRef<Widget>) -> Self
pub fn transient_for_native(self, widget: impl AsRef<Widget>) -> Self
Set the component’s root widget transient for a given window.
This function doesn’t require a gtk::Window
as parameter,
but instead uses RelmWidgetExt::toplevel_window()
to retrieve the toplevel
window of any gtk::Widget
.
Therefore, you don’t have to pass a window to every component.
Applicable to native dialogs only, such as gtk::FileChooserNative
.
If the root widget is a non-native dialog,
you should use transient_for
instead.
source§impl<C: Component> ComponentBuilder<C>
impl<C: Component> ComponentBuilder<C>
sourcepub fn launch(self, payload: C::Init) -> Connector<C>
pub fn launch(self, payload: C::Init) -> Connector<C>
Starts the component, passing ownership to a future attached to a gtk::glib::MainContext.
Examples found in repository?
143 144 145 146 147 148 149 150 151 152 153 154
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let button = Button::builder()
.launch(())
.forward(sender.input_sender(), identity);
let model = App { button };
let widgets = view_output!();
ComponentParts { model, widgets }
}
More examples
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let header = Header::builder()
.launch_with_broker((), &HEADER_BROKER)
.forward(sender.input_sender(), identity);
let dialog = Dialog::builder()
.launch(root.clone().upcast())
.forward(sender.input_sender(), identity);
let model = App {
mode: AppMode::View,
header,
dialog,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
fn init(
_: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let header = Header::builder()
.launch(())
.forward(sender.input_sender(), identity);
let dialog = Dialog::builder()
.transient_for(&root)
.launch(DialogInit {
text: "Do you want to close before saving?".to_string(),
secondary_text: Some("All unsaved changes will be lost".to_string()),
accept_text: "Close".to_string(),
cancel_text: "Cancel".to_string(),
})
.forward(sender.input_sender(), identity);
let model = App {
mode: AppMode::View,
header,
dialog,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
fn update(&mut self, msg: Self::Input, sender: ComponentSender<Self>, root: &Self::Root) {
match msg {
AppMsg::StartSearch => {
self.searching = true;
let stream = Dialog::builder()
.transient_for(root)
.launch(())
.into_stream();
sender.oneshot_command(async move {
// Use the component as stream
let result = stream.recv_one().await;
if let Some(search) = result {
let response =
reqwest::get(format!("https://duckduckgo.com/lite/?q={search}"))
.await
.unwrap();
let response_text = response.text().await.unwrap();
// Extract the url of the first search result.
if let Some(url) = response_text.split("<a rel=\"nofollow\" href=\"").nth(1)
{
let url = url.split('\"').next().unwrap().replace("amp;", "");
Some(format!("https:{url}"))
} else {
None
}
} else {
None
}
});
}
}
}
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
fn main() {
gtk::Application::builder()
.application_id("org.relm4.SettingsListExample")
.launch(|_app, window| {
// Initialize a component's root widget
let mut component = App::builder()
// Attach the root widget to the given window.
.attach_to(&window)
// Start the component service with an initial parameter
.launch("Settings List Demo".into())
// Attach the returned receiver's messages to this closure.
.connect_receiver(move |sender, message| match message {
Output::Clicked(id) => {
eprintln!("ID {id} Clicked");
match id {
0 => xdg_open("https://github.com/Relm4/Relm4".into()),
1 => xdg_open("https://docs.rs/relm4/".into()),
2 => {
sender.send(Input::Clear).unwrap();
}
_ => (),
}
}
Output::Reload => {
sender
.send(Input::AddSetting {
description: "Browse GitHub Repository".into(),
button: "GitHub".into(),
id: 0,
})
.unwrap();
sender
.send(Input::AddSetting {
description: "Browse Documentation".into(),
button: "Docs".into(),
id: 1,
})
.unwrap();
sender
.send(Input::AddSetting {
description: "Clear List".into(),
button: "Clear".into(),
id: 2,
})
.unwrap();
}
});
// Keep runtime alive after the component is dropped
component.detach_runtime();
println!("parent is {:?}", component.widget().toplevel_window());
});
}
sourcepub fn launch_with_broker(
self,
payload: C::Init,
broker: &MessageBroker<C::Input>
) -> Connector<C>
pub fn launch_with_broker( self, payload: C::Init, broker: &MessageBroker<C::Input> ) -> Connector<C>
Similar to launch()
but also initializes a MessageBroker
.
§Panics
This method panics if the message broker was already initialized in another launch.
Examples found in repository?
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let header = Header::builder()
.launch_with_broker((), &HEADER_BROKER)
.forward(sender.input_sender(), identity);
let dialog = Dialog::builder()
.launch(root.clone().upcast())
.forward(sender.input_sender(), identity);
let model = App {
mode: AppMode::View,
header,
dialog,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
More examples
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
// We don't have access to the parent window from here
// but we can just use the button to set the transient window for the dialog.
// Relm4 will get the window later by calling [`WidgetExt::root()`]
// on the button once all widgets are connected.
let dialog = Dialog::builder()
.transient_for(&root)
.launch_with_broker((), &DIALOG_BROKER)
.forward(sender.input_sender(), identity);
let model = Button { dialog };
let widgets = view_output!();
ComponentParts { model, widgets }
}
source§impl<C> ComponentBuilder<C>
impl<C> ComponentBuilder<C>
sourcepub fn detach_worker(self, payload: C::Init) -> WorkerHandle<C>
pub fn detach_worker(self, payload: C::Init) -> WorkerHandle<C>
Starts a worker on a separate thread, passing ownership to a future attached to a gtk::glib::MainContext.
Examples found in repository?
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
fn init(
_: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = App {
counter: 0,
worker: AsyncHandler::builder()
.detach_worker(())
.forward(sender.input_sender(), identity),
};
let widgets = view_output!();
ComponentParts { model, widgets }
}