Checkpoint

This commit is contained in:
Antonio Scandurra
2023-10-18 15:46:17 +02:00
parent acca8ea786
commit 8914b94577
6 changed files with 139 additions and 14 deletions
+3 -3
View File
@@ -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();
+1
View File
@@ -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);
+5
View File
@@ -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(),
}
}
}
+98
View File
@@ -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
}
}
+2
View File
@@ -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
View File
@@ -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 {