@@ -1,15 +1,16 @@
use crate::{
Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable,
- Hover, Identified, Interactive, IntoAnyElement, LayoutId, MouseClickEvent, MouseDownEvent,
- MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point,
- ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
+ Hover, Identified, Interactive, IntoAnyElement, KeyDownEvent, KeyMatch, LayoutId,
+ MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow,
+ ParentElement, Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled,
+ ViewContext,
};
use collections::HashMap;
use parking_lot::Mutex;
use refineable::Refineable;
use smallvec::SmallVec;
-use std::{mem, sync::Arc};
+use std::{any::TypeId, mem, sync::Arc};
#[derive(Default)]
pub struct DivState {
@@ -423,11 +424,30 @@ where
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<Self::ViewState>,
) -> Self::ElementState {
+ let element_state = element_state.unwrap_or_default();
for listener in self.listeners.focus.iter().cloned() {
cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
}
- let key_listeners = mem::take(&mut self.listeners.key);
+ let mut key_listeners = mem::take(&mut self.listeners.key);
+
+ if let Some(id) = self.id() {
+ key_listeners.push((
+ TypeId::of::<KeyDownEvent>(),
+ Arc::new(move |_, key_down, phase, cx| {
+ if phase == DispatchPhase::Bubble {
+ let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
+ if let KeyMatch::Some(action) = cx.match_keystroke(&id, &key_down.keystroke)
+ {
+ return Some(action);
+ }
+ }
+
+ None
+ }),
+ ));
+ }
+
cx.with_key_listeners(&key_listeners, |cx| {
if let Some(focus_handle) = self.focusability.focus_handle().cloned() {
cx.with_focus(focus_handle, |cx| {
@@ -443,7 +463,7 @@ where
});
self.listeners.key = key_listeners;
- element_state.unwrap_or_default()
+ element_state
}
fn layout(
@@ -1,9 +1,5 @@
-use std::{any::TypeId, sync::Arc};
-
-use crate::{
- DispatchPhase, FocusEvent, FocusHandle, Interactive, KeyDownEvent, KeyUpEvent, StyleRefinement,
- ViewContext,
-};
+use crate::{FocusEvent, FocusHandle, Interactive, StyleRefinement, ViewContext};
+use std::sync::Arc;
pub trait Focus: Interactive {
fn set_focus_style(&mut self, style: StyleRefinement);
@@ -135,48 +131,4 @@ pub trait Focus: Interactive {
}));
self
}
-
- fn on_key_down(
- mut self,
- listener: impl Fn(
- &mut Self::ViewState,
- &KeyDownEvent,
- DispatchPhase,
- &mut ViewContext<Self::ViewState>,
- ) + Send
- + Sync
- + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.listeners().key.push((
- TypeId::of::<KeyDownEvent>(),
- Arc::new(move |view, event, phase, cx| {
- let event = event.downcast_ref().unwrap();
- listener(view, event, phase, cx)
- }),
- ));
- self
- }
-
- fn on_key_up(
- mut self,
- listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
- + Send
- + Sync
- + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.listeners().key.push((
- TypeId::of::<KeyUpEvent>(),
- Arc::new(move |view, event, phase, cx| {
- let event = event.downcast_ref().unwrap();
- listener(view, event, phase, cx)
- }),
- ));
- self
- }
}
@@ -1,8 +1,8 @@
-use std::sync::Arc;
+use std::{any::TypeId, sync::Arc};
use crate::{
- DispatchPhase, Element, EventListeners, MouseButton, MouseClickEvent, MouseDownEvent,
- MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
+ DispatchPhase, Element, EventListeners, KeyDownEvent, KeyUpEvent, MouseButton, MouseClickEvent,
+ MouseDownEvent, MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
};
pub trait Interactive: Element {
@@ -143,6 +143,73 @@ pub trait Interactive: Element {
}));
self
}
+
+ fn on_key_down(
+ mut self,
+ listener: impl Fn(
+ &mut Self::ViewState,
+ &KeyDownEvent,
+ DispatchPhase,
+ &mut ViewContext<Self::ViewState>,
+ ) + Send
+ + Sync
+ + 'static,
+ ) -> Self
+ where
+ Self: Sized,
+ {
+ self.listeners().key.push((
+ TypeId::of::<KeyDownEvent>(),
+ Arc::new(move |view, event, phase, cx| {
+ let event = event.downcast_ref().unwrap();
+ listener(view, event, phase, cx);
+ None
+ }),
+ ));
+ self
+ }
+
+ fn on_key_up(
+ mut self,
+ listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
+ + Send
+ + Sync
+ + 'static,
+ ) -> Self
+ where
+ Self: Sized,
+ {
+ self.listeners().key.push((
+ TypeId::of::<KeyUpEvent>(),
+ Arc::new(move |view, event, phase, cx| {
+ let event = event.downcast_ref().unwrap();
+ listener(view, event, phase, cx);
+ None
+ }),
+ ));
+ self
+ }
+
+ fn on_action<A: 'static>(
+ mut self,
+ listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
+ + Send
+ + Sync
+ + 'static,
+ ) -> Self
+ where
+ Self: Sized,
+ {
+ self.listeners().key.push((
+ TypeId::of::<A>(),
+ Arc::new(move |view, event, phase, cx| {
+ let event = event.downcast_ref().unwrap();
+ listener(view, event, phase, cx);
+ None
+ }),
+ ));
+ self
+ }
}
pub trait Click: Interactive {
@@ -2,11 +2,11 @@ use crate::{
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
EventEmitter, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData,
- InputEvent, IsZero, KeyListener, LayoutId, MainThread, MainThreadOnly, MonochromeSprite,
- MouseMoveEvent, Path, Pixels, Platform, PlatformAtlas, PlatformWindow, Point, PolychromeSprite,
- Quad, Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
- SceneBuilder, Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task,
- Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
+ InputEvent, IsZero, KeyListener, KeyMatch, Keystroke, LayoutId, MainThread, MainThreadOnly,
+ MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform, PlatformAtlas, PlatformWindow, Point,
+ PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams,
+ ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine,
+ Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use collections::HashMap;
@@ -45,6 +45,9 @@ pub enum DispatchPhase {
}
type AnyListener = Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
+type AnyKeyListener = Arc<
+ dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) -> Option<AnyBox> + Send + Sync + 'static,
+>;
type AnyFocusListener = Arc<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
slotmap::new_key_type! { pub struct FocusId; }
@@ -146,13 +149,13 @@ pub struct Window {
z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
- key_listeners: HashMap<TypeId, Vec<AnyListener>>,
+ key_listeners: Vec<(TypeId, AnyKeyListener)>,
key_events_enabled: bool,
focus_stack: Vec<FocusId>,
focus_parents_by_child: HashMap<FocusId, FocusId>,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
- propagate_event: bool,
+ propagate: bool,
default_prevented: bool,
mouse_position: Point<Pixels>,
scale_factor: f32,
@@ -219,12 +222,12 @@ impl Window {
z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(),
mouse_listeners: HashMap::default(),
- key_listeners: HashMap::default(),
+ key_listeners: Vec::new(),
key_events_enabled: true,
focus_stack: Vec::new(),
focus_parents_by_child: HashMap::default(),
focus_listeners: Vec::new(),
- propagate_event: true,
+ propagate: true,
default_prevented: true,
mouse_position,
scale_factor,
@@ -434,7 +437,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
pub fn stop_propagation(&mut self) {
- self.window.propagate_event = false;
+ self.window.propagate = false;
}
pub fn prevent_default(&mut self) {
@@ -462,19 +465,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
))
}
- pub fn on_keyboard_event<Event: 'static>(
- &mut self,
- handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static,
- ) {
- self.window
- .key_listeners
- .entry(TypeId::of::<Event>())
- .or_default()
- .push(Arc::new(move |event: &dyn Any, phase, cx| {
- handler(event.downcast_ref().unwrap(), phase, cx)
- }))
- }
-
pub fn mouse_position(&self) -> Point<Pixels> {
self.window.mouse_position
}
@@ -821,7 +811,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
// Clear focus state, because we determine what is focused when the new elements
// in the upcoming frame are initialized.
window.focus_listeners.clear();
- window.key_listeners.values_mut().for_each(Vec::clear);
+ window.key_listeners.clear();
window.focus_parents_by_child.clear();
window.key_events_enabled = true;
}
@@ -837,7 +827,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
}
// Handlers may set this to false by calling `stop_propagation`
- self.window.propagate_event = true;
+ self.window.propagate = true;
self.window.default_prevented = false;
if let Some(mut handlers) = self
@@ -852,16 +842,16 @@ impl<'a, 'w> WindowContext<'a, 'w> {
// special purposes, such as detecting events outside of a given Bounds.
for (_, handler) in &handlers {
handler(any_mouse_event, DispatchPhase::Capture, self);
- if !self.window.propagate_event {
+ if !self.window.propagate {
break;
}
}
// Bubble phase, where most normal handlers do their work.
- if self.window.propagate_event {
+ if self.window.propagate {
for (_, handler) in handlers.iter().rev() {
handler(any_mouse_event, DispatchPhase::Bubble, self);
- if !self.window.propagate_event {
+ if !self.window.propagate {
break;
}
}
@@ -879,43 +869,68 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.mouse_listeners
.insert(any_mouse_event.type_id(), handlers);
}
- } else if let Some(any_keyboard_event) = event.keyboard_event() {
- if let Some(mut handlers) = self
- .window
- .key_listeners
- .remove(&any_keyboard_event.type_id())
- {
- for handler in &handlers {
- handler(any_keyboard_event, DispatchPhase::Capture, self);
- if !self.window.propagate_event {
+ } else if let Some(any_key_event) = event.keyboard_event() {
+ let key_listeners = mem::take(&mut self.window.key_listeners);
+ let key_event_type = any_key_event.type_id();
+
+ for (ix, (listener_event_type, listener)) in key_listeners.iter().enumerate() {
+ if key_event_type == *listener_event_type {
+ if let Some(action) = listener(any_key_event, DispatchPhase::Capture, self) {
+ self.dispatch_action(action, &key_listeners[..ix]);
+ }
+ if !self.window.propagate {
break;
}
}
+ }
- if self.window.propagate_event {
- for handler in handlers.iter().rev() {
- handler(any_keyboard_event, DispatchPhase::Bubble, self);
- if !self.window.propagate_event {
+ if self.window.propagate {
+ for (ix, (listener_event_type, listener)) in key_listeners.iter().enumerate().rev()
+ {
+ if key_event_type == *listener_event_type {
+ if let Some(action) = listener(any_key_event, DispatchPhase::Bubble, self) {
+ self.dispatch_action(action, &key_listeners[..ix]);
+ }
+
+ if !self.window.propagate {
break;
}
}
}
-
- handlers.extend(
- self.window
- .key_listeners
- .get_mut(&any_keyboard_event.type_id())
- .into_iter()
- .flat_map(|handlers| handlers.drain(..)),
- );
- self.window
- .key_listeners
- .insert(any_keyboard_event.type_id(), handlers);
}
+
+ self.window.key_listeners = key_listeners;
}
true
}
+
+ pub fn match_keystroke(&mut self, element_id: &ElementId, keystroke: &Keystroke) -> KeyMatch {
+ todo!();
+ }
+
+ fn dispatch_action(&mut self, action: AnyBox, listeners: &[(TypeId, AnyKeyListener)]) {
+ let action_type = action.type_id();
+ for (event_type, listener) in listeners {
+ if action_type == *event_type {
+ listener(action.as_ref(), DispatchPhase::Capture, self);
+ if !self.window.propagate {
+ break;
+ }
+ }
+ }
+
+ if self.window.propagate {
+ for (event_type, listener) in listeners.iter().rev() {
+ if action_type == *event_type {
+ listener(action.as_ref(), DispatchPhase::Capture, self);
+ if !self.window.propagate {
+ break;
+ }
+ }
+ }
+ }
+ }
}
impl<'a, 'w> MainThread<WindowContext<'a, 'w>> {
@@ -1225,28 +1240,25 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
f: impl FnOnce(&mut Self) -> R,
) -> R {
if self.window.key_events_enabled {
- let handle = self.handle();
- for (type_id, listener) in key_listeners {
- let handle = handle.clone();
- let listener = listener.clone();
- self.window
- .key_listeners
- .entry(*type_id)
- .or_default()
- .push(Arc::new(move |event, phase, cx| {
+ for (event_type, listener) in key_listeners.iter().cloned() {
+ let handle = self.handle();
+ let listener = Arc::new(
+ move |event: &dyn Any, phase: DispatchPhase, cx: &mut WindowContext<'_, '_>| {
handle
.update(cx, |view, cx| listener(view, event, phase, cx))
- .log_err();
- }));
+ .log_err()
+ .flatten()
+ },
+ );
+ self.window.key_listeners.push((event_type, listener));
}
}
let result = f(self);
if self.window.key_events_enabled {
- for (type_id, _) in key_listeners {
- self.window.key_listeners.get_mut(type_id).unwrap().pop();
- }
+ let prev_len = self.window.key_listeners.len() - key_listeners.len();
+ self.window.key_listeners.truncate(prev_len);
}
result
@@ -1317,18 +1329,6 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
})
});
}
-
- pub fn on_keyboard_event<Event: 'static>(
- &mut self,
- handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
- ) {
- let handle = self.handle().upgrade(self).unwrap();
- self.window_cx.on_keyboard_event(move |event, phase, cx| {
- handle.update(cx, |view, cx| {
- handler(view, event, phase, cx);
- })
- });
- }
}
impl<'a, 'w, S: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, S> {