Checkpoint

This commit is contained in:
Antonio Scandurra 2023-10-18 16:10:58 +02:00
parent 8914b94577
commit 1270bcc6ed
5 changed files with 130 additions and 26 deletions

View file

@ -201,6 +201,19 @@ impl InputEvent {
InputEvent::ScrollWheel(event) => Some(event), InputEvent::ScrollWheel(event) => Some(event),
} }
} }
pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
match self {
InputEvent::KeyDown(event) => Some(event),
InputEvent::KeyUp(event) => Some(event),
InputEvent::ModifiersChanged(event) => Some(event),
InputEvent::MouseDown(_) => None,
InputEvent::MouseUp(_) => None,
InputEvent::MouseMoved(_) => None,
InputEvent::MouseExited(_) => None,
InputEvent::ScrollWheel(_) => None,
}
}
} }
pub struct FocusEvent { pub struct FocusEvent {

View file

@ -1,4 +1,7 @@
use crate::{Element, EventListeners, FocusEvent, FocusHandle, ViewContext}; use crate::{
DispatchPhase, Element, EventListeners, FocusEvent, FocusHandle, KeyDownEvent, KeyUpEvent,
ViewContext,
};
pub trait Focus: Element { pub trait Focus: Element {
fn handle(&self) -> &FocusHandle; fn handle(&self) -> &FocusHandle;
@ -95,4 +98,36 @@ pub trait Focus: Element {
})); }));
self 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_down.push(Box::new(listener));
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_up.push(Box::new(listener));
self
}
} }

View file

@ -141,7 +141,7 @@ pub(crate) trait PlatformWindow {
fn minimize(&self); fn minimize(&self);
fn zoom(&self); fn zoom(&self);
fn toggle_full_screen(&self); fn toggle_full_screen(&self);
fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>); fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>); fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>); fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>);
fn on_fullscreen(&self, callback: Box<dyn FnMut(bool)>); fn on_fullscreen(&self, callback: Box<dyn FnMut(bool)>);

View file

@ -854,7 +854,7 @@ impl PlatformWindow for MacWindow {
.detach(); .detach();
} }
fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) { fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) {
self.0.as_ref().lock().event_callback = Some(callback); self.0.as_ref().lock().event_callback = Some(callback);
} }

View file

@ -10,7 +10,7 @@ use crate::{
WindowOptions, SUBPIXEL_VARIANTS, WindowOptions, SUBPIXEL_VARIANTS,
}; };
use anyhow::Result; use anyhow::Result;
use collections::{HashMap, HashSet}; use collections::HashMap;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
@ -42,6 +42,8 @@ pub enum DispatchPhase {
type AnyMouseEventListener = type AnyMouseEventListener =
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>; Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
type AnyKeyboardEventListener =
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>; type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
type AnyKeyDownListener = type AnyKeyDownListener =
Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>; Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
@ -66,7 +68,8 @@ impl FocusHandle {
} }
pub fn contains_focused(&self, cx: &WindowContext) -> bool { pub fn contains_focused(&self, cx: &WindowContext) -> bool {
cx.window.containing_focus.contains(&self.id) cx.focused()
.map_or(false, |focused| self.contains(&focused, cx))
} }
pub fn within_focused(&self, cx: &WindowContext) -> bool { pub fn within_focused(&self, cx: &WindowContext) -> bool {
@ -102,12 +105,10 @@ pub struct Window {
z_index_stack: StackingOrder, z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>, content_mask_stack: Vec<ContentMask<Pixels>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseEventListener)>>, mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseEventListener)>>,
keyboard_listeners: HashMap<TypeId, Vec<AnyKeyboardEventListener>>,
focus_stack: Vec<FocusStackFrame>, focus_stack: Vec<FocusStackFrame>,
focus_parents_by_child: HashMap<FocusId, FocusId>, focus_parents_by_child: HashMap<FocusId, FocusId>,
containing_focus: HashSet<FocusId>,
pub(crate) focus_listeners: Vec<AnyFocusListener>, pub(crate) focus_listeners: Vec<AnyFocusListener>,
key_down_listeners: Vec<AnyKeyDownListener>,
key_up_listeners: Vec<AnyKeyUpListener>,
propagate_event: bool, propagate_event: bool,
mouse_position: Point<Pixels>, mouse_position: Point<Pixels>,
scale_factor: f32, scale_factor: f32,
@ -149,7 +150,7 @@ impl Window {
} }
})); }));
platform_window.on_event({ platform_window.on_input({
let cx = cx.to_async(); let cx = cx.to_async();
Box::new(move |event| { Box::new(move |event| {
cx.update_window(handle, |cx| cx.dispatch_event(event)) cx.update_window(handle, |cx| cx.dispatch_event(event))
@ -174,13 +175,11 @@ impl Window {
element_states: HashMap::default(), element_states: HashMap::default(),
z_index_stack: StackingOrder(SmallVec::new()), z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(), content_mask_stack: Vec::new(),
mouse_listeners: HashMap::default(),
keyboard_listeners: HashMap::default(),
focus_stack: Vec::new(), focus_stack: Vec::new(),
focus_parents_by_child: HashMap::default(), focus_parents_by_child: HashMap::default(),
containing_focus: HashSet::default(),
mouse_listeners: HashMap::default(),
focus_listeners: Vec::new(), focus_listeners: Vec::new(),
key_down_listeners: Vec::new(),
key_up_listeners: Vec::new(),
propagate_event: true, propagate_event: true,
mouse_position, mouse_position,
scale_factor, scale_factor,
@ -415,6 +414,19 @@ 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
.keyboard_listeners
.entry(TypeId::of::<Event>())
.or_default()
.push(Box::new(move |event: &dyn Any, phase, cx| {
handler(event.downcast_ref().unwrap(), phase, cx)
}))
}
pub fn mouse_position(&self) -> Point<Pixels> { pub fn mouse_position(&self) -> Point<Pixels> {
self.window.mouse_position self.window.mouse_position
} }
@ -761,9 +773,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
// Clear focus state, because we determine what is focused when the new elements // Clear focus state, because we determine what is focused when the new elements
// in the upcoming frame are initialized. // in the upcoming frame are initialized.
window.focus_listeners.clear(); window.focus_listeners.clear();
window.key_down_listeners.clear(); window.keyboard_listeners.values_mut().for_each(Vec::clear);
window.key_up_listeners.clear();
window.containing_focus.clear();
window.focus_parents_by_child.clear(); window.focus_parents_by_child.clear();
} }
@ -819,6 +829,39 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.mouse_listeners .mouse_listeners
.insert(any_mouse_event.type_id(), handlers); .insert(any_mouse_event.type_id(), handlers);
} }
} else if let Some(any_keyboard_event) = event.keyboard_event() {
if let Some(mut handlers) = self
.window
.keyboard_listeners
.remove(&any_keyboard_event.type_id())
{
for handler in &handlers {
handler(any_keyboard_event, DispatchPhase::Capture, self);
if !self.window.propagate_event {
break;
}
}
if self.window.propagate_event {
for handler in handlers.iter().rev() {
handler(any_keyboard_event, DispatchPhase::Bubble, self);
if !self.window.propagate_event {
break;
}
}
}
handlers.extend(
self.window
.keyboard_listeners
.get_mut(&any_keyboard_event.type_id())
.into_iter()
.flat_map(|handlers| handlers.drain(..)),
);
self.window
.keyboard_listeners
.insert(any_keyboard_event.type_id(), handlers);
}
} }
true true
@ -1138,7 +1181,8 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
})); }));
} }
if let Some(parent_frame) = window.focus_stack.last() { let mut focus_stack = mem::take(&mut window.focus_stack);
if let Some(parent_frame) = focus_stack.last() {
window window
.focus_parents_by_child .focus_parents_by_child
.insert(focus_handle.id, parent_frame.handle.id); .insert(focus_handle.id, parent_frame.handle.id);
@ -1170,20 +1214,20 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
.log_err(); .log_err();
})); }));
} }
window.focus_stack.push(frame); focus_stack.push(frame);
if Some(focus_handle.id) == window.focus { if Some(focus_handle.id) == window.focus {
for frame in &mut window.focus_stack { for focus_frame in &mut focus_stack {
window.containing_focus.insert(frame.handle.id); for listener in focus_frame.key_down_listeners.drain(..) {
window self.window_cx.on_keyboard_event(listener);
.key_down_listeners }
.extend(frame.key_down_listeners.drain(..)); for listener in focus_frame.key_up_listeners.drain(..) {
window self.window_cx.on_keyboard_event(listener);
.key_up_listeners }
.extend(frame.key_up_listeners.drain(..));
} }
} }
self.window.focus_stack = focus_stack;
let result = f(self); let result = f(self);
self.window.focus_stack.pop(); self.window.focus_stack.pop();
result result
@ -1232,6 +1276,18 @@ 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> { impl<'a, 'w, S: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, S> {