key_dispatch.rs

  1use crate::{
  2    build_action_from_type, Action, Bounds, DispatchPhase, Element, FocusEvent, FocusHandle,
  3    FocusId, KeyContext, KeyDownEvent, KeyMatch, Keymap, KeystrokeMatcher, MouseDownEvent, Pixels,
  4    Style, StyleRefinement, ViewContext, WindowContext,
  5};
  6use collections::HashMap;
  7use parking_lot::Mutex;
  8use refineable::Refineable;
  9use smallvec::SmallVec;
 10use std::{
 11    any::{Any, TypeId},
 12    sync::Arc,
 13};
 14use util::ResultExt;
 15
 16type KeyListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>;
 17pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
 18pub type FocusListener<V> =
 19    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
 20
 21#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 22pub struct DispatchNodeId(usize);
 23
 24pub struct KeyDispatcher {
 25    node_stack: Vec<DispatchNodeId>,
 26    context_stack: Vec<KeyContext>,
 27    nodes: Vec<DispatchNode>,
 28    focusable_node_ids: HashMap<FocusId, DispatchNodeId>,
 29    keystroke_matchers: HashMap<SmallVec<[KeyContext; 4]>, KeystrokeMatcher>,
 30    keymap: Arc<Mutex<Keymap>>,
 31}
 32
 33#[derive(Default)]
 34pub struct DispatchNode {
 35    key_listeners: SmallVec<[KeyListener; 2]>,
 36    action_listeners: SmallVec<[ActionListener; 16]>,
 37    context: KeyContext,
 38    parent: Option<DispatchNodeId>,
 39}
 40
 41struct ActionListener {
 42    action_type: TypeId,
 43    listener: Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
 44}
 45
 46impl KeyDispatcher {
 47    pub fn new(keymap: Arc<Mutex<Keymap>>) -> Self {
 48        Self {
 49            node_stack: Vec::new(),
 50            context_stack: Vec::new(),
 51            nodes: Vec::new(),
 52            focusable_node_ids: HashMap::default(),
 53            keystroke_matchers: HashMap::default(),
 54            keymap,
 55        }
 56    }
 57
 58    pub fn clear(&mut self) {
 59        self.node_stack.clear();
 60        self.nodes.clear();
 61    }
 62
 63    pub fn push_node(&mut self, context: KeyContext, old_dispatcher: &mut Self) {
 64        let parent = self.node_stack.last().copied();
 65        let node_id = DispatchNodeId(self.nodes.len());
 66        self.nodes.push(DispatchNode {
 67            parent,
 68            ..Default::default()
 69        });
 70        self.node_stack.push(node_id);
 71        if !context.is_empty() {
 72            self.context_stack.push(context);
 73            if let Some((context_stack, matcher)) = old_dispatcher
 74                .keystroke_matchers
 75                .remove_entry(self.context_stack.as_slice())
 76            {
 77                self.keystroke_matchers.insert(context_stack, matcher);
 78            }
 79        }
 80    }
 81
 82    pub fn pop_node(&mut self) {
 83        let node_id = self.node_stack.pop().unwrap();
 84        if !self.nodes[node_id.0].context.is_empty() {
 85            self.context_stack.pop();
 86        }
 87    }
 88
 89    pub fn on_key_event(&mut self, listener: KeyListener) {
 90        self.active_node().key_listeners.push(listener);
 91    }
 92
 93    pub fn on_action(
 94        &mut self,
 95        action_type: TypeId,
 96        listener: Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
 97    ) {
 98        self.active_node().action_listeners.push(ActionListener {
 99            action_type,
100            listener,
101        });
102    }
103
104    pub fn make_focusable(&mut self, focus_id: FocusId) {
105        self.focusable_node_ids
106            .insert(focus_id, self.active_node_id());
107    }
108
109    pub fn focus_contains(&self, parent: FocusId, child: FocusId) -> bool {
110        if parent == child {
111            return true;
112        }
113
114        if let Some(parent_node_id) = self.focusable_node_ids.get(&parent) {
115            let mut current_node_id = self.focusable_node_ids.get(&child).copied();
116            while let Some(node_id) = current_node_id {
117                if node_id == *parent_node_id {
118                    return true;
119                }
120                current_node_id = self.nodes[node_id.0].parent;
121            }
122        }
123        false
124    }
125
126    pub fn available_actions(&self, target: FocusId) -> Vec<Box<dyn Action>> {
127        let mut actions = Vec::new();
128        if let Some(node) = self.focusable_node_ids.get(&target) {
129            for node_id in self.dispatch_path(*node) {
130                let node = &self.nodes[node_id.0];
131                for ActionListener { action_type, .. } in &node.action_listeners {
132                    actions.extend(build_action_from_type(action_type).log_err());
133                }
134            }
135        }
136        actions
137    }
138
139    pub fn dispatch_key(&mut self, target: FocusId, event: &dyn Any, cx: &mut WindowContext) {
140        if let Some(target_node_id) = self.focusable_node_ids.get(&target).copied() {
141            self.dispatch_key_on_node(target_node_id, event, cx);
142        }
143    }
144
145    fn dispatch_key_on_node(
146        &mut self,
147        node_id: DispatchNodeId,
148        event: &dyn Any,
149        cx: &mut WindowContext,
150    ) {
151        let dispatch_path = self.dispatch_path(node_id);
152
153        // Capture phase
154        self.context_stack.clear();
155        cx.propagate_event = true;
156        for node_id in &dispatch_path {
157            let node = &self.nodes[node_id.0];
158            if !node.context.is_empty() {
159                self.context_stack.push(node.context.clone());
160            }
161
162            for key_listener in &node.key_listeners {
163                key_listener(event, DispatchPhase::Capture, cx);
164                if !cx.propagate_event {
165                    return;
166                }
167            }
168        }
169
170        // Bubble phase
171        for node_id in dispatch_path.iter().rev() {
172            let node = &self.nodes[node_id.0];
173
174            // Handle low level key events
175            for key_listener in &node.key_listeners {
176                key_listener(event, DispatchPhase::Bubble, cx);
177                if !cx.propagate_event {
178                    return;
179                }
180            }
181
182            // Match keystrokes
183            if !node.context.is_empty() {
184                if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
185                    if !self
186                        .keystroke_matchers
187                        .contains_key(self.context_stack.as_slice())
188                    {
189                        let keystroke_contexts = self.context_stack.iter().cloned().collect();
190                        self.keystroke_matchers.insert(
191                            keystroke_contexts,
192                            KeystrokeMatcher::new(self.keymap.clone()),
193                        );
194                    }
195
196                    if let Some(keystroke_matcher) = self
197                        .keystroke_matchers
198                        .get_mut(self.context_stack.as_slice())
199                    {
200                        if let KeyMatch::Some(action) = keystroke_matcher.match_keystroke(
201                            &key_down_event.keystroke,
202                            self.context_stack.as_slice(),
203                        ) {
204                            self.dispatch_action_on_node(*node_id, action, cx);
205                            if !cx.propagate_event {
206                                return;
207                            }
208                        }
209                    }
210                }
211
212                self.context_stack.pop();
213            }
214        }
215    }
216
217    pub fn dispatch_action(
218        &self,
219        target: FocusId,
220        action: Box<dyn Action>,
221        cx: &mut WindowContext,
222    ) {
223        if let Some(target_node_id) = self.focusable_node_ids.get(&target).copied() {
224            self.dispatch_action_on_node(target_node_id, action, cx);
225        }
226    }
227
228    fn dispatch_action_on_node(
229        &self,
230        node_id: DispatchNodeId,
231        action: Box<dyn Action>,
232        cx: &mut WindowContext,
233    ) {
234        let dispatch_path = self.dispatch_path(node_id);
235
236        // Capture phase
237        for node_id in &dispatch_path {
238            let node = &self.nodes[node_id.0];
239            for ActionListener { listener, .. } in &node.action_listeners {
240                listener(&action, DispatchPhase::Capture, cx);
241                if !cx.propagate_event {
242                    return;
243                }
244            }
245        }
246
247        // Bubble phase
248        for node_id in dispatch_path.iter().rev() {
249            let node = &self.nodes[node_id.0];
250            for ActionListener { listener, .. } in &node.action_listeners {
251                cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
252                listener(&action, DispatchPhase::Capture, cx);
253                if !cx.propagate_event {
254                    return;
255                }
256            }
257        }
258    }
259
260    fn active_node(&mut self) -> &mut DispatchNode {
261        let active_node_id = self.active_node_id();
262        &mut self.nodes[active_node_id.0]
263    }
264
265    fn active_node_id(&self) -> DispatchNodeId {
266        *self.node_stack.last().unwrap()
267    }
268
269    /// Returns the DispatchNodeIds from the root of the tree to the given target node id.
270    fn dispatch_path(&self, target: DispatchNodeId) -> SmallVec<[DispatchNodeId; 32]> {
271        let mut dispatch_path: SmallVec<[DispatchNodeId; 32]> = SmallVec::new();
272        let mut current_node_id = Some(target);
273        while let Some(node_id) = current_node_id {
274            dispatch_path.push(node_id);
275            current_node_id = self.nodes[node_id.0].parent;
276        }
277        dispatch_path.reverse(); // Reverse the path so it goes from the root to the focused node.
278        dispatch_path
279    }
280}
281
282pub trait KeyDispatch<V: 'static>: 'static {
283    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>>;
284    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>>;
285    fn key_context(&self) -> &KeyContext;
286    fn key_context_mut(&mut self) -> &mut KeyContext;
287
288    fn initialize<R>(
289        &mut self,
290        focus_handle: Option<FocusHandle>,
291        cx: &mut ViewContext<V>,
292        f: impl FnOnce(Option<FocusHandle>, &mut ViewContext<V>) -> R,
293    ) -> R {
294        if let Some(focusable) = self.as_focusable_mut() {
295            let focus_handle = focusable
296                .focus_handle
297                .get_or_insert_with(|| focus_handle.unwrap_or_else(|| cx.focus_handle()))
298                .clone();
299            for listener in focusable.focus_listeners.drain(..) {
300                let focus_handle = focus_handle.clone();
301                cx.on_focus_changed(move |view, event, cx| {
302                    listener(view, &focus_handle, event, cx)
303                });
304            }
305
306            cx.with_key_dispatch(self.key_context().clone(), Some(focus_handle), f)
307        } else {
308            f(None, cx)
309        }
310    }
311
312    fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
313        if let Some(focusable) = self.as_focusable() {
314            let focus_handle = focusable
315                .focus_handle
316                .as_ref()
317                .expect("must call initialize before refine_style");
318            if focus_handle.contains_focused(cx) {
319                style.refine(&focusable.focus_in_style);
320            }
321
322            if focus_handle.within_focused(cx) {
323                style.refine(&focusable.in_focus_style);
324            }
325
326            if focus_handle.is_focused(cx) {
327                style.refine(&focusable.focus_style);
328            }
329        }
330    }
331
332    fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
333        if let Some(focusable) = self.as_focusable() {
334            let focus_handle = focusable
335                .focus_handle
336                .clone()
337                .expect("must call initialize before paint");
338            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
339                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
340                    if !cx.default_prevented() {
341                        cx.focus(&focus_handle);
342                        cx.prevent_default();
343                    }
344                }
345            })
346        }
347    }
348}
349
350pub struct FocusableKeyDispatch<V> {
351    pub key_context: KeyContext,
352    pub focus_handle: Option<FocusHandle>,
353    pub focus_listeners: FocusListeners<V>,
354    pub focus_style: StyleRefinement,
355    pub focus_in_style: StyleRefinement,
356    pub in_focus_style: StyleRefinement,
357}
358
359impl<V> FocusableKeyDispatch<V> {
360    pub fn new() -> Self {
361        Self {
362            key_context: KeyContext::default(),
363            focus_handle: None,
364            focus_listeners: FocusListeners::default(),
365            focus_style: StyleRefinement::default(),
366            focus_in_style: StyleRefinement::default(),
367            in_focus_style: StyleRefinement::default(),
368        }
369    }
370
371    pub fn tracked(handle: &FocusHandle) -> Self {
372        Self {
373            key_context: KeyContext::default(),
374            focus_handle: Some(handle.clone()),
375            focus_listeners: FocusListeners::default(),
376            focus_style: StyleRefinement::default(),
377            focus_in_style: StyleRefinement::default(),
378            in_focus_style: StyleRefinement::default(),
379        }
380    }
381}
382
383impl<V: 'static> KeyDispatch<V> for FocusableKeyDispatch<V> {
384    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>> {
385        Some(self)
386    }
387
388    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>> {
389        Some(self)
390    }
391
392    fn key_context(&self) -> &KeyContext {
393        &self.key_context
394    }
395
396    fn key_context_mut(&mut self) -> &mut KeyContext {
397        &mut self.key_context
398    }
399}
400
401impl<V> From<FocusHandle> for FocusableKeyDispatch<V> {
402    fn from(value: FocusHandle) -> Self {
403        Self {
404            key_context: KeyContext::default(),
405            focus_handle: Some(value),
406            focus_listeners: FocusListeners::default(),
407            focus_style: StyleRefinement::default(),
408            focus_in_style: StyleRefinement::default(),
409            in_focus_style: StyleRefinement::default(),
410        }
411    }
412}
413
414#[derive(Default)]
415pub struct NonFocusableKeyDispatch {
416    pub(crate) key_context: KeyContext,
417}
418
419impl<V: 'static> KeyDispatch<V> for NonFocusableKeyDispatch {
420    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>> {
421        None
422    }
423
424    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>> {
425        None
426    }
427
428    fn key_context(&self) -> &KeyContext {
429        &self.key_context
430    }
431
432    fn key_context_mut(&mut self) -> &mut KeyContext {
433        &mut self.key_context
434    }
435}
436
437pub trait Focusable<V: 'static>: Element<V> {
438    fn focus_listeners(&mut self) -> &mut FocusListeners<V>;
439    fn set_focus_style(&mut self, style: StyleRefinement);
440    fn set_focus_in_style(&mut self, style: StyleRefinement);
441    fn set_in_focus_style(&mut self, style: StyleRefinement);
442
443    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
444    where
445        Self: Sized,
446    {
447        self.set_focus_style(f(StyleRefinement::default()));
448        self
449    }
450
451    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
452    where
453        Self: Sized,
454    {
455        self.set_focus_in_style(f(StyleRefinement::default()));
456        self
457    }
458
459    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
460    where
461        Self: Sized,
462    {
463        self.set_in_focus_style(f(StyleRefinement::default()));
464        self
465    }
466
467    fn on_focus(
468        mut self,
469        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
470    ) -> Self
471    where
472        Self: Sized,
473    {
474        self.focus_listeners()
475            .push(Box::new(move |view, focus_handle, event, cx| {
476                if event.focused.as_ref() == Some(focus_handle) {
477                    listener(view, event, cx)
478                }
479            }));
480        self
481    }
482
483    fn on_blur(
484        mut self,
485        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
486    ) -> Self
487    where
488        Self: Sized,
489    {
490        self.focus_listeners()
491            .push(Box::new(move |view, focus_handle, event, cx| {
492                if event.blurred.as_ref() == Some(focus_handle) {
493                    listener(view, event, cx)
494                }
495            }));
496        self
497    }
498
499    fn on_focus_in(
500        mut self,
501        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
502    ) -> Self
503    where
504        Self: Sized,
505    {
506        self.focus_listeners()
507            .push(Box::new(move |view, focus_handle, event, cx| {
508                let descendant_blurred = event
509                    .blurred
510                    .as_ref()
511                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
512                let descendant_focused = event
513                    .focused
514                    .as_ref()
515                    .map_or(false, |focused| focus_handle.contains(focused, cx));
516
517                if !descendant_blurred && descendant_focused {
518                    listener(view, event, cx)
519                }
520            }));
521        self
522    }
523
524    fn on_focus_out(
525        mut self,
526        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
527    ) -> Self
528    where
529        Self: Sized,
530    {
531        self.focus_listeners()
532            .push(Box::new(move |view, focus_handle, event, cx| {
533                let descendant_blurred = event
534                    .blurred
535                    .as_ref()
536                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
537                let descendant_focused = event
538                    .focused
539                    .as_ref()
540                    .map_or(false, |focused| focus_handle.contains(focused, cx));
541                if descendant_blurred && !descendant_focused {
542                    listener(view, event, cx)
543                }
544            }));
545        self
546    }
547}