Checkpoint
This commit is contained in:
parent
8914b94577
commit
1270bcc6ed
5 changed files with 130 additions and 26 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)>);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue