Checkpoint

This commit is contained in:
Antonio Scandurra
2023-10-19 22:05:01 +02:00
parent d5fc831321
commit e74285f6d2
7 changed files with 168 additions and 71 deletions
+4 -4
View File
@@ -10,14 +10,14 @@ pub trait Action: Any + Send + Sync {
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct ActionContext {
pub struct DispatchContext {
set: HashSet<SharedString>,
map: HashMap<SharedString, SharedString>,
}
impl ActionContext {
impl DispatchContext {
pub fn new() -> Self {
ActionContext {
DispatchContext {
set: HashSet::default(),
map: HashMap::default(),
}
@@ -68,7 +68,7 @@ impl ActionContextPredicate {
}
}
pub fn eval(&self, contexts: &[ActionContext]) -> bool {
pub fn eval(&self, contexts: &[&DispatchContext]) -> bool {
let Some(context) = contexts.first() else {
return false;
};
+2 -2
View File
@@ -435,11 +435,11 @@ where
if let Some(global_id) = global_id {
key_listeners.push((
TypeId::of::<KeyDownEvent>(),
Arc::new(move |_, key_down, phase, cx| {
Arc::new(move |_, key_down, context, phase, cx| {
if phase == DispatchPhase::Bubble {
let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
if let KeyMatch::Some(action) =
cx.match_keystroke(&global_id, &key_down.keystroke)
cx.match_keystroke(&global_id, &key_down.keystroke, context)
{
return Some(action);
}
+9 -3
View File
@@ -1,6 +1,6 @@
use crate::{
point, Action, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point,
ViewContext,
point, Action, Bounds, DispatchContext, DispatchPhase, FocusHandle, Keystroke, Modifiers,
Pixels, Point, ViewContext,
};
use smallvec::SmallVec;
use std::{
@@ -256,7 +256,13 @@ pub type ScrollWheelListener<V> = Arc<
>;
pub type KeyListener<V> = Arc<
dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) -> Option<Box<dyn Action>>
dyn Fn(
&mut V,
&dyn Any,
&[&DispatchContext],
DispatchPhase,
&mut ViewContext<V>,
) -> Option<Box<dyn Action>>
+ Send
+ Sync
+ 'static,
+3 -3
View File
@@ -160,7 +160,7 @@ pub trait Interactive: Element {
{
self.listeners().key.push((
TypeId::of::<KeyDownEvent>(),
Arc::new(move |view, event, phase, cx| {
Arc::new(move |view, event, _, phase, cx| {
let event = event.downcast_ref().unwrap();
listener(view, event, phase, cx);
None
@@ -181,7 +181,7 @@ pub trait Interactive: Element {
{
self.listeners().key.push((
TypeId::of::<KeyUpEvent>(),
Arc::new(move |view, event, phase, cx| {
Arc::new(move |view, event, _, phase, cx| {
let event = event.downcast_ref().unwrap();
listener(view, event, phase, cx);
None
@@ -202,7 +202,7 @@ pub trait Interactive: Element {
{
self.listeners().key.push((
TypeId::of::<A>(),
Arc::new(move |view, event, phase, cx| {
Arc::new(move |view, event, _, phase, cx| {
let event = event.downcast_ref().unwrap();
listener(view, event, phase, cx);
None
+4 -4
View File
@@ -1,4 +1,4 @@
use crate::{Action, ActionContext, ActionContextPredicate, KeyMatch, Keystroke};
use crate::{Action, ActionContextPredicate, DispatchContext, KeyMatch, Keystroke};
use anyhow::Result;
use smallvec::SmallVec;
@@ -32,7 +32,7 @@ impl KeyBinding {
})
}
pub fn matches_context(&self, contexts: &[ActionContext]) -> bool {
pub fn matches_context(&self, contexts: &[&DispatchContext]) -> bool {
self.context_predicate
.as_ref()
.map(|predicate| predicate.eval(contexts))
@@ -42,7 +42,7 @@ impl KeyBinding {
pub fn match_keystrokes(
&self,
pending_keystrokes: &[Keystroke],
contexts: &[ActionContext],
contexts: &[&DispatchContext],
) -> KeyMatch {
if self.keystrokes.as_ref().starts_with(&pending_keystrokes)
&& self.matches_context(contexts)
@@ -61,7 +61,7 @@ impl KeyBinding {
pub fn keystrokes_for_action(
&self,
action: &dyn Action,
contexts: &[ActionContext],
contexts: &[&DispatchContext],
) -> Option<SmallVec<[Keystroke; 2]>> {
if self.action.eq(action) && self.matches_context(contexts) {
Some(self.keystrokes.clone())
+3 -3
View File
@@ -1,4 +1,4 @@
use crate::{Action, ActionContext, Keymap, KeymapVersion, Keystroke};
use crate::{Action, DispatchContext, Keymap, KeymapVersion, Keystroke};
use parking_lot::RwLock;
use smallvec::SmallVec;
use std::sync::Arc;
@@ -44,7 +44,7 @@ impl KeyMatcher {
pub fn match_keystroke(
&mut self,
keystroke: &Keystroke,
context_stack: &[ActionContext],
context_stack: &[&DispatchContext],
) -> KeyMatch {
let keymap = self.keymap.read();
// Clear pending keystrokes if the keymap has changed since the last matched keystroke.
@@ -86,7 +86,7 @@ impl KeyMatcher {
pub fn keystrokes_for_action(
&self,
action: &dyn Action,
contexts: &[ActionContext],
contexts: &[&DispatchContext],
) -> Option<SmallVec<[Keystroke; 2]>> {
self.keymap
.read()
+143 -52
View File
@@ -1,13 +1,13 @@
use crate::{
px, size, Action, 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, KeyMatch, KeyMatcher, 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,
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext,
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId,
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
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;
@@ -47,7 +47,12 @@ 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<Box<dyn Action>>
dyn Fn(
&dyn Any,
&[&DispatchContext],
DispatchPhase,
&mut WindowContext,
) -> Option<Box<dyn Action>>
+ Send
+ Sync
+ 'static,
@@ -155,8 +160,8 @@ pub struct Window {
z_index_stack: StackingOrder,
content_mask_stack: Vec<ContentMask<Pixels>>,
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
key_listeners: Vec<(TypeId, AnyKeyListener)>,
key_events_enabled: bool,
key_dispatch_stack: Vec<KeyDispatchStackFrame>,
freeze_key_dispatch_stack: bool,
focus_stack: Vec<FocusId>,
focus_parents_by_child: HashMap<FocusId, FocusId>,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
@@ -230,24 +235,32 @@ impl Window {
z_index_stack: StackingOrder(SmallVec::new()),
content_mask_stack: Vec::new(),
mouse_listeners: HashMap::default(),
key_listeners: Vec::new(),
key_events_enabled: true,
key_dispatch_stack: Vec::new(),
freeze_key_dispatch_stack: false,
focus_stack: Vec::new(),
focus_parents_by_child: HashMap::default(),
focus_listeners: Vec::new(),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
propagate: true,
default_prevented: true,
mouse_position,
scale_factor,
scene_builder: SceneBuilder::new(),
dirty: true,
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
last_blur: None,
focus: None,
}
}
}
enum KeyDispatchStackFrame {
Listener {
event_type: TypeId,
listener: AnyKeyListener,
},
Context(DispatchContext),
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[repr(C)]
pub struct ContentMask<P: Clone + Default + Debug> {
@@ -833,9 +846,9 @@ 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.clear();
window.key_dispatch_stack.clear();
window.focus_parents_by_child.clear();
window.key_events_enabled = true;
window.freeze_key_dispatch_stack = false;
}
fn dispatch_event(&mut self, event: InputEvent) -> bool {
@@ -888,36 +901,67 @@ impl<'a, 'w> WindowContext<'a, 'w> {
.insert(any_mouse_event.type_id(), handlers);
}
} else if let Some(any_key_event) = event.keyboard_event() {
let key_listeners = mem::take(&mut self.window.key_listeners);
let key_dispatch_stack = mem::take(&mut self.window.key_dispatch_stack);
let key_event_type = any_key_event.type_id();
let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new();
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]);
for (ix, frame) in key_dispatch_stack.iter().enumerate() {
match frame {
KeyDispatchStackFrame::Listener {
event_type,
listener,
} => {
if key_event_type == *event_type {
if let Some(action) = listener(
any_key_event,
&context_stack,
DispatchPhase::Capture,
self,
) {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
}
if !self.window.propagate {
break;
}
}
}
if !self.window.propagate {
break;
KeyDispatchStackFrame::Context(context) => {
context_stack.push(&context);
}
}
}
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]);
}
for (ix, frame) in key_dispatch_stack.iter().enumerate().rev() {
match frame {
KeyDispatchStackFrame::Listener {
event_type,
listener,
} => {
if key_event_type == *event_type {
if let Some(action) = listener(
any_key_event,
&context_stack,
DispatchPhase::Bubble,
self,
) {
self.dispatch_action(action, &key_dispatch_stack[..ix]);
}
if !self.window.propagate {
break;
if !self.window.propagate {
break;
}
}
}
KeyDispatchStackFrame::Context(_) => {
context_stack.pop();
}
}
}
}
self.window.key_listeners = key_listeners;
drop(context_stack);
self.window.key_dispatch_stack = key_dispatch_stack;
}
true
@@ -927,13 +971,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
&mut self,
element_id: &GlobalElementId,
keystroke: &Keystroke,
context_stack: &[&DispatchContext],
) -> KeyMatch {
let key_match = self
.window
.key_matchers
.get_mut(element_id)
.unwrap()
.match_keystroke(keystroke, &[]);
.match_keystroke(keystroke, context_stack);
if key_match.is_some() {
for matcher in self.window.key_matchers.values_mut() {
@@ -944,23 +989,39 @@ impl<'a, 'w> WindowContext<'a, 'w> {
key_match
}
fn dispatch_action(&mut self, action: Box<dyn Action>, listeners: &[(TypeId, AnyKeyListener)]) {
fn dispatch_action(
&mut self,
action: Box<dyn Action>,
dispatch_stack: &[KeyDispatchStackFrame],
) {
let action_type = action.as_any().type_id();
for (event_type, listener) in listeners {
if action_type == *event_type {
listener(action.as_any(), DispatchPhase::Capture, self);
if !self.window.propagate {
break;
for stack_frame in dispatch_stack {
if let KeyDispatchStackFrame::Listener {
event_type,
listener,
} = stack_frame
{
if action_type == *event_type {
listener(action.as_any(), &[], 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_any(), DispatchPhase::Bubble, self);
if !self.window.propagate {
break;
for stack_frame in dispatch_stack.iter().rev() {
if let KeyDispatchStackFrame::Listener {
event_type,
listener,
} = stack_frame
{
if action_type == *event_type {
listener(action.as_any(), &[], DispatchPhase::Bubble, self);
if !self.window.propagate {
break;
}
}
}
}
@@ -1287,26 +1348,56 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
key_listeners: &[(TypeId, KeyListener<V>)],
f: impl FnOnce(&mut Self) -> R,
) -> R {
if self.window.key_events_enabled {
if !self.window.freeze_key_dispatch_stack {
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<'_, '_>| {
move |event: &dyn Any,
context_stack: &[&DispatchContext],
phase: DispatchPhase,
cx: &mut WindowContext<'_, '_>| {
handle
.update(cx, |view, cx| listener(view, event, phase, cx))
.update(cx, |view, cx| {
listener(view, event, context_stack, phase, cx)
})
.log_err()
.flatten()
},
);
self.window.key_listeners.push((event_type, listener));
self.window
.key_dispatch_stack
.push(KeyDispatchStackFrame::Listener {
event_type,
listener,
});
}
}
let result = f(self);
if self.window.key_events_enabled {
let prev_len = self.window.key_listeners.len() - key_listeners.len();
self.window.key_listeners.truncate(prev_len);
if !self.window.freeze_key_dispatch_stack {
let prev_len = self.window.key_dispatch_stack.len() - key_listeners.len();
self.window.key_dispatch_stack.truncate(prev_len);
}
result
}
pub fn with_key_dispatch_context<R>(
&mut self,
context: DispatchContext,
f: impl FnOnce(&mut Self) -> R,
) -> R {
if !self.window.freeze_key_dispatch_stack {
self.window
.key_dispatch_stack
.push(KeyDispatchStackFrame::Context(context));
}
let result = f(self);
if !self.window.freeze_key_dispatch_stack {
self.window.key_dispatch_stack.pop();
}
result
@@ -1325,7 +1416,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
self.window.focus_stack.push(focus_handle.id);
if Some(focus_handle.id) == self.window.focus {
self.window.key_events_enabled = false;
self.window.freeze_key_dispatch_stack = true;
}
let result = f(self);