pub trait Component: Sized + 'static {
type CommandOutput: Debug + Send + 'static;
type Input: Debug + 'static;
type Output: Debug + 'static;
type Init;
type Root: Debug + Clone;
type Widgets: 'static;
// Required methods
fn init_root() -> Self::Root;
fn init(
init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self>;
// Provided methods
fn builder() -> ComponentBuilder<Self> { ... }
fn update(
&mut self,
message: Self::Input,
sender: ComponentSender<Self>,
root: &Self::Root,
) { ... }
fn update_cmd(
&mut self,
message: Self::CommandOutput,
sender: ComponentSender<Self>,
root: &Self::Root,
) { ... }
fn update_cmd_with_view(
&mut self,
widgets: &mut Self::Widgets,
message: Self::CommandOutput,
sender: ComponentSender<Self>,
root: &Self::Root,
) { ... }
fn update_view(
&self,
widgets: &mut Self::Widgets,
sender: ComponentSender<Self>,
) { ... }
fn update_with_view(
&mut self,
widgets: &mut Self::Widgets,
message: Self::Input,
sender: ComponentSender<Self>,
root: &Self::Root,
) { ... }
fn shutdown(
&mut self,
widgets: &mut Self::Widgets,
output: Sender<Self::Output>,
) { ... }
fn id(&self) -> String { ... }
}Expand description
The fundamental building block of a Relm4 application.
A Component is an element of an application that defines initialization, state, behavior and
communication as a modular unit.
Component is powerful and flexible, but for many use-cases the SimpleComponent
convenience trait will suffice. SimpleComponent enforces separation between model and view
updates, and provides no-op implementations for advanced features that are not relevant for most
use-cases.
Required Associated Types§
Sourcetype CommandOutput: Debug + Send + 'static
type CommandOutput: Debug + Send + 'static
Messages which are received from commands executing in the background.
Required Methods§
Sourcefn init(
init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self>
fn init( init: Self::Init, root: Self::Root, sender: ComponentSender<Self>, ) -> ComponentParts<Self>
Creates the initial model and view, docking it into the component.
Provided Methods§
Sourcefn builder() -> ComponentBuilder<Self>
fn builder() -> ComponentBuilder<Self>
Create a builder for this component.
Examples found in repository?
88 fn init(
89 _: Self::Init,
90 root: Self::Root,
91 sender: ComponentSender<Self>,
92 ) -> ComponentParts<Self> {
93 let model = App {
94 counter: 0,
95 worker: AsyncHandler::builder()
96 .detach_worker(())
97 .forward(sender.input_sender(), identity),
98 };
99
100 let widgets = view_output!();
101
102 ComponentParts { model, widgets }
103 }More examples
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 }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 }71 fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
72 match msg {
73 Msg::Increment => {
74 self.counter = self.counter.wrapping_add(1);
75 }
76 Msg::Decrement => {
77 self.counter = self.counter.wrapping_sub(1);
78 }
79 Msg::NewWindow => {
80 let app = relm4::main_application();
81 let builder = Self::builder();
82
83 // Add window to the GTK application.
84 // This ensures that the app will live as long
85 // as at least one window exists.
86 app.add_window(&builder.root);
87
88 builder.launch(self.counter).detach_runtime();
89 }
90 }
91 }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 }88 fn init(
89 init: Self::Init,
90 root: Self::Root,
91 sender: ComponentSender<Self>,
92 ) -> ComponentParts<Self> {
93 let counter = CounterModel::builder()
94 .launch(init.0)
95 .forward(sender.input_sender(), identity);
96 let toggler = TogglerModel::builder()
97 .launch(init.1)
98 .forward(sender.input_sender(), identity);
99
100 let widgets = view_output!();
101
102 let model = App {
103 _counter: counter,
104 _toggler: toggler,
105 };
106
107 widgets.stack.connect_visible_child_notify({
108 let split_view = widgets.split_view.clone();
109 move |_| {
110 split_view.set_show_content(true);
111 }
112 });
113
114 ComponentParts { model, widgets }
115 }Sourcefn update(
&mut self,
message: Self::Input,
sender: ComponentSender<Self>,
root: &Self::Root,
)
fn update( &mut self, message: Self::Input, sender: ComponentSender<Self>, root: &Self::Root, )
Processes inputs received by the component.
Sourcefn update_cmd(
&mut self,
message: Self::CommandOutput,
sender: ComponentSender<Self>,
root: &Self::Root,
)
fn update_cmd( &mut self, message: Self::CommandOutput, sender: ComponentSender<Self>, root: &Self::Root, )
Defines how the component should respond to command updates.
Sourcefn update_cmd_with_view(
&mut self,
widgets: &mut Self::Widgets,
message: Self::CommandOutput,
sender: ComponentSender<Self>,
root: &Self::Root,
)
fn update_cmd_with_view( &mut self, widgets: &mut Self::Widgets, message: Self::CommandOutput, sender: ComponentSender<Self>, root: &Self::Root, )
Updates the model and view upon completion of a command.
Overriding this method is helpful if you need access to the widgets while processing a command output.
The default implementation of this method calls update_cmd followed by update_view.
If you override this method while using the component macro, you must remember to call
update_view in your implementation. Otherwise, the view will not reflect the updated
model.
Sourcefn update_view(
&self,
widgets: &mut Self::Widgets,
sender: ComponentSender<Self>,
)
fn update_view( &self, widgets: &mut Self::Widgets, sender: ComponentSender<Self>, )
Updates the view after the model has been updated.
Sourcefn update_with_view(
&mut self,
widgets: &mut Self::Widgets,
message: Self::Input,
sender: ComponentSender<Self>,
root: &Self::Root,
)
fn update_with_view( &mut self, widgets: &mut Self::Widgets, message: Self::Input, sender: ComponentSender<Self>, root: &Self::Root, )
Updates the model and view when a new input is received.
Overriding this method is helpful if you need access to the widgets while processing an input.
The default implementation of this method calls update followed by update_view. If
you override this method while using the component macro, you must remember to
call update_view in your implementation. Otherwise, the view will not reflect the
updated model.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.