1use crate::Action;
3use crate::core::event;
4use crate::core::layout::{self, Layout};
5use crate::core::mouse;
6use crate::core::overlay;
7use crate::core::renderer;
8use crate::core::shell;
9use crate::core::widget;
10use crate::core::widget::tree::{self, Tree};
11use crate::core::window;
12use crate::core::{self, Element, Event, Length, Rectangle, Shell, Size, Vector, Widget};
13
14use std::cell::{Cell, RefCell};
15
16pub trait Component<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
43where
44 Renderer: core::Renderer,
45{
46 type State: Default + 'static;
48
49 type Event: 'static;
51
52 fn update(
56 &self,
57 state: &mut Self::State,
58 event: Self::Event,
59 renderer: &Renderer,
60 ) -> Option<Message>;
61
62 fn view(&self, state: &Self::State) -> impl crate::Widget<Self::Event, Theme, Renderer> + 'a;
65
66 fn listen(
73 &self,
74 _state: &Self::State,
75 _event: &Event,
76 _bounds: Rectangle,
77 _cursor: mouse::Cursor,
78 ) -> Action<Self::Event> {
79 Action::none()
80 }
81
82 fn mouse_interaction(&self, _state: &Self::State) -> mouse::Interaction {
89 mouse::Interaction::None
90 }
91
92 fn diff(&mut self, _state: &mut Self::State) {}
100
101 fn operate(
105 &self,
106 _state: &mut Self::State,
107 _bounds: Rectangle,
108 _operation: &mut dyn widget::Operation,
109 ) {
110 }
111}
112
113pub fn component<'a, C, Message, Theme, Renderer>(
116 component: C,
117) -> impl Widget<Message, Theme, Renderer> + 'a
118where
119 C: Component<'a, Message, Theme, Renderer> + 'a,
120 C::State: 'static,
121 Message: 'a,
122 Theme: 'a,
123 Renderer: core::Renderer + 'a,
124{
125 Instance {
126 component,
127 view: crate::space()._boxed(),
128 limits: layout::Limits::new(Size::ZERO, Size::INFINITE),
129 is_outdated: Cell::new(true),
130 has_overlay: false,
131 }
132}
133
134struct Instance<'a, C, Message, Theme, Renderer>
135where
136 C: Component<'a, Message, Theme, Renderer> + 'a,
137 Renderer: core::Renderer,
138{
139 component: C,
140 view: Element<'a, C::Event, Theme, Renderer>,
141 limits: layout::Limits,
142 is_outdated: Cell<bool>,
143 has_overlay: bool,
144}
145
146struct Internal<State, Event> {
147 state: State,
148 events: shell::Bus<Event>,
149}
150
151impl<'a, C, Message, Theme, Renderer> widget::Meta for Instance<'a, C, Message, Theme, Renderer>
152where
153 C: Component<'a, Message, Theme, Renderer> + 'a,
154 Renderer: core::Renderer,
155{
156}
157
158impl<'a, C, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
159 for Instance<'a, C, Message, Theme, Renderer>
160where
161 C: Component<'a, Message, Theme, Renderer> + 'a,
162 Renderer: core::Renderer,
163{
164 fn tag(&self) -> tree::Tag {
165 tree::Tag::of::<RefCell<Internal<C::State, C::Event>>>()
166 }
167
168 fn state(&self) -> tree::State {
169 tree::State::new(RefCell::new(Internal {
170 state: C::State::default(),
171 events: shell::Bus::<C::Event>::new(),
172 }))
173 }
174
175 fn diff(&mut self, tree: &mut Tree) {
176 let mut internal = tree
177 .state
178 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
179 .borrow_mut();
180
181 self.component.diff(&mut internal.state);
182
183 if self.is_outdated.get() {
184 self.view = self.component.view(&internal.state)._boxed();
185 drop(internal);
186
187 tree.diff_children(std::slice::from_mut(&mut self.view));
188
189 self.is_outdated.set(false);
190 }
191 }
192
193 fn size(&self) -> Size<Length> {
194 self.view.size()
195 }
196
197 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
198 if &self.limits != limits {
199 self.limits = *limits;
200 self.view.layout(&mut tree.children[0], renderer, limits);
201 }
202
203 tree.size = tree.children[0].size;
204 }
205
206 fn update(
207 &mut self,
208 tree: &mut Tree,
209 event: &Event,
210 layout: Layout,
211 cursor: mouse::Cursor,
212 renderer: &Renderer,
213 shell: &mut Shell<'_, Message>,
214 viewport: &Rectangle,
215 ) {
216 let mut internal = tree
217 .state
218 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
219 .borrow_mut();
220
221 let action = self
222 .component
223 .listen(&internal.state, event, layout.bounds(), cursor);
224
225 let (publish, redraw_request, event_status) = action.into_inner();
226
227 shell.request_redraw_at(redraw_request);
228
229 if let event::Status::Captured = event_status {
230 shell.capture_event();
231 }
232
233 if let Some(event) = publish {
234 let _ = internal.events.push(event);
235 }
236
237 let mut invalidation = shell::Invalidation::None;
238
239 if !shell.is_event_captured() {
240 let mut local_shell = shell.local(&mut internal.events);
241
242 self.view.update(
243 &mut tree.children[0],
244 event,
245 layout,
246 cursor,
247 renderer,
248 &mut local_shell,
249 viewport,
250 );
251
252 if local_shell.is_event_captured() {
253 shell.capture_event();
254 }
255
256 shell.request_redraw_at(local_shell.redraw_request());
257 shell.request_input_method(local_shell.input_method());
258 shell.clipboard_mut().merge(local_shell.clipboard_mut());
259
260 invalidation = local_shell.invalidation();
261 }
262
263 if internal.events.is_empty() && matches!(invalidation, shell::Invalidation::None) {
264 return;
265 }
266
267 let Internal { state, events } = &mut *internal;
268
269 for (event, receipt) in events.drain() {
270 if let Some(message) = self.component.update(state, event, renderer) {
271 shell.forward(message, receipt);
272 }
273 }
274
275 let previous_sizing = self.view.size();
276
277 self.view = self.component.view(state)._boxed();
278 drop(internal);
279
280 tree.diff_children(std::slice::from_mut(&mut self.view));
281
282 let previous_size = tree.size;
283
284 self.view
285 .layout(&mut tree.children[0], renderer, &self.limits);
286
287 tree.size = tree.children[0].size;
288
289 let new_sizing = self.view.size();
290
291 if new_sizing != previous_sizing {
300 shell.invalidate_widgets();
301 } else if (new_sizing.width.fill_factor() == 0 || new_sizing.height.fill_factor() == 0)
302 && previous_size != tree.size
303 {
304 shell.invalidate_layout();
305 } else {
306 shell.invalidate_overlay();
307 }
308
309 self.is_outdated.set(false);
310
311 if let Event::Window(window::Event::RedrawRequested(_)) = event {
312 let mut internal = tree
313 .state
314 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
315 .borrow_mut();
316
317 let mut local_shell = shell.local(&mut internal.events);
318
319 self.view.update(
320 &mut tree.children[0],
321 event,
322 layout,
323 cursor,
324 renderer,
325 &mut local_shell,
326 viewport,
327 );
328
329 if internal.events.is_empty() {
330 return;
331 }
332 }
333
334 shell.request_redraw();
335 }
336
337 fn draw(
338 &self,
339 tree: &Tree,
340 renderer: &mut Renderer,
341 theme: &Theme,
342 style: &renderer::Style,
343 layout: Layout,
344 cursor: mouse::Cursor,
345 viewport: &Rectangle,
346 ) {
347 self.view.draw(
348 &tree.children[0],
349 renderer,
350 theme,
351 style,
352 layout,
353 cursor,
354 viewport,
355 );
356 }
357
358 fn mouse_interaction(
359 &self,
360 tree: &Tree,
361 layout: Layout,
362 cursor: mouse::Cursor,
363 viewport: &Rectangle,
364 renderer: &Renderer,
365 ) -> mouse::Interaction {
366 let internal = tree
367 .state
368 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>()
369 .borrow();
370
371 let interaction = self.component.mouse_interaction(&internal.state);
372
373 if interaction != mouse::Interaction::None {
374 return interaction;
375 }
376
377 self.view
378 .mouse_interaction(&tree.children[0], layout, cursor, viewport, renderer)
379 }
380
381 fn operate(
382 &mut self,
383 tree: &mut Tree,
384 layout: Layout,
385 viewport: &Rectangle,
386 renderer: &Renderer,
387 operation: &mut dyn widget::Operation,
388 ) {
389 {
390 let internal = tree
391 .state
392 .downcast_mut::<RefCell<Internal<C::State, C::Event>>>()
393 .get_mut();
394
395 self.component
396 .operate(&mut internal.state, layout.bounds(), operation);
397 }
398
399 self.view
400 .operate(&mut tree.children[0], layout, viewport, renderer, operation);
401 }
402
403 fn overlay<'b>(
404 &'b mut self,
405 tree: &'b mut Tree,
406 layout: Layout,
407 renderer: &Renderer,
408 viewport: &Rectangle,
409 translation: Vector,
410 window: Size,
411 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
412 let overlays = self.view.overlay(
413 &mut tree.children[0],
414 layout,
415 renderer,
416 viewport,
417 translation,
418 window,
419 );
420
421 self.has_overlay = !overlays.is_empty();
422
423 let internal = tree
424 .state
425 .downcast_ref::<RefCell<Internal<C::State, C::Event>>>();
426
427 overlays
428 .into_iter()
429 .map(|raw| {
430 overlay::Element::new(Box::new(Overlay {
431 component: &self.component,
432 internal,
433 is_outdated: &self.is_outdated,
434 raw,
435 }))
436 })
437 .collect()
438 }
439}
440
441struct Overlay<'a, 'b, C, Message, Theme, Renderer>
442where
443 C: Component<'a, Message, Theme, Renderer>,
444 Renderer: core::Renderer,
445{
446 component: &'b C,
447 internal: &'b RefCell<Internal<C::State, C::Event>>,
448 is_outdated: &'b Cell<bool>,
449 raw: overlay::Element<'b, C::Event, Theme, Renderer>,
450}
451
452impl<'a, 'b, C, Message, Theme, Renderer> overlay::Overlay<Message, Theme, Renderer>
453 for Overlay<'a, 'b, C, Message, Theme, Renderer>
454where
455 C: Component<'a, Message, Theme, Renderer>,
456 Renderer: core::Renderer,
457{
458 fn update(
459 &mut self,
460 event: &Event,
461 cursor: mouse::Cursor,
462 renderer: &Renderer,
463 shell: &mut Shell<'_, Message>,
464 ) {
465 let mut internal = self.internal.borrow_mut();
466 let mut local_shell = shell.local(&mut internal.events);
467
468 self.raw
469 .as_overlay_mut()
470 .update(event, cursor, renderer, &mut local_shell);
471
472 if local_shell.is_event_captured() {
473 shell.capture_event();
474 }
475
476 shell.invalidate(local_shell.invalidation());
477 shell.request_redraw_at(local_shell.redraw_request());
478 shell.request_input_method(local_shell.input_method());
479 shell.clipboard_mut().merge(local_shell.clipboard_mut());
480
481 if internal.events.is_empty() {
482 return;
483 }
484
485 let Internal { state, events } = &mut *internal;
486
487 for (event, receipt) in events.drain() {
488 if let Some(message) = self.component.update(state, event, renderer) {
489 shell.forward(message, receipt);
490 }
491 }
492
493 self.is_outdated.set(true);
494
495 shell.invalidate_layout();
496 shell.request_redraw();
497 }
498
499 fn draw(
500 &self,
501 renderer: &mut Renderer,
502 theme: &Theme,
503 style: &renderer::Style,
504 cursor: mouse::Cursor,
505 ) {
506 self.raw.as_overlay().draw(renderer, theme, style, cursor);
507 }
508
509 fn mouse_interaction(&self, cursor: mouse::Cursor, renderer: &Renderer) -> mouse::Interaction {
510 self.raw.as_overlay().mouse_interaction(cursor, renderer)
511 }
512
513 fn index(&self) -> f32 {
514 self.raw.as_overlay().index()
515 }
516
517 fn operate(&mut self, renderer: &Renderer, operation: &mut dyn widget::Operation) {
518 self.raw.as_overlay_mut().operate(renderer, operation);
519 }
520
521 fn overlay<'c>(
522 &'c mut self,
523 renderer: &Renderer,
524 ) -> Vec<overlay::Element<'c, Message, Theme, Renderer>> {
525 let overlays = self.raw.as_overlay_mut().overlay(renderer);
526
527 if overlays.is_empty() {
528 return Vec::new();
529 }
530
531 overlays
532 .into_iter()
533 .map(|raw| {
534 overlay::Element::new(Box::new(Overlay {
535 component: self.component,
536 internal: self.internal,
537 is_outdated: self.is_outdated,
538 raw,
539 }))
540 })
541 .collect()
542 }
543}