focusable.rs

  1use crate::{
  2    Bounds, DispatchPhase, Element, FocusEvent, FocusHandle, MouseDownEvent, Pixels, Style,
  3    StyleRefinement, ViewContext, WindowContext,
  4};
  5use refineable::Refineable;
  6use smallvec::SmallVec;
  7use std::sync::Arc;
  8
  9pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
 10
 11pub type FocusListener<V> =
 12    Arc<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
 13
 14pub trait Focusable: Element {
 15    fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState>;
 16    fn set_focus_style(&mut self, style: StyleRefinement);
 17    fn set_focus_in_style(&mut self, style: StyleRefinement);
 18    fn set_in_focus_style(&mut self, style: StyleRefinement);
 19
 20    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 21    where
 22        Self: Sized,
 23    {
 24        self.set_focus_style(f(StyleRefinement::default()));
 25        self
 26    }
 27
 28    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 29    where
 30        Self: Sized,
 31    {
 32        self.set_focus_in_style(f(StyleRefinement::default()));
 33        self
 34    }
 35
 36    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 37    where
 38        Self: Sized,
 39    {
 40        self.set_in_focus_style(f(StyleRefinement::default()));
 41        self
 42    }
 43
 44    fn on_focus(
 45        mut self,
 46        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 47            + Send
 48            + Sync
 49            + 'static,
 50    ) -> Self
 51    where
 52        Self: Sized,
 53    {
 54        self.focus_listeners()
 55            .push(Arc::new(move |view, focus_handle, event, cx| {
 56                if event.focused.as_ref() == Some(focus_handle) {
 57                    listener(view, event, cx)
 58                }
 59            }));
 60        self
 61    }
 62
 63    fn on_blur(
 64        mut self,
 65        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 66            + Send
 67            + Sync
 68            + 'static,
 69    ) -> Self
 70    where
 71        Self: Sized,
 72    {
 73        self.focus_listeners()
 74            .push(Arc::new(move |view, focus_handle, event, cx| {
 75                if event.blurred.as_ref() == Some(focus_handle) {
 76                    listener(view, event, cx)
 77                }
 78            }));
 79        self
 80    }
 81
 82    fn on_focus_in(
 83        mut self,
 84        listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
 85            + Send
 86            + Sync
 87            + 'static,
 88    ) -> Self
 89    where
 90        Self: Sized,
 91    {
 92        self.focus_listeners()
 93            .push(Arc::new(move |view, focus_handle, event, cx| {
 94                let descendant_blurred = event
 95                    .blurred
 96                    .as_ref()
 97                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
 98                let descendant_focused = event
 99                    .focused
100                    .as_ref()
101                    .map_or(false, |focused| focus_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        self.focus_listeners()
121            .push(Arc::new(move |view, focus_handle, event, cx| {
122                let descendant_blurred = event
123                    .blurred
124                    .as_ref()
125                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
126                let descendant_focused = event
127                    .focused
128                    .as_ref()
129                    .map_or(false, |focused| focus_handle.contains(focused, cx));
130                if descendant_blurred && !descendant_focused {
131                    listener(view, event, cx)
132                }
133            }));
134        self
135    }
136}
137
138pub trait ElementFocus<V: 'static>: 'static + Send + Sync {
139    fn as_focusable(&self) -> Option<&FocusEnabled<V>>;
140    fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>>;
141
142    fn initialize<R>(
143        &mut self,
144        focus_handle: Option<FocusHandle>,
145        cx: &mut ViewContext<V>,
146        f: impl FnOnce(Option<FocusHandle>, &mut ViewContext<V>) -> R,
147    ) -> R {
148        if let Some(focusable) = self.as_focusable_mut() {
149            let focus_handle = focusable
150                .focus_handle
151                .get_or_insert_with(|| focus_handle.unwrap_or_else(|| cx.focus_handle()))
152                .clone();
153            for listener in focusable.focus_listeners.iter().cloned() {
154                let focus_handle = focus_handle.clone();
155                cx.on_focus_changed(move |view, event, cx| {
156                    listener(view, &focus_handle, event, cx)
157                });
158            }
159            cx.with_focus(focus_handle.clone(), |cx| f(Some(focus_handle), cx))
160        } else {
161            f(None, cx)
162        }
163    }
164
165    fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
166        if let Some(focusable) = self.as_focusable() {
167            let focus_handle = focusable
168                .focus_handle
169                .as_ref()
170                .expect("must call initialize before refine_style");
171            if focus_handle.contains_focused(cx) {
172                style.refine(&focusable.focus_in_style);
173            }
174
175            if focus_handle.within_focused(cx) {
176                style.refine(&focusable.in_focus_style);
177            }
178
179            if focus_handle.is_focused(cx) {
180                style.refine(&focusable.focus_style);
181            }
182        }
183    }
184
185    fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
186        if let Some(focusable) = self.as_focusable() {
187            let focus_handle = focusable
188                .focus_handle
189                .clone()
190                .expect("must call initialize before paint");
191            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
192                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
193                    if !cx.default_prevented() {
194                        cx.focus(&focus_handle);
195                        cx.prevent_default();
196                    }
197                }
198            })
199        }
200    }
201}
202
203pub struct FocusEnabled<V> {
204    pub focus_handle: Option<FocusHandle>,
205    pub focus_listeners: FocusListeners<V>,
206    pub focus_style: StyleRefinement,
207    pub focus_in_style: StyleRefinement,
208    pub in_focus_style: StyleRefinement,
209}
210
211impl<V> FocusEnabled<V> {
212    pub fn new() -> Self {
213        Self {
214            focus_handle: None,
215            focus_listeners: FocusListeners::default(),
216            focus_style: StyleRefinement::default(),
217            focus_in_style: StyleRefinement::default(),
218            in_focus_style: StyleRefinement::default(),
219        }
220    }
221
222    pub fn tracked(handle: &FocusHandle) -> Self {
223        Self {
224            focus_handle: Some(handle.clone()),
225            focus_listeners: FocusListeners::default(),
226            focus_style: StyleRefinement::default(),
227            focus_in_style: StyleRefinement::default(),
228            in_focus_style: StyleRefinement::default(),
229        }
230    }
231}
232
233impl<V: 'static> ElementFocus<V> for FocusEnabled<V> {
234    fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
235        Some(self)
236    }
237
238    fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>> {
239        Some(self)
240    }
241}
242
243impl<V> From<FocusHandle> for FocusEnabled<V> {
244    fn from(value: FocusHandle) -> Self {
245        Self {
246            focus_handle: Some(value),
247            focus_listeners: FocusListeners::default(),
248            focus_style: StyleRefinement::default(),
249            focus_in_style: StyleRefinement::default(),
250            in_focus_style: StyleRefinement::default(),
251        }
252    }
253}
254
255pub struct FocusDisabled;
256
257impl<V: 'static> ElementFocus<V> for FocusDisabled {
258    fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
259        None
260    }
261
262    fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>> {
263        None
264    }
265}