diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 20832a1ea38493e0bcef0e1a630869872b11d8b7..5295cb5d6712b3a33609102d6fab92a24c173498 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -1,4 +1,7 @@ -use crate::{BorrowWindow, Bounds, ElementId, FocusHandle, LayoutId, Pixels, Point, ViewContext}; +use crate::{ + BorrowWindow, Bounds, ElementId, FocusHandle, FocusListeners, LayoutId, Pixels, Point, + ViewContext, +}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::mem; @@ -55,36 +58,72 @@ impl ElementIdentity for Anonymous { } } -pub trait ElementFocusability: 'static + Send + Sync { +pub trait ElementFocusability: 'static + Send + Sync { fn focus_handle(&self) -> Option<&FocusHandle>; -} + fn focus_listeners(&self) -> Option<&FocusListeners>; -pub struct Focusable(FocusHandle); + fn initialize( + &self, + cx: &mut ViewContext, + f: impl FnOnce(&mut ViewContext) -> R, + ) -> R { + if let Some(focus_listeners) = self.focus_listeners() { + for listener in focus_listeners.iter().cloned() { + cx.on_focus_changed(move |view, event, cx| listener(view, event, cx)); + } + } -impl AsRef for Focusable { - fn as_ref(&self) -> &FocusHandle { - &self.0 + if let Some(focus_handle) = self.focus_handle().cloned() { + cx.with_focus(focus_handle, |cx| f(cx)) + } else { + f(cx) + } } } -impl ElementFocusability for Focusable { +pub struct Focusable { + pub focus_handle: FocusHandle, + pub focus_listeners: FocusListeners, +} + +impl ElementFocusability for Focusable +where + V: 'static + Send + Sync, +{ fn focus_handle(&self) -> Option<&FocusHandle> { - Some(&self.0) + Some(&self.focus_handle) + } + + fn focus_listeners(&self) -> Option<&FocusListeners> { + Some(&self.focus_listeners) } } -impl From for Focusable { +impl From for Focusable +where + V: 'static + Send + Sync, +{ fn from(value: FocusHandle) -> Self { - Self(value) + Self { + focus_handle: value, + focus_listeners: Default::default(), + } } } pub struct NonFocusable; -impl ElementFocusability for NonFocusable { +impl ElementFocusability for NonFocusable +where + V: 'static + Send + Sync, +{ fn focus_handle(&self) -> Option<&FocusHandle> { None } + + fn focus_listeners(&self) -> Option<&FocusListeners> { + None + } } pub trait ParentElement: Element { diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 8b7a2f741f0938fd87ddcd59c5a37abb60da863d..06192d82e43f2da1b2a26d80d1111dc5b258f813 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -1,10 +1,10 @@ use crate::{ Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element, - ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable, - GlobalElementId, Hover, Identified, Interactive, IntoAnyElement, KeyDownEvent, KeyMatch, - LayoutId, MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, - Overflow, ParentElement, Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement, - Styled, ViewContext, + ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, + FocusListeners, Focusable, GlobalElementId, 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; @@ -61,6 +61,26 @@ impl ScrollState { } } +pub struct Div< + V: 'static + Send + Sync, + I: ElementIdentity = Anonymous, + F: ElementFocusability = NonFocusable, +> { + identity: I, + focusability: F, + children: SmallVec<[AnyElement; 2]>, + group: Option, + base_style: StyleRefinement, + hover_style: StyleRefinement, + group_hover: Option, + active_style: StyleRefinement, + group_active: Option, + focus_style: StyleRefinement, + focus_in_style: StyleRefinement, + in_focus_style: StyleRefinement, + listeners: EventListeners, +} + pub fn div() -> Div where V: 'static + Send + Sync, @@ -82,26 +102,6 @@ where } } -pub struct Div< - V: 'static + Send + Sync, - I: ElementIdentity = Anonymous, - F: ElementFocusability = NonFocusable, -> { - identity: I, - focusability: F, - children: SmallVec<[AnyElement; 2]>, - group: Option, - base_style: StyleRefinement, - hover_style: StyleRefinement, - group_hover: Option, - active_style: StyleRefinement, - group_active: Option, - focus_style: StyleRefinement, - focus_in_style: StyleRefinement, - in_focus_style: StyleRefinement, - listeners: EventListeners, -} - struct GroupStyle { group: SharedString, style: StyleRefinement, @@ -109,7 +109,7 @@ struct GroupStyle { impl Div where - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { pub fn id(self, id: impl Into) -> Div { @@ -134,7 +134,7 @@ where impl Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { pub fn group(mut self, group: impl Into) -> Self { @@ -364,7 +364,7 @@ where I: ElementIdentity, V: 'static + Send + Sync, { - pub fn focusable(self, handle: &FocusHandle) -> Div { + pub fn focusable(self, handle: &FocusHandle) -> Div> { Div { identity: self.identity, focusability: handle.clone().into(), @@ -383,13 +383,17 @@ where } } -impl Focus for Div +impl Focus for Div> where I: ElementIdentity, V: 'static + Send + Sync, { + fn focus_listeners(&mut self) -> &mut FocusListeners { + &mut self.focusability.focus_listeners + } + fn handle(&self) -> &FocusHandle { - self.focusability.as_ref() + &self.focusability.focus_handle } fn set_focus_style(&mut self, style: StyleRefinement) { @@ -408,7 +412,7 @@ where impl Element for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { type ViewState = V; @@ -426,12 +430,8 @@ where ) -> Self::ElementState { self.with_element_id(cx, |this, global_id, cx| { let element_state = element_state.unwrap_or_default(); - for listener in this.listeners.focus.iter().cloned() { - cx.on_focus_changed(move |view, event, cx| listener(view, event, cx)); - } let mut key_listeners = mem::take(&mut this.listeners.key); - if let Some(global_id) = global_id { key_listeners.push(( TypeId::of::(), @@ -451,17 +451,11 @@ where } cx.with_key_listeners(&key_listeners, |cx| { - if let Some(focus_handle) = this.focusability.focus_handle().cloned() { - cx.with_focus(focus_handle, |cx| { - for child in &mut this.children { - child.initialize(view_state, cx); - } - }) - } else { + this.focusability.initialize(cx, |cx| { for child in &mut this.children { child.initialize(view_state, cx); } - } + }); }); this.listeners.key = key_listeners; @@ -554,7 +548,7 @@ where impl IntoAnyElement for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn into_any(self) -> AnyElement { @@ -565,7 +559,7 @@ where impl ParentElement for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { @@ -576,7 +570,7 @@ where impl Styled for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn style(&mut self) -> &mut StyleRefinement { @@ -587,7 +581,7 @@ where impl Interactive for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn listeners(&mut self) -> &mut EventListeners { @@ -598,7 +592,7 @@ where impl Hover for Div where I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn set_hover_style(&mut self, group: Option, style: StyleRefinement) { @@ -612,14 +606,14 @@ where impl Click for Div where - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { } impl Active for Div where - F: ElementFocusability, + F: ElementFocusability, V: 'static + Send + Sync, { fn set_active_style(&mut self, group: Option, style: StyleRefinement) { diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index 2cd411f0856af226a88b8580ab0bcbd17834fdf3..b0a8fe2fb037e8d388b2ccab107d0a2383a26f2e 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/crates/gpui3/src/elements/img.rs @@ -1,8 +1,8 @@ use crate::{ div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element, - ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover, - Identified, Interactive, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, - StyleRefinement, Styled, ViewContext, + ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusListeners, + Focusable, Hover, Identified, Interactive, IntoAnyElement, LayoutId, NonFocusable, Pixels, + SharedString, StyleRefinement, Styled, ViewContext, }; use futures::FutureExt; use util::ResultExt; @@ -10,7 +10,7 @@ use util::ResultExt; pub struct Img< V: 'static + Send + Sync, I: ElementIdentity = Anonymous, - F: ElementFocusability = NonFocusable, + F: ElementFocusability = NonFocusable, > { base: Div, uri: Option, @@ -32,7 +32,7 @@ impl Img where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { pub fn uri(mut self, uri: impl Into) -> Self { self.uri = Some(uri.into()); @@ -48,7 +48,7 @@ where impl Img where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { pub fn id(self, id: impl Into) -> Img { Img { @@ -63,7 +63,7 @@ impl IntoAnyElement for Img where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn into_any(self) -> AnyElement { AnyElement::new(self) @@ -74,7 +74,7 @@ impl Element for Img where V: Send + Sync + 'static, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { type ViewState = V; type ElementState = DivState; @@ -143,7 +143,7 @@ impl Styled for Img where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn style(&mut self) -> &mut StyleRefinement { self.base.style() @@ -154,7 +154,7 @@ impl Interactive for Img where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn listeners(&mut self) -> &mut EventListeners { self.base.listeners() @@ -165,7 +165,7 @@ impl Hover for Img where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn set_hover_style(&mut self, group: Option, style: StyleRefinement) { self.base.set_hover_style(group, style); @@ -175,25 +175,29 @@ where impl Click for Img where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { } impl Active for Img where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { fn set_active_style(&mut self, group: Option, style: StyleRefinement) { self.base.set_active_style(group, style) } } -impl Focus for Img +impl Focus for Img> where V: 'static + Send + Sync, I: ElementIdentity, { + fn focus_listeners(&mut self) -> &mut FocusListeners { + self.base.focus_listeners() + } + fn set_focus_style(&mut self, style: StyleRefinement) { self.base.set_focus_style(style) } diff --git a/crates/gpui3/src/elements/svg.rs b/crates/gpui3/src/elements/svg.rs index 17be310457db6a929e1882d52ab0ddf4dea8a292..b8c02df1b6e379cb2a480e93134a1133d930cb9b 100644 --- a/crates/gpui3/src/elements/svg.rs +++ b/crates/gpui3/src/elements/svg.rs @@ -1,15 +1,15 @@ use crate::{ div, Active, Anonymous, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability, - ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover, Identified, Interactive, - IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StyleRefinement, Styled, - ViewContext, + ElementId, ElementIdentity, EventListeners, Focus, FocusListeners, Focusable, Hover, + Identified, Interactive, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, + StyleRefinement, Styled, ViewContext, }; use util::ResultExt; pub struct Svg< V: 'static + Send + Sync, I: ElementIdentity = Anonymous, - F: ElementFocusability = NonFocusable, + F: ElementFocusability = NonFocusable, > { base: Div, path: Option, @@ -29,7 +29,7 @@ impl Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { pub fn path(mut self, path: impl Into) -> Self { self.path = Some(path.into()); @@ -40,7 +40,7 @@ where impl Svg where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { pub fn id(self, id: impl Into) -> Svg { Svg { @@ -54,7 +54,7 @@ impl IntoAnyElement for Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn into_any(self) -> AnyElement { AnyElement::new(self) @@ -65,7 +65,7 @@ impl Element for Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { type ViewState = V; type ElementState = DivState; @@ -117,7 +117,7 @@ impl Styled for Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn style(&mut self) -> &mut StyleRefinement { self.base.style() @@ -128,7 +128,7 @@ impl Interactive for Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn listeners(&mut self) -> &mut EventListeners { self.base.listeners() @@ -139,7 +139,7 @@ impl Hover for Svg where V: 'static + Send + Sync, I: ElementIdentity, - F: ElementFocusability, + F: ElementFocusability, { fn set_hover_style(&mut self, group: Option, style: StyleRefinement) { self.base.set_hover_style(group, style); @@ -149,25 +149,29 @@ where impl Click for Svg where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { } impl Active for Svg where V: 'static + Send + Sync, - F: ElementFocusability, + F: ElementFocusability, { fn set_active_style(&mut self, group: Option, style: StyleRefinement) { self.base.set_active_style(group, style) } } -impl Focus for Svg +impl Focus for Svg> where V: 'static + Send + Sync, I: ElementIdentity, { + fn focus_listeners(&mut self) -> &mut FocusListeners { + self.base.focus_listeners() + } + fn set_focus_style(&mut self, style: StyleRefinement) { self.base.set_focus_style(style) } diff --git a/crates/gpui3/src/events.rs b/crates/gpui3/src/events.rs index e4e43f03e03b44bd8df2d3818a571cac56ff569d..718ababf031f41c3dfadfe84d02fb24c3f9f110f 100644 --- a/crates/gpui3/src/events.rs +++ b/crates/gpui3/src/events.rs @@ -268,9 +268,6 @@ pub type KeyListener = Arc< + 'static, >; -pub type FocusListener = - Arc) + Send + Sync + 'static>; - pub struct EventListeners { pub mouse_down: SmallVec<[MouseDownListener; 2]>, pub mouse_up: SmallVec<[MouseUpListener; 2]>, @@ -278,7 +275,6 @@ pub struct EventListeners { pub mouse_move: SmallVec<[MouseMoveListener; 2]>, pub scroll_wheel: SmallVec<[ScrollWheelListener; 2]>, pub key: SmallVec<[(TypeId, KeyListener); 32]>, - pub focus: SmallVec<[FocusListener; 2]>, } impl Default for EventListeners { @@ -290,7 +286,6 @@ impl Default for EventListeners { mouse_move: SmallVec::new(), scroll_wheel: SmallVec::new(), key: SmallVec::new(), - focus: SmallVec::new(), } } } diff --git a/crates/gpui3/src/focus.rs b/crates/gpui3/src/focus.rs index c7cefbe27885f83c91955c06fb1c9fb53dd794cc..16595f2e808e28fde14d373084cccab4c70d439f 100644 --- a/crates/gpui3/src/focus.rs +++ b/crates/gpui3/src/focus.rs @@ -1,7 +1,14 @@ -use crate::{FocusEvent, FocusHandle, Interactive, StyleRefinement, ViewContext}; +use crate::{Element, FocusEvent, FocusHandle, StyleRefinement, ViewContext}; +use smallvec::SmallVec; use std::sync::Arc; -pub trait Focus: Interactive { +pub type FocusListeners = SmallVec<[FocusListener; 2]>; + +pub type FocusListener = + Arc) + Send + Sync + 'static>; + +pub trait Focus: Element { + fn focus_listeners(&mut self) -> &mut FocusListeners; fn set_focus_style(&mut self, style: StyleRefinement); fn set_focus_in_style(&mut self, style: StyleRefinement); fn set_in_focus_style(&mut self, style: StyleRefinement); @@ -42,8 +49,7 @@ pub trait Focus: Interactive { Self: Sized, { let handle = self.handle().clone(); - self.listeners() - .focus + self.focus_listeners() .push(Arc::new(move |view, event, cx| { if event.focused.as_ref() == Some(&handle) { listener(view, event, cx) @@ -63,8 +69,7 @@ pub trait Focus: Interactive { Self: Sized, { let handle = self.handle().clone(); - self.listeners() - .focus + self.focus_listeners() .push(Arc::new(move |view, event, cx| { if event.blurred.as_ref() == Some(&handle) { listener(view, event, cx) @@ -84,8 +89,7 @@ pub trait Focus: Interactive { Self: Sized, { let handle = self.handle().clone(); - self.listeners() - .focus + self.focus_listeners() .push(Arc::new(move |view, event, cx| { let descendant_blurred = event .blurred @@ -114,8 +118,7 @@ pub trait Focus: Interactive { Self: Sized, { let handle = self.handle().clone(); - self.listeners() - .focus + self.focus_listeners() .push(Arc::new(move |view, event, cx| { let descendant_blurred = event .blurred