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>where
C::Root: AsRef<Widget>,
impl<C: Component> ComponentBuilder<C>where C::Root: AsRef<Widget>,
sourcepub fn attach_to(self, container: &impl RelmContainerExt) -> Self
pub fn attach_to(self, container: &impl RelmContainerExt) -> 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
fn main() {
gtk::Application::builder()
.application_id("org.relm4.SettingsListExample")
.launch(|_app, window| {
// Initialize a component's root widget
let 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();
}
});
println!("parent is {:?}", component.widget().toplevel_window());
});
}
source§impl<C: Component> ComponentBuilder<C>where
C::Root: AsRef<Window> + Clone,
impl<C: Component> ComponentBuilder<C>where C::Root: AsRef<Window> + Clone,
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?
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
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 }
}
137 138 139 140 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
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
}
});
}
}
}
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
fn init(
_: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = App {
counter: 0,
alert_toggle: false,
dialog: Alert::builder()
.transient_for(root)
.launch(AlertSettings {
text: String::from("Do you want to quit without saving? (First alert)"),
secondary_text: Some(String::from("Your counter hasn't reached 42 yet")),
confirm_label: String::from("Close without saving"),
cancel_label: String::from("Cancel"),
option_label: Some(String::from("Save")),
is_modal: true,
destructive_accept: true,
})
.forward(sender.input_sender(), convert_alert_response),
second_dialog: Alert::builder()
.transient_for(root)
.launch(AlertSettings {
text: String::from("Do you want to quit without saving? (Second alert)"),
secondary_text: Some(String::from("Your counter hasn't reached 42 yet")),
confirm_label: String::from("Close without saving"),
cancel_label: String::from("Cancel"),
option_label: Some(String::from("Save")),
is_modal: true,
destructive_accept: true,
})
.forward(sender.input_sender(), convert_alert_response),
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
source§impl<C: Component> ComponentBuilder<C>where
C::Root: AsRef<NativeDialog> + Clone,
impl<C: Component> ComponentBuilder<C>where C::Root: AsRef<NativeDialog> + Clone,
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.
Examples found in repository?
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
fn init(
_: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let open_dialog = OpenDialog::builder()
.transient_for_native(root)
.launch(OpenDialogSettings::default())
.forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => Input::OpenResponse(path),
OpenDialogResponse::Cancel => Input::Ignore,
});
let save_dialog = SaveDialog::builder()
.transient_for_native(root)
.launch(SaveDialogSettings::default())
.forward(sender.input_sender(), |response| match response {
SaveDialogResponse::Accept(path) => Input::SaveResponse(path),
SaveDialogResponse::Cancel => Input::Ignore,
});
let model = App {
open_dialog,
save_dialog,
buffer: gtk::TextBuffer::new(None),
file_name: None,
message: None,
};
let widgets = view_output!();
sender.input(Input::ShowMessage(String::from(
"A simple text editor showing the usage of\n<b>OpenFileDialog</b> and <b>SaveFileDialog</b> components.\n\nStart by clicking <b>Open</b> on the header bar.",
)));
ComponentParts { model, widgets }
}
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?
138 139 140 141 142 143 144 145 146 147 148 149
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
66 67 68 69 70 71 72 73 74 75 76 77 78
fn init(
_: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let image = WebImage::builder().launch(IMAGES[0].to_owned()).detach();
let model = App { image, idx: 0 };
let image = model.image.widget();
let widgets = view_output!();
ComponentParts { model, widgets }
}
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
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 }
}
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
fn init(
_: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let open_button = OpenButton::builder()
.launch(OpenButtonSettings {
dialog_settings: OpenDialogSettings::default(),
text: "Open file",
recently_opened_files: Some(".recent_files"),
max_recent_files: 10,
})
.forward(sender.input_sender(), AppMsg::Open);
let model = App { open_button };
let widgets = view_output!();
ComponentParts { model, widgets }
}
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
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 }
}
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
fn init(
_: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let open_dialog = OpenDialog::builder()
.transient_for_native(root)
.launch(OpenDialogSettings::default())
.forward(sender.input_sender(), |response| match response {
OpenDialogResponse::Accept(path) => Input::OpenResponse(path),
OpenDialogResponse::Cancel => Input::Ignore,
});
let save_dialog = SaveDialog::builder()
.transient_for_native(root)
.launch(SaveDialogSettings::default())
.forward(sender.input_sender(), |response| match response {
SaveDialogResponse::Accept(path) => Input::SaveResponse(path),
SaveDialogResponse::Cancel => Input::Ignore,
});
let model = App {
open_dialog,
save_dialog,
buffer: gtk::TextBuffer::new(None),
file_name: None,
message: None,
};
let widgets = view_output!();
sender.input(Input::ShowMessage(String::from(
"A simple text editor showing the usage of\n<b>OpenFileDialog</b> and <b>SaveFileDialog</b> components.\n\nStart by clicking <b>Open</b> on the header bar.",
)));
ComponentParts { model, widgets }
}
sourcepub fn launch_with_broker(
self,
payload: C::Init,
broker: &MessageBroker<C>
) -> Connector<C>
pub fn launch_with_broker( self, payload: C::Init, broker: &MessageBroker<C> ) -> 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?
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
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
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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>where
C: Component<Root = (), Widgets = ()> + Send,
C::Input: Send,
C::Output: Send,
C::CommandOutput: Send,
impl<C> ComponentBuilder<C>where C: Component<Root = (), Widgets = ()> + Send, C::Input: Send, C::Output: Send, C::CommandOutput: Send,
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 }
}