From 9985f388ac2c9d32dfd35f1e8a4367ff630df573 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 19 Oct 2023 17:19:25 +0200 Subject: [PATCH] Checkpoint --- crates/gpui3/src/elements/div.rs | 32 +++++-- crates/gpui3/src/events.rs | 11 ++- crates/gpui3/src/focus.rs | 52 +---------- crates/gpui3/src/gpui3.rs | 4 +- crates/gpui3/src/interactive.rs | 73 ++++++++++++++- crates/gpui3/src/keymap.rs | 16 ++++ crates/gpui3/src/window.rs | 156 +++++++++++++++---------------- 7 files changed, 203 insertions(+), 141 deletions(-) create mode 100644 crates/gpui3/src/keymap.rs diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 76561f742b8f3a3ce12318fee4cea366c6d7d5e6..37c07e2559a6e1a01681913884b37d9201c60b28 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -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, cx: &mut ViewContext, ) -> 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::(), + Arc::new(move |_, key_down, phase, cx| { + if phase == DispatchPhase::Bubble { + let key_down = key_down.downcast_ref::().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( diff --git a/crates/gpui3/src/events.rs b/crates/gpui3/src/events.rs index 58228b4175139d2da20b032e8acb8e24ec1a32d4..e7dc2e5359faee273140589fd129ed8c46c887e4 100644 --- a/crates/gpui3/src/events.rs +++ b/crates/gpui3/src/events.rs @@ -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 = Arc< + 'static, >; -pub type KeyListener = - Arc) + Send + Sync + 'static>; +pub type KeyListener = Arc< + dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext) -> Option + + Send + + Sync + + 'static, +>; pub type FocusListener = Arc) + Send + Sync + 'static>; diff --git a/crates/gpui3/src/focus.rs b/crates/gpui3/src/focus.rs index ecfda740f2296bc4e2aa24abe54210854793af18..c7cefbe27885f83c91955c06fb1c9fb53dd794cc 100644 --- a/crates/gpui3/src/focus.rs +++ b/crates/gpui3/src/focus.rs @@ -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, - ) + Send - + Sync - + 'static, - ) -> Self - where - Self: Sized, - { - self.listeners().key.push(( - TypeId::of::(), - 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) - + Send - + Sync - + 'static, - ) -> Self - where - Self: Sized, - { - self.listeners().key.push(( - TypeId::of::(), - Arc::new(move |view, event, phase, cx| { - let event = event.downcast_ref().unwrap(); - listener(view, event, phase, cx) - }), - )); - self - } } diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index caf265a60c8df828308c22524dab7d0eaa612e55..1af9a1cc222386f812fbf1e9c6d535bfafc968e8 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/crates/gpui3/src/gpui3.rs @@ -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; +type AnyBox = Box; pub trait Context { type EntityContext<'a, 'w, T: 'static + Send + Sync>; diff --git a/crates/gpui3/src/interactive.rs b/crates/gpui3/src/interactive.rs index ac150652dd1e5d9bbd27c3b6c247c2737954ba8a..9d1197419f114ac2ce1b807bb8cbb1d3ce9f14be 100644 --- a/crates/gpui3/src/interactive.rs +++ b/crates/gpui3/src/interactive.rs @@ -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, + ) + Send + + Sync + + 'static, + ) -> Self + where + Self: Sized, + { + self.listeners().key.push(( + TypeId::of::(), + 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) + + Send + + Sync + + 'static, + ) -> Self + where + Self: Sized, + { + self.listeners().key.push(( + TypeId::of::(), + Arc::new(move |view, event, phase, cx| { + let event = event.downcast_ref().unwrap(); + listener(view, event, phase, cx); + None + }), + )); + self + } + + fn on_action( + mut self, + listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext) + + Send + + Sync + + 'static, + ) -> Self + where + Self: Sized, + { + self.listeners().key.push(( + TypeId::of::(), + Arc::new(move |view, event, phase, cx| { + let event = event.downcast_ref().unwrap(); + listener(view, event, phase, cx); + None + }), + )); + self + } } pub trait Click: Interactive { diff --git a/crates/gpui3/src/keymap.rs b/crates/gpui3/src/keymap.rs new file mode 100644 index 0000000000000000000000000000000000000000..d5dae0f4a4be7acc86fde013274feb6df53991bd --- /dev/null +++ b/crates/gpui3/src/keymap.rs @@ -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), +} diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index d16539a369ab3ea748c83fa7ea3b1ad8fcd0ab4d..545c07ed2f8997cb477cd7874ac93f6207aca62c 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -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; +type AnyKeyListener = Arc< + dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) -> Option + Send + Sync + 'static, +>; type AnyFocusListener = Arc; slotmap::new_key_type! { pub struct FocusId; } @@ -146,13 +149,13 @@ pub struct Window { z_index_stack: StackingOrder, content_mask_stack: Vec>, mouse_listeners: HashMap>, - key_listeners: HashMap>, + key_listeners: Vec<(TypeId, AnyKeyListener)>, key_events_enabled: bool, focus_stack: Vec, focus_parents_by_child: HashMap, pub(crate) focus_listeners: Vec, pub(crate) focus_handles: Arc>>, - propagate_event: bool, + propagate: bool, default_prevented: bool, mouse_position: Point, 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( - &mut self, - handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static, - ) { - self.window - .key_listeners - .entry(TypeId::of::()) - .or_default() - .push(Arc::new(move |event: &dyn Any, phase, cx| { - handler(event.downcast_ref().unwrap(), phase, cx) - })) - } - pub fn mouse_position(&self) -> Point { 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> { @@ -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( - &mut self, - handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext) + 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> {