node.rs

  1use crate::{
  2    point, Action, AnyDrag, AnyElement, AnyView, AppContext, BorrowWindow, Bounds, ClickEvent,
  3    DispatchPhase, Element, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
  4    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, Render,
  5    ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, View, ViewContext, Visibility,
  6};
  7use collections::HashMap;
  8use refineable::Refineable;
  9use smallvec::SmallVec;
 10use std::{
 11    any::{Any, TypeId},
 12    marker::PhantomData,
 13    sync::Arc,
 14};
 15
 16pub struct GroupStyle {
 17    pub group: SharedString,
 18    pub style: StyleRefinement,
 19}
 20
 21pub trait InteractiveComponent<V: 'static> {
 22    fn interactivity(&mut self) -> &mut Interactivity<V>;
 23
 24    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 25    where
 26        Self: Sized,
 27    {
 28        self.interactivity().hover_style = f(StyleRefinement::default());
 29        self
 30    }
 31
 32    fn group_hover(
 33        mut self,
 34        group_name: impl Into<SharedString>,
 35        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 36    ) -> Self
 37    where
 38        Self: Sized,
 39    {
 40        self.interactivity().group_hover_style = Some(GroupStyle {
 41            group: group_name.into(),
 42            style: f(StyleRefinement::default()),
 43        });
 44        self
 45    }
 46
 47    fn on_mouse_down(
 48        mut self,
 49        button: MouseButton,
 50        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
 51    ) -> Self
 52    where
 53        Self: Sized,
 54    {
 55        self.interactivity().mouse_down_listeners.push(Box::new(
 56            move |view, event, bounds, phase, cx| {
 57                if phase == DispatchPhase::Bubble
 58                    && event.button == button
 59                    && bounds.contains_point(&event.position)
 60                {
 61                    handler(view, event, cx)
 62                }
 63            },
 64        ));
 65        self
 66    }
 67
 68    fn on_mouse_up(
 69        mut self,
 70        button: MouseButton,
 71        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
 72    ) -> Self
 73    where
 74        Self: Sized,
 75    {
 76        self.interactivity().mouse_up_listeners.push(Box::new(
 77            move |view, event, bounds, phase, cx| {
 78                if phase == DispatchPhase::Bubble
 79                    && event.button == button
 80                    && bounds.contains_point(&event.position)
 81                {
 82                    handler(view, event, cx)
 83                }
 84            },
 85        ));
 86        self
 87    }
 88
 89    fn on_mouse_down_out(
 90        mut self,
 91        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
 92    ) -> Self
 93    where
 94        Self: Sized,
 95    {
 96        self.interactivity().mouse_down_listeners.push(Box::new(
 97            move |view, event, bounds, phase, cx| {
 98                if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
 99                    handler(view, event, cx)
100                }
101            },
102        ));
103        self
104    }
105
106    fn on_mouse_up_out(
107        mut self,
108        button: MouseButton,
109        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
110    ) -> Self
111    where
112        Self: Sized,
113    {
114        self.interactivity().mouse_up_listeners.push(Box::new(
115            move |view, event, bounds, phase, cx| {
116                if phase == DispatchPhase::Capture
117                    && event.button == button
118                    && !bounds.contains_point(&event.position)
119                {
120                    handler(view, event, cx);
121                }
122            },
123        ));
124        self
125    }
126
127    fn on_mouse_move(
128        mut self,
129        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
130    ) -> Self
131    where
132        Self: Sized,
133    {
134        self.interactivity().mouse_move_listeners.push(Box::new(
135            move |view, event, bounds, phase, cx| {
136                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
137                    handler(view, event, cx);
138                }
139            },
140        ));
141        self
142    }
143
144    fn on_scroll_wheel(
145        mut self,
146        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
147    ) -> Self
148    where
149        Self: Sized,
150    {
151        self.interactivity().scroll_wheel_listeners.push(Box::new(
152            move |view, event, bounds, phase, cx| {
153                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
154                    handler(view, event, cx);
155                }
156            },
157        ));
158        self
159    }
160
161    /// Capture the given action, fires during the capture phase
162    fn capture_action<A: Action>(
163        mut self,
164        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
165    ) -> Self
166    where
167        Self: Sized,
168    {
169        self.interactivity().action_listeners.push((
170            TypeId::of::<A>(),
171            Box::new(move |view, action, phase, cx| {
172                let action = action.downcast_ref().unwrap();
173                if phase == DispatchPhase::Capture {
174                    listener(view, action, cx)
175                }
176            }),
177        ));
178        self
179    }
180
181    /// Add a listener for the given action, fires during the bubble event phase
182    fn on_action<A: Action>(
183        mut self,
184        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
185    ) -> Self
186    where
187        Self: Sized,
188    {
189        self.interactivity().action_listeners.push((
190            TypeId::of::<A>(),
191            Box::new(move |view, action, phase, cx| {
192                let action = action.downcast_ref().unwrap();
193                if phase == DispatchPhase::Bubble {
194                    listener(view, action, cx)
195                }
196            }),
197        ));
198        self
199    }
200
201    fn on_key_down(
202        mut self,
203        listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
204    ) -> Self
205    where
206        Self: Sized,
207    {
208        self.interactivity()
209            .key_down_listeners
210            .push(Box::new(move |view, event, phase, cx| {
211                listener(view, event, phase, cx)
212            }));
213        self
214    }
215
216    fn on_key_up(
217        mut self,
218        listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
219    ) -> Self
220    where
221        Self: Sized,
222    {
223        self.interactivity()
224            .key_up_listeners
225            .push(Box::new(move |view, event, phase, cx| {
226                listener(view, event, phase, cx)
227            }));
228        self
229    }
230
231    fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
232    where
233        Self: Sized,
234    {
235        self.interactivity()
236            .drag_over_styles
237            .push((TypeId::of::<S>(), f(StyleRefinement::default())));
238        self
239    }
240
241    fn group_drag_over<S: 'static>(
242        mut self,
243        group_name: impl Into<SharedString>,
244        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
245    ) -> Self
246    where
247        Self: Sized,
248    {
249        self.interactivity().group_drag_over_styles.push((
250            TypeId::of::<S>(),
251            GroupStyle {
252                group: group_name.into(),
253                style: f(StyleRefinement::default()),
254            },
255        ));
256        self
257    }
258
259    fn on_drop<W: 'static>(
260        mut self,
261        listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
262    ) -> Self
263    where
264        Self: Sized,
265    {
266        self.interactivity().drop_listeners.push((
267            TypeId::of::<W>(),
268            Box::new(move |view, dragged_view, cx| {
269                listener(view, dragged_view.downcast().unwrap(), cx);
270            }),
271        ));
272        self
273    }
274}
275
276pub trait StatefulInteractiveComponent<V: 'static> {
277    fn interactivity(&mut self) -> &mut StatefulInteractivity<V>;
278
279    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
280    where
281        Self: Sized,
282    {
283        self.interactivity().active_style = f(StyleRefinement::default());
284        self
285    }
286
287    fn group_active(
288        mut self,
289        group_name: impl Into<SharedString>,
290        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
291    ) -> Self
292    where
293        Self: Sized,
294    {
295        self.interactivity().group_active_style = Some(GroupStyle {
296            group: group_name.into(),
297            style: f(StyleRefinement::default()),
298        });
299        self
300    }
301
302    fn on_click(
303        mut self,
304        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
305    ) -> Self
306    where
307        Self: Sized,
308    {
309        self.interactivity()
310            .click_listeners
311            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
312        self
313    }
314
315    fn on_drag<W>(
316        mut self,
317        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
318    ) -> Self
319    where
320        Self: Sized,
321        W: 'static + Render,
322    {
323        debug_assert!(
324            self.interactivity().drag_listener.is_none(),
325            "calling on_drag more than once on the same element is not supported"
326        );
327        self.interactivity().drag_listener =
328            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
329                view: listener(view_state, cx).into(),
330                cursor_offset,
331            }));
332        self
333    }
334
335    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
336    where
337        Self: Sized,
338    {
339        debug_assert!(
340            self.interactivity().hover_listener.is_none(),
341            "calling on_hover more than once on the same element is not supported"
342        );
343        self.interactivity().hover_listener = Some(Box::new(listener));
344        self
345    }
346
347    fn tooltip<W>(
348        mut self,
349        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
350    ) -> Self
351    where
352        Self: Sized,
353        W: 'static + Render,
354    {
355        debug_assert!(
356            self.interactivity().tooltip_builder.is_none(),
357            "calling tooltip more than once on the same element is not supported"
358        );
359        self.interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
360            build_tooltip(view_state, cx).into()
361        }));
362
363        self
364    }
365}
366
367pub trait FocusableComponent<V> {
368    fn focusability(&mut self) -> &mut Focusability<V>;
369
370    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
371    where
372        Self: Sized,
373    {
374        self.focusability().focus_style = f(StyleRefinement::default());
375        self
376    }
377
378    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
379    where
380        Self: Sized,
381    {
382        self.focusability().focus_in_style = f(StyleRefinement::default());
383        self
384    }
385
386    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
387    where
388        Self: Sized,
389    {
390        // self.focusability(). (f(StyleRefinement::default()));
391        self
392    }
393
394    fn on_focus(
395        mut self,
396        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
397    ) -> Self
398    where
399        Self: Sized,
400    {
401        self.focusability()
402            .focus_listeners
403            .push(Box::new(move |view, focus_handle, event, cx| {
404                if event.focused.as_ref() == Some(focus_handle) {
405                    listener(view, event, cx)
406                }
407            }));
408        self
409    }
410
411    fn on_blur(
412        mut self,
413        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
414    ) -> Self
415    where
416        Self: Sized,
417    {
418        self.focusability()
419            .focus_listeners
420            .push(Box::new(move |view, focus_handle, event, cx| {
421                if event.blurred.as_ref() == Some(focus_handle) {
422                    listener(view, event, cx)
423                }
424            }));
425        self
426    }
427
428    fn on_focus_in(
429        mut self,
430        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
431    ) -> Self
432    where
433        Self: Sized,
434    {
435        self.focusability()
436            .focus_listeners
437            .push(Box::new(move |view, focus_handle, event, cx| {
438                let descendant_blurred = event
439                    .blurred
440                    .as_ref()
441                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
442                let descendant_focused = event
443                    .focused
444                    .as_ref()
445                    .map_or(false, |focused| focus_handle.contains(focused, cx));
446
447                if !descendant_blurred && descendant_focused {
448                    listener(view, event, cx)
449                }
450            }));
451        self
452    }
453
454    fn on_focus_out(
455        mut self,
456        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
457    ) -> Self
458    where
459        Self: Sized,
460    {
461        self.focusability()
462            .focus_listeners
463            .push(Box::new(move |view, focus_handle, event, cx| {
464                let descendant_blurred = event
465                    .blurred
466                    .as_ref()
467                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
468                let descendant_focused = event
469                    .focused
470                    .as_ref()
471                    .map_or(false, |focused| focus_handle.contains(focused, cx));
472                if descendant_blurred && !descendant_focused {
473                    listener(view, event, cx)
474                }
475            }));
476        self
477    }
478}
479
480pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
481
482pub type FocusListener<V> =
483    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
484
485pub type MouseDownListener<V> = Box<
486    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
487>;
488pub type MouseUpListener<V> = Box<
489    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
490>;
491
492pub type MouseMoveListener<V> = Box<
493    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
494>;
495
496pub type ScrollWheelListener<V> = Box<
497    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
498        + 'static,
499>;
500
501pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
502
503pub type DragListener<V> =
504    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
505
506type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
507
508pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
509
510pub type TooltipBuilder<V> = Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
511
512pub type KeyDownListener<V> =
513    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
514
515pub type KeyUpListener<V> =
516    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
517
518pub type ActionListener<V> =
519    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
520
521pub struct FocusEvent {
522    pub blurred: Option<FocusHandle>,
523    pub focused: Option<FocusHandle>,
524}
525
526pub struct Node<V> {
527    style: StyleRefinement,
528    key_context: KeyContext,
529    interactivity: Interactivity<V>,
530    children: Vec<AnyElement<V>>,
531}
532
533pub struct Interactivity<V> {
534    group: Option<SharedString>,
535    pub dispatch_context: KeyContext,
536    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
537    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
538    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
539    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
540    pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
541    pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
542    pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
543    pub hover_style: StyleRefinement,
544    pub group_hover_style: Option<GroupStyle>,
545    drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
546    group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
547    drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
548    scroll_offset: Point<Pixels>,
549}
550
551impl<V> Node<V> {
552    fn compute_style(&self) -> Style {
553        let mut style = Style::default();
554        style.refine(&self.style);
555        style
556    }
557}
558
559impl<V> Styled for Node<V> {
560    fn style(&mut self) -> &mut StyleRefinement {
561        &mut self.style
562    }
563}
564
565impl<V: 'static> InteractiveComponent<V> for Node<V> {
566    fn interactivity(&mut self) -> &mut Interactivity<V> {
567        &mut self.interactivity
568    }
569}
570
571pub struct NodeState {
572    child_layout_ids: SmallVec<[LayoutId; 4]>,
573}
574
575impl<V: 'static> Element<V> for Node<V> {
576    type ElementState = NodeState;
577
578    fn id(&self) -> Option<crate::ElementId> {
579        None
580    }
581
582    fn initialize(
583        &mut self,
584        view_state: &mut V,
585        _: Option<Self::ElementState>,
586        cx: &mut ViewContext<V>,
587    ) -> Self::ElementState {
588        for child in &mut self.children {
589            child.initialize(view_state, cx);
590        }
591        NodeState {
592            child_layout_ids: SmallVec::new(),
593        }
594    }
595
596    fn layout(
597        &mut self,
598        view_state: &mut V,
599        element_state: &mut Self::ElementState,
600        cx: &mut ViewContext<V>,
601    ) -> crate::LayoutId {
602        let style = self.compute_style();
603        style.with_text_style(cx, |cx| {
604            element_state.child_layout_ids = self
605                .children
606                .iter_mut()
607                .map(|child| child.layout(view_state, cx))
608                .collect::<SmallVec<_>>();
609            cx.request_layout(&style, element_state.child_layout_ids.iter().copied())
610        })
611    }
612
613    fn paint(
614        &mut self,
615        bounds: Bounds<Pixels>,
616        view_state: &mut V,
617        element_state: &mut Self::ElementState,
618        cx: &mut ViewContext<V>,
619    ) {
620        let style = self.compute_style();
621        if style.visibility == Visibility::Hidden {
622            return;
623        }
624
625        if let Some(mouse_cursor) = style.mouse_cursor {
626            let hovered = bounds.contains_point(&cx.mouse_position());
627            if hovered {
628                cx.set_cursor_style(mouse_cursor);
629            }
630        }
631
632        if let Some(group) = self.interactivity.group.clone() {
633            GroupBounds::push(group, bounds, cx);
634        }
635
636        let z_index = style.z_index.unwrap_or(0);
637
638        let mut child_min = point(Pixels::MAX, Pixels::MAX);
639        let mut child_max = Point::default();
640
641        let content_size = if element_state.child_layout_ids.is_empty() {
642            bounds.size
643        } else {
644            for child_layout_id in &element_state.child_layout_ids {
645                let child_bounds = cx.layout_bounds(*child_layout_id);
646                child_min = child_min.min(&child_bounds.origin);
647                child_max = child_max.max(&child_bounds.lower_right());
648            }
649            (child_max - child_min).into()
650        };
651
652        cx.with_z_index(z_index, |cx| {
653            cx.with_z_index(0, |cx| {
654                style.paint(bounds, cx);
655            });
656            cx.with_z_index(1, |cx| {
657                style.with_text_style(cx, |cx| {
658                    style.apply_overflow(bounds, cx, |cx| {
659                        let scroll_offset = self.interactivity.scroll_offset;
660                        cx.with_element_offset2(scroll_offset, |cx| {
661                            for child in &mut self.children {
662                                child.paint(view_state, cx);
663                            }
664                        });
665                    })
666                })
667            });
668        });
669
670        if let Some(group) = self.interactivity.group.as_ref() {
671            GroupBounds::pop(group, cx);
672        }
673    }
674}
675
676#[derive(Default)]
677pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
678
679impl GroupBounds {
680    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
681        cx.default_global::<Self>()
682            .0
683            .get(name)
684            .and_then(|bounds_stack| bounds_stack.last())
685            .cloned()
686    }
687
688    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
689        cx.default_global::<Self>()
690            .0
691            .entry(name)
692            .or_default()
693            .push(bounds);
694    }
695
696    pub fn pop(name: &SharedString, cx: &mut AppContext) {
697        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
698    }
699}
700
701pub struct Focusable<V, E> {
702    focusability: Focusability<V>,
703    view_type: PhantomData<V>,
704    element: E,
705}
706
707pub struct Focusability<V> {
708    focus_handle: Option<FocusHandle>,
709    focus_listeners: FocusListeners<V>,
710    focus_style: StyleRefinement,
711    focus_in_style: StyleRefinement,
712    in_focus_style: StyleRefinement,
713}
714
715impl<V, E> FocusableComponent<V> for Focusable<V, E> {
716    fn focusability(&mut self) -> &mut Focusability<V> {
717        &mut self.focusability
718    }
719}
720
721impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Focusable<V, E> {
722    fn interactivity(&mut self) -> &mut Interactivity<V> {
723        self.element.interactivity()
724    }
725}
726
727impl<V: 'static, E: StatefulInteractiveComponent<V>> StatefulInteractiveComponent<V>
728    for Focusable<V, E>
729{
730    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
731        self.element.interactivity()
732    }
733}
734
735pub struct Stateful<V, E> {
736    id: SharedString,
737    interactivity: StatefulInteractivity<V>,
738    view_type: PhantomData<V>,
739    element: E,
740}
741
742pub struct StatefulInteractivity<V> {
743    click_listeners: SmallVec<[ClickListener<V>; 2]>,
744    active_style: StyleRefinement,
745    group_active_style: Option<GroupStyle>,
746    drag_listener: Option<DragListener<V>>,
747    hover_listener: Option<HoverListener<V>>,
748    tooltip_builder: Option<TooltipBuilder<V>>,
749}
750
751impl<V: 'static, E> StatefulInteractiveComponent<V> for Stateful<V, E> {
752    fn interactivity(&mut self) -> &mut StatefulInteractivity<V> {
753        &mut self.interactivity
754    }
755}
756
757impl<V: 'static, E: InteractiveComponent<V>> InteractiveComponent<V> for Stateful<V, E> {
758    fn interactivity(&mut self) -> &mut Interactivity<V> {
759        self.element.interactivity()
760    }
761}
762
763impl<V, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {
764    fn focusability(&mut self) -> &mut Focusability<V> {
765        self.element.focusability()
766    }
767}