focus.rs

  1use crate::{Element, FocusEvent, FocusHandle, StyleRefinement, ViewContext};
  2use smallvec::SmallVec;
  3use std::sync::Arc;
  4
  5pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
  6
  7pub type FocusListener<V> =
  8    Arc<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
  9
 10pub trait Focus: Element {
 11    fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState>;
 12    fn set_focus_style(&mut self, style: StyleRefinement);
 13    fn set_focus_in_style(&mut self, style: StyleRefinement);
 14    fn set_in_focus_style(&mut self, style: StyleRefinement);
 15    fn handle(&self) -> &FocusHandle;
 16
 17    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 18    where
 19        Self: Sized,
 20    {
 21        self.set_focus_style(f(StyleRefinement::default()));
 22        self
 23    }
 24
 25    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 26    where
 27        Self: Sized,
 28    {
 29        self.set_focus_in_style(f(StyleRefinement::default()));
 30        self
 31    }
 32
 33    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 34    where
 35        Self: Sized,
 36    {
 37        self.set_in_focus_style(f(StyleRefinement::default()));
 38        self
 39    }
 40
 41    fn on_focus(
 42        mut self,
 43        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 44            + Send
 45            + Sync
 46            + 'static,
 47    ) -> Self
 48    where
 49        Self: Sized,
 50    {
 51        let handle = self.handle().clone();
 52        self.focus_listeners()
 53            .push(Arc::new(move |view, event, cx| {
 54                if event.focused.as_ref() == Some(&handle) {
 55                    listener(view, event, cx)
 56                }
 57            }));
 58        self
 59    }
 60
 61    fn on_blur(
 62        mut self,
 63        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 64            + Send
 65            + Sync
 66            + 'static,
 67    ) -> Self
 68    where
 69        Self: Sized,
 70    {
 71        let handle = self.handle().clone();
 72        self.focus_listeners()
 73            .push(Arc::new(move |view, event, cx| {
 74                if event.blurred.as_ref() == Some(&handle) {
 75                    listener(view, event, cx)
 76                }
 77            }));
 78        self
 79    }
 80
 81    fn on_focus_in(
 82        mut self,
 83        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 84            + Send
 85            + Sync
 86            + 'static,
 87    ) -> Self
 88    where
 89        Self: Sized,
 90    {
 91        let handle = self.handle().clone();
 92        self.focus_listeners()
 93            .push(Arc::new(move |view, event, cx| {
 94                let descendant_blurred = event
 95                    .blurred
 96                    .as_ref()
 97                    .map_or(false, |blurred| handle.contains(blurred, cx));
 98                let descendant_focused = event
 99                    .focused
100                    .as_ref()
101                    .map_or(false, |focused| handle.contains(focused, cx));
102
103                if !descendant_blurred && descendant_focused {
104                    listener(view, event, cx)
105                }
106            }));
107        self
108    }
109
110    fn on_focus_out(
111        mut self,
112        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
113            + Send
114            + Sync
115            + 'static,
116    ) -> Self
117    where
118        Self: Sized,
119    {
120        let handle = self.handle().clone();
121        self.focus_listeners()
122            .push(Arc::new(move |view, event, cx| {
123                let descendant_blurred = event
124                    .blurred
125                    .as_ref()
126                    .map_or(false, |blurred| handle.contains(blurred, cx));
127                let descendant_focused = event
128                    .focused
129                    .as_ref()
130                    .map_or(false, |focused| handle.contains(focused, cx));
131                if descendant_blurred && !descendant_focused {
132                    listener(view, event, cx)
133                }
134            }));
135        self
136    }
137}