Clear the state of keystroke matchers when focus changes (#3335)
Release Notes: - N/A
This commit is contained in:
@@ -60,7 +60,7 @@ impl DispatchTree {
|
||||
self.keystroke_matchers.clear();
|
||||
}
|
||||
|
||||
pub fn push_node(&mut self, context: KeyContext, old_dispatcher: &mut Self) {
|
||||
pub fn push_node(&mut self, context: KeyContext) {
|
||||
let parent = self.node_stack.last().copied();
|
||||
let node_id = DispatchNodeId(self.nodes.len());
|
||||
self.nodes.push(DispatchNode {
|
||||
@@ -71,12 +71,6 @@ impl DispatchTree {
|
||||
if !context.is_empty() {
|
||||
self.active_node().context = context.clone();
|
||||
self.context_stack.push(context);
|
||||
if let Some((context_stack, matcher)) = old_dispatcher
|
||||
.keystroke_matchers
|
||||
.remove_entry(self.context_stack.as_slice())
|
||||
{
|
||||
self.keystroke_matchers.insert(context_stack, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +81,33 @@ impl DispatchTree {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_keystroke_matchers(&mut self) {
|
||||
self.keystroke_matchers.clear();
|
||||
}
|
||||
|
||||
/// Preserve keystroke matchers from previous frames to support multi-stroke
|
||||
/// bindings across multiple frames.
|
||||
pub fn preserve_keystroke_matchers(&mut self, old_tree: &mut Self, focus_id: Option<FocusId>) {
|
||||
if let Some(node_id) = focus_id.and_then(|focus_id| self.focusable_node_id(focus_id)) {
|
||||
let dispatch_path = self.dispatch_path(node_id);
|
||||
|
||||
self.context_stack.clear();
|
||||
for node_id in dispatch_path {
|
||||
let node = self.node(node_id);
|
||||
if !node.context.is_empty() {
|
||||
self.context_stack.push(node.context.clone());
|
||||
}
|
||||
|
||||
if let Some((context_stack, matcher)) = old_tree
|
||||
.keystroke_matchers
|
||||
.remove_entry(self.context_stack.as_slice())
|
||||
{
|
||||
self.keystroke_matchers.insert(context_stack, matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_key_event(&mut self, listener: KeyListener) {
|
||||
self.active_node().key_listeners.push(listener);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
|
||||
BorrowWindow, Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId,
|
||||
Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels,
|
||||
Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use std::{
|
||||
@@ -325,12 +325,10 @@ where
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| {
|
||||
let mut element = self.component.take().unwrap().render();
|
||||
element.initialize(view, cx);
|
||||
element
|
||||
})
|
||||
self.view.update(cx, |view, cx| {
|
||||
let mut element = self.component.take().unwrap().render();
|
||||
element.initialize(view, cx);
|
||||
element
|
||||
})
|
||||
}
|
||||
|
||||
@@ -340,9 +338,7 @@ where
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) -> LayoutId {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| element.layout(view, cx))
|
||||
})
|
||||
self.view.update(cx, |view, cx| element.layout(view, cx))
|
||||
}
|
||||
|
||||
fn paint(
|
||||
@@ -352,9 +348,7 @@ where
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<ParentViewState>,
|
||||
) {
|
||||
cx.with_element_id(Some(self.view.entity_id()), |cx| {
|
||||
self.view.update(cx, |view, cx| element.paint(view, cx))
|
||||
})
|
||||
self.view.update(cx, |view, cx| element.paint(view, cx))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -393,6 +393,10 @@ impl<'a> WindowContext<'a> {
|
||||
|
||||
/// Move focus to the element associated with the given `FocusHandle`.
|
||||
pub fn focus(&mut self, handle: &FocusHandle) {
|
||||
if self.window.focus == Some(handle.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let focus_id = handle.id;
|
||||
|
||||
if self.window.last_blur.is_none() {
|
||||
@@ -400,6 +404,10 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
|
||||
self.window.focus = Some(focus_id);
|
||||
self.window
|
||||
.current_frame
|
||||
.dispatch_tree
|
||||
.clear_keystroke_matchers();
|
||||
self.app.push_effect(Effect::FocusChanged {
|
||||
window_handle: self.window.handle,
|
||||
focused: Some(focus_id),
|
||||
@@ -1091,6 +1099,14 @@ impl<'a> WindowContext<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
self.window
|
||||
.current_frame
|
||||
.dispatch_tree
|
||||
.preserve_keystroke_matchers(
|
||||
&mut self.window.previous_frame.dispatch_tree,
|
||||
self.window.focus,
|
||||
);
|
||||
|
||||
self.window.root_view = Some(root_view);
|
||||
let scene = self.window.current_frame.scene_builder.build();
|
||||
|
||||
@@ -2093,7 +2109,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
||||
window
|
||||
.current_frame
|
||||
.dispatch_tree
|
||||
.push_node(context.clone(), &mut window.previous_frame.dispatch_tree);
|
||||
.push_node(context.clone());
|
||||
if let Some(focus_handle) = focus_handle.as_ref() {
|
||||
window
|
||||
.current_frame
|
||||
|
||||
Reference in New Issue
Block a user