Checkpoint
This commit is contained in:
@@ -234,7 +234,7 @@ impl AppContext {
|
||||
fn apply_focus_changed(&mut self, window_id: WindowId, focused: Option<FocusId>) {
|
||||
self.update_window(window_id, |cx| {
|
||||
if cx.window.focus == focused {
|
||||
let mut listeners = mem::take(&mut cx.window.focus_change_listeners);
|
||||
let mut listeners = mem::take(&mut cx.window.focus_listeners);
|
||||
let focused = focused.map(FocusHandle::new);
|
||||
let blurred = cx.window.last_blur.unwrap().map(FocusHandle::new);
|
||||
let event = FocusEvent { focused, blurred };
|
||||
@@ -242,8 +242,8 @@ impl AppContext {
|
||||
listener(&event, cx);
|
||||
}
|
||||
|
||||
listeners.extend(cx.window.focus_change_listeners.drain(..));
|
||||
cx.window.focus_change_listeners = listeners;
|
||||
listeners.extend(cx.window.focus_listeners.drain(..));
|
||||
cx.window.focus_listeners = listeners;
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
|
||||
@@ -379,6 +379,7 @@ where
|
||||
self.focusability.focus_handle().cloned(),
|
||||
mem::take(&mut self.listeners.key_down),
|
||||
mem::take(&mut self.listeners.key_up),
|
||||
mem::take(&mut self.listeners.focus),
|
||||
|cx| {
|
||||
for child in &mut self.children {
|
||||
child.initialize(view_state, cx);
|
||||
|
||||
@@ -243,6 +243,9 @@ pub type KeyDownListener<V> =
|
||||
pub type KeyUpListener<V> =
|
||||
Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type FocusListener<V> =
|
||||
Box<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub struct EventListeners<V: 'static> {
|
||||
pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
@@ -251,6 +254,7 @@ pub struct EventListeners<V: 'static> {
|
||||
pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
pub key_down: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
pub key_up: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
pub focus: SmallVec<[FocusListener<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Default for EventListeners<V> {
|
||||
@@ -263,6 +267,7 @@ impl<V> Default for EventListeners<V> {
|
||||
scroll_wheel: SmallVec::new(),
|
||||
key_down: SmallVec::new(),
|
||||
key_up: SmallVec::new(),
|
||||
focus: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
use crate::{Element, EventListeners, FocusEvent, FocusHandle, ViewContext};
|
||||
|
||||
pub trait Focus: Element {
|
||||
fn handle(&self) -> &FocusHandle;
|
||||
fn listeners(&mut self) -> &mut EventListeners<Self::ViewState>;
|
||||
|
||||
fn on_focus(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event.focused.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_blur(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event.blurred.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_in(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event
|
||||
.focused
|
||||
.as_ref()
|
||||
.map_or(false, |focused| focused.contains(&handle, cx))
|
||||
{
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_out(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event
|
||||
.blurred
|
||||
.as_ref()
|
||||
.map_or(false, |blurred| handle.contains(&blurred, cx))
|
||||
{
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ mod element;
|
||||
mod elements;
|
||||
mod events;
|
||||
mod executor;
|
||||
mod focus;
|
||||
mod geometry;
|
||||
mod hover;
|
||||
mod image_cache;
|
||||
@@ -31,6 +32,7 @@ pub use element::*;
|
||||
pub use elements::*;
|
||||
pub use events::*;
|
||||
pub use executor::*;
|
||||
pub use focus::*;
|
||||
pub use geometry::*;
|
||||
pub use gpui3_macros::*;
|
||||
pub use hover::*;
|
||||
|
||||
+30
-11
@@ -1,9 +1,9 @@
|
||||
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, KeyDownEvent, KeyDownListener, KeyUpEvent, KeyUpListener, LayoutId,
|
||||
MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform,
|
||||
EventEmitter, FocusEvent, FocusListener, FontId, GlobalElementId, GlyphId, Handle, Hsla,
|
||||
ImageData, InputEvent, IsZero, KeyDownEvent, KeyDownListener, KeyUpEvent, KeyUpListener,
|
||||
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,
|
||||
@@ -42,7 +42,7 @@ pub enum DispatchPhase {
|
||||
|
||||
type AnyMouseEventListener =
|
||||
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyFocusChangeListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyDownListener =
|
||||
Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyUpListener =
|
||||
@@ -51,7 +51,7 @@ type AnyKeyUpListener =
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FocusId(usize);
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct FocusHandle {
|
||||
pub(crate) id: FocusId,
|
||||
}
|
||||
@@ -70,9 +70,14 @@ impl FocusHandle {
|
||||
}
|
||||
|
||||
pub fn within_focused(&self, cx: &WindowContext) -> bool {
|
||||
let mut ancestor = Some(self.id);
|
||||
let focused = cx.focused();
|
||||
focused.map_or(false, |focused| focused.contains(self, cx))
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, other: &Self, cx: &WindowContext) -> bool {
|
||||
let mut ancestor = Some(other.id);
|
||||
while let Some(ancestor_id) = ancestor {
|
||||
if cx.window.focus == Some(ancestor_id) {
|
||||
if self.id == ancestor_id {
|
||||
return true;
|
||||
} else {
|
||||
ancestor = cx.window.focus_parents_by_child.get(&ancestor_id).copied();
|
||||
@@ -100,7 +105,7 @@ pub struct Window {
|
||||
focus_stack: Vec<FocusStackFrame>,
|
||||
focus_parents_by_child: HashMap<FocusId, FocusId>,
|
||||
containing_focus: HashSet<FocusId>,
|
||||
pub(crate) focus_change_listeners: Vec<AnyFocusChangeListener>,
|
||||
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
||||
key_down_listeners: Vec<AnyKeyDownListener>,
|
||||
key_up_listeners: Vec<AnyKeyUpListener>,
|
||||
propagate_event: bool,
|
||||
@@ -173,7 +178,7 @@ impl Window {
|
||||
focus_parents_by_child: HashMap::default(),
|
||||
containing_focus: HashSet::default(),
|
||||
mouse_listeners: HashMap::default(),
|
||||
focus_change_listeners: Vec::new(),
|
||||
focus_listeners: Vec::new(),
|
||||
key_down_listeners: Vec::new(),
|
||||
key_up_listeners: Vec::new(),
|
||||
propagate_event: true,
|
||||
@@ -235,6 +240,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
FocusHandle { id }
|
||||
}
|
||||
|
||||
pub fn focused(&self) -> Option<FocusHandle> {
|
||||
self.window.focus.map(|id| FocusHandle::new(id))
|
||||
}
|
||||
|
||||
pub fn focus(&mut self, handle: &FocusHandle) {
|
||||
if self.window.last_blur.is_none() {
|
||||
self.window.last_blur = Some(self.window.focus);
|
||||
@@ -751,7 +760,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_change_listeners.clear();
|
||||
window.focus_listeners.clear();
|
||||
window.key_down_listeners.clear();
|
||||
window.key_up_listeners.clear();
|
||||
window.containing_focus.clear();
|
||||
@@ -1110,6 +1119,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||
focus_handle: Option<FocusHandle>,
|
||||
key_down: impl IntoIterator<Item = KeyDownListener<V>>,
|
||||
key_up: impl IntoIterator<Item = KeyUpListener<V>>,
|
||||
focus: impl IntoIterator<Item = FocusListener<V>>,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let Some(focus_handle) = focus_handle else {
|
||||
@@ -1118,6 +1128,16 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||
|
||||
let handle = self.handle();
|
||||
let window = &mut *self.window;
|
||||
|
||||
for listener in focus {
|
||||
let handle = handle.clone();
|
||||
window.focus_listeners.push(Box::new(move |event, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(parent_frame) = window.focus_stack.last() {
|
||||
window
|
||||
.focus_parents_by_child
|
||||
@@ -1150,7 +1170,6 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
|
||||
window.focus_stack.push(frame);
|
||||
|
||||
if Some(focus_handle.id) == window.focus {
|
||||
|
||||
Reference in New Issue
Block a user