Checkpoint
This commit is contained in:
@@ -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,5 +1,6 @@
|
||||
use crate::{
|
||||
point, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point, ViewContext,
|
||||
point, AnyBox, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point,
|
||||
ViewContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
@@ -254,8 +255,12 @@ pub type ScrollWheelListener<V> = Arc<
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type KeyListener<V> =
|
||||
Arc<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
pub type KeyListener<V> = Arc<
|
||||
dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) -> Option<AnyBox>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type FocusListener<V> =
|
||||
Arc<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ mod geometry;
|
||||
mod hover;
|
||||
mod image_cache;
|
||||
mod interactive;
|
||||
mod keymap;
|
||||
mod platform;
|
||||
mod scene;
|
||||
mod style;
|
||||
@@ -38,6 +39,7 @@ pub use gpui3_macros::*;
|
||||
pub use hover::*;
|
||||
pub use image_cache::*;
|
||||
pub use interactive::*;
|
||||
pub use keymap::*;
|
||||
pub use platform::*;
|
||||
pub use refineable::*;
|
||||
pub use scene::*;
|
||||
@@ -64,7 +66,7 @@ use std::{
|
||||
};
|
||||
use taffy::TaffyLayoutEngine;
|
||||
|
||||
type AnyBox = Box<dyn Any + Send + Sync + 'static>;
|
||||
type AnyBox = Box<dyn Any + Send + Sync>;
|
||||
|
||||
pub trait Context {
|
||||
type EntityContext<'a, 'w, T: 'static + Send + Sync>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
16
crates/gpui3/src/keymap.rs
Normal file
16
crates/gpui3/src/keymap.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use crate::{AnyBox, Keystroke};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct KeyMatcher;
|
||||
|
||||
impl KeyMatcher {
|
||||
pub fn push_keystroke(&mut self, keystroke: Keystroke) -> KeyMatch {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum KeyMatch {
|
||||
None,
|
||||
Pending,
|
||||
Some(AnyBox),
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user