Detailed changes
@@ -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;
};
@@ -1,5 +1,9 @@
-use crate::{BorrowWindow, Bounds, ElementId, FocusHandle, LayoutId, Pixels, Point, ViewContext};
+use crate::{
+ BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, LayoutId,
+ MouseDownEvent, Pixels, Point, Style, StyleRefinement, ViewContext, WindowContext,
+};
use derive_more::{Deref, DerefMut};
+use refineable::Refineable;
pub(crate) use smallvec::SmallVec;
use std::mem;
@@ -55,34 +59,94 @@ impl ElementIdentity for Anonymous {
}
}
-pub trait ElementFocusability: 'static + Send + Sync {
- fn focus_handle(&self) -> Option<&FocusHandle>;
-}
+pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
+ fn as_focusable(&self) -> Option<&Focusable<V>>;
-pub struct Focusable(FocusHandle);
+ fn initialize<R>(
+ &self,
+ cx: &mut ViewContext<V>,
+ f: impl FnOnce(&mut ViewContext<V>) -> R,
+ ) -> R {
+ if let Some(focusable) = self.as_focusable() {
+ for listener in focusable.focus_listeners.iter().cloned() {
+ cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
+ }
+ cx.with_focus(focusable.focus_handle.clone(), |cx| f(cx))
+ } else {
+ f(cx)
+ }
+ }
-impl AsRef<FocusHandle> for Focusable {
- fn as_ref(&self) -> &FocusHandle {
- &self.0
+ fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
+ if let Some(focusable) = self.as_focusable() {
+ if focusable.focus_handle.contains_focused(cx) {
+ style.refine(&focusable.focus_in_style);
+ }
+
+ if focusable.focus_handle.within_focused(cx) {
+ style.refine(&focusable.in_focus_style);
+ }
+
+ if focusable.focus_handle.is_focused(cx) {
+ style.refine(&focusable.focus_style);
+ }
+ }
+ }
+
+ fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
+ if let Some(focusable) = self.as_focusable() {
+ let focus_handle = focusable.focus_handle.clone();
+ cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
+ if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+ if !cx.default_prevented() {
+ cx.focus(&focus_handle);
+ cx.prevent_default();
+ }
+ }
+ })
+ }
}
}
-impl ElementFocusability for Focusable {
- fn focus_handle(&self) -> Option<&FocusHandle> {
- Some(&self.0)
+pub struct Focusable<V: 'static + Send + Sync> {
+ pub focus_handle: FocusHandle,
+ pub focus_listeners: FocusListeners<V>,
+ pub focus_style: StyleRefinement,
+ pub focus_in_style: StyleRefinement,
+ pub in_focus_style: StyleRefinement,
+}
+
+impl<V> ElementFocusability<V> for Focusable<V>
+where
+ V: 'static + Send + Sync,
+{
+ fn as_focusable(&self) -> Option<&Focusable<V>> {
+ Some(self)
}
}
-impl From<FocusHandle> for Focusable {
+impl<V> From<FocusHandle> for Focusable<V>
+where
+ V: 'static + Send + Sync,
+{
fn from(value: FocusHandle) -> Self {
- Self(value)
+ Self {
+ focus_handle: value,
+ focus_listeners: FocusListeners::default(),
+ focus_style: StyleRefinement::default(),
+ focus_in_style: StyleRefinement::default(),
+ in_focus_style: StyleRefinement::default(),
+ }
}
}
pub struct NonFocusable;
-impl ElementFocusability for NonFocusable {
- fn focus_handle(&self) -> Option<&FocusHandle> {
+impl<V> ElementFocusability<V> for NonFocusable
+where
+ V: 'static + Send + Sync,
+{
+ fn as_focusable(&self) -> Option<&Focusable<V>> {
None
}
}
@@ -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, Focus, FocusHandle, FocusListeners, Focusable,
+ GlobalElementId, Hover, Identified, Interactive, InteractiveState, 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,23 @@ impl ScrollState {
}
}
+pub struct Div<
+ V: 'static + Send + Sync,
+ I: ElementIdentity = Anonymous,
+ F: ElementFocusability<V> = NonFocusable,
+> {
+ identity: I,
+ focusability: F,
+ children: SmallVec<[AnyElement<V>; 2]>,
+ group: Option<SharedString>,
+ base_style: StyleRefinement,
+ hover_style: StyleRefinement,
+ group_hover: Option<GroupStyle>,
+ active_style: StyleRefinement,
+ group_active: Option<GroupStyle>,
+ interactive_state: InteractiveState<V>,
+}
+
pub fn div<V>() -> Div<V, Anonymous, NonFocusable>
where
V: 'static + Send + Sync,
@@ -75,33 +92,10 @@ where
group_hover: None,
active_style: StyleRefinement::default(),
group_active: None,
- focus_style: StyleRefinement::default(),
- focus_in_style: StyleRefinement::default(),
- in_focus_style: StyleRefinement::default(),
- listeners: EventListeners::default(),
+ interactive_state: InteractiveState::default(),
}
}
-pub struct Div<
- V: 'static + Send + Sync,
- I: ElementIdentity = Anonymous,
- F: ElementFocusability = NonFocusable,
-> {
- identity: I,
- focusability: F,
- children: SmallVec<[AnyElement<V>; 2]>,
- group: Option<SharedString>,
- base_style: StyleRefinement,
- hover_style: StyleRefinement,
- group_hover: Option<GroupStyle>,
- active_style: StyleRefinement,
- group_active: Option<GroupStyle>,
- focus_style: StyleRefinement,
- focus_in_style: StyleRefinement,
- in_focus_style: StyleRefinement,
- listeners: EventListeners<V>,
-}
-
struct GroupStyle {
group: SharedString,
style: StyleRefinement,
@@ -109,7 +103,7 @@ struct GroupStyle {
impl<V, F> Div<V, Anonymous, F>
where
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
@@ -123,10 +117,7 @@ where
group_hover: self.group_hover,
active_style: self.active_style,
group_active: self.group_active,
- focus_style: self.focus_style,
- focus_in_style: self.focus_in_style,
- in_focus_style: self.in_focus_style,
- listeners: self.listeners,
+ interactive_state: self.interactive_state,
}
}
}
@@ -134,7 +125,7 @@ where
impl<V, I, F> Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
@@ -206,19 +197,7 @@ where
let mut computed_style = Style::default();
computed_style.refine(&self.base_style);
- if let Some(handle) = self.focusability.focus_handle() {
- if handle.contains_focused(cx) {
- computed_style.refine(&self.focus_in_style);
- }
-
- if handle.within_focused(cx) {
- computed_style.refine(&self.in_focus_style);
- }
-
- if handle.is_focused(cx) {
- computed_style.refine(&self.focus_style);
- }
- }
+ self.focusability.refine_style(&mut computed_style, cx);
let mouse_position = cx.mouse_position();
@@ -296,7 +275,7 @@ where
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
cx: &mut ViewContext<V>,
) {
- let click_listeners = mem::take(&mut self.listeners.mouse_click);
+ let click_listeners = mem::take(&mut self.interactive_state.mouse_click);
let mouse_down = pending_click.lock().clone();
if let Some(mouse_down) = mouse_down {
@@ -321,37 +300,25 @@ where
});
}
- if let Some(focus_handle) = self.focusability.focus_handle() {
- let focus_handle = focus_handle.clone();
- cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
- if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
- if !cx.default_prevented() {
- cx.focus(&focus_handle);
- cx.prevent_default();
- }
- }
- })
- }
-
- for listener in mem::take(&mut self.listeners.mouse_down) {
+ for listener in mem::take(&mut self.interactive_state.mouse_down) {
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
- for listener in mem::take(&mut self.listeners.mouse_up) {
+ for listener in mem::take(&mut self.interactive_state.mouse_up) {
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
- for listener in mem::take(&mut self.listeners.mouse_move) {
+ for listener in mem::take(&mut self.interactive_state.mouse_move) {
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
}
- for listener in mem::take(&mut self.listeners.scroll_wheel) {
+ for listener in mem::take(&mut self.interactive_state.scroll_wheel) {
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
listener(state, event, &bounds, phase, cx);
})
@@ -364,7 +331,7 @@ where
I: ElementIdentity,
V: 'static + Send + Sync,
{
- pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable> {
+ pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {
Div {
identity: self.identity,
focusability: handle.clone().into(),
@@ -375,40 +342,41 @@ where
group_hover: self.group_hover,
active_style: self.active_style,
group_active: self.group_active,
- focus_style: self.focus_style,
- focus_in_style: self.focus_in_style,
- in_focus_style: self.in_focus_style,
- listeners: self.listeners,
+ interactive_state: self.interactive_state,
}
}
}
-impl<V, I> Focus for Div<V, I, Focusable>
+impl<V, I> Focus for Div<V, I, Focusable<V>>
where
I: ElementIdentity,
V: 'static + Send + Sync,
{
+ fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
+ &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) {
- self.focus_style = style;
+ self.focusability.focus_style = style;
}
fn set_focus_in_style(&mut self, style: StyleRefinement) {
- self.focus_in_style = style;
+ self.focusability.focus_in_style = style;
}
fn set_in_focus_style(&mut self, style: StyleRefinement) {
- self.in_focus_style = style;
+ self.focusability.in_focus_style = style;
}
}
impl<V, I, F> Element for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
type ViewState = V;
@@ -426,20 +394,16 @@ 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);
+ let mut key_listeners = mem::take(&mut this.interactive_state.key);
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);
}
@@ -451,19 +415,13 @@ 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;
+ this.interactive_state.key = key_listeners;
element_state
})
@@ -526,6 +484,7 @@ where
element_state.active_state.clone(),
cx,
);
+ this.focusability.paint(bounds, cx);
this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
});
@@ -554,7 +513,7 @@ where
impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
fn into_any(self) -> AnyElement<V> {
@@ -565,7 +524,7 @@ where
impl<V, I, F> ParentElement for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
@@ -576,7 +535,7 @@ where
impl<V, I, F> Styled for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
fn style(&mut self) -> &mut StyleRefinement {
@@ -587,18 +546,18 @@ where
impl<V, I, F> Interactive for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
- fn listeners(&mut self) -> &mut EventListeners<V> {
- &mut self.listeners
+ fn interactive_state(&mut self) -> &mut InteractiveState<V> {
+ &mut self.interactive_state
}
}
impl<V, I, F> Hover for Div<V, I, F>
where
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
@@ -612,14 +571,14 @@ where
impl<V, F> Click for Div<V, Identified, F>
where
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
}
impl<V, F> Active for Div<V, Identified, F>
where
- F: ElementFocusability,
+ F: ElementFocusability<V>,
V: 'static + Send + Sync,
{
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
@@ -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, Focus, FocusListeners, Focusable, Hover,
+ Identified, Interactive, InteractiveState, 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<V> = NonFocusable,
> {
base: Div<V, I, F>,
uri: Option<SharedString>,
@@ -32,7 +32,7 @@ impl<V, I, F> Img<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
self.uri = Some(uri.into());
@@ -48,7 +48,7 @@ where
impl<V, F> Img<V, Anonymous, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified, F> {
Img {
@@ -63,7 +63,7 @@ impl<V, I, F> IntoAnyElement<V> for Img<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn into_any(self) -> AnyElement<V> {
AnyElement::new(self)
@@ -74,7 +74,7 @@ impl<V, I, F> Element for Img<V, I, F>
where
V: Send + Sync + 'static,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
type ViewState = V;
type ElementState = DivState;
@@ -143,7 +143,7 @@ impl<V, I, F> Styled for Img<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn style(&mut self) -> &mut StyleRefinement {
self.base.style()
@@ -154,10 +154,10 @@ impl<V, I, F> Interactive for Img<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
- fn listeners(&mut self) -> &mut EventListeners<V> {
- self.base.listeners()
+ fn interactive_state(&mut self) -> &mut InteractiveState<V> {
+ self.base.interactive_state()
}
}
@@ -165,7 +165,7 @@ impl<V, I, F> Hover for Img<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
self.base.set_hover_style(group, style);
@@ -175,25 +175,29 @@ where
impl<V, F> Click for Img<V, Identified, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
}
impl<V, F> Active for Img<V, Identified, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
self.base.set_active_style(group, style)
}
}
-impl<V, I> Focus for Img<V, I, Focusable>
+impl<V, I> Focus for Img<V, I, Focusable<V>>
where
V: 'static + Send + Sync,
I: ElementIdentity,
{
+ fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
+ self.base.focus_listeners()
+ }
+
fn set_focus_style(&mut self, style: StyleRefinement) {
self.base.set_focus_style(style)
}
@@ -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, Focus, FocusListeners, Focusable, Hover, Identified, Interactive,
+ InteractiveState, 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<V> = NonFocusable,
> {
base: Div<V, I, F>,
path: Option<SharedString>,
@@ -29,7 +29,7 @@ impl<V, I, F> Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
self.path = Some(path.into());
@@ -40,7 +40,7 @@ where
impl<V, F> Svg<V, Anonymous, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, Identified, F> {
Svg {
@@ -54,7 +54,7 @@ impl<V, I, F> IntoAnyElement<V> for Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn into_any(self) -> AnyElement<V> {
AnyElement::new(self)
@@ -65,7 +65,7 @@ impl<V, I, F> Element for Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
type ViewState = V;
type ElementState = DivState;
@@ -117,7 +117,7 @@ impl<V, I, F> Styled for Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn style(&mut self) -> &mut StyleRefinement {
self.base.style()
@@ -128,10 +128,10 @@ impl<V, I, F> Interactive for Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
- fn listeners(&mut self) -> &mut EventListeners<V> {
- self.base.listeners()
+ fn interactive_state(&mut self) -> &mut InteractiveState<V> {
+ self.base.interactive_state()
}
}
@@ -139,7 +139,7 @@ impl<V, I, F> Hover for Svg<V, I, F>
where
V: 'static + Send + Sync,
I: ElementIdentity,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
self.base.set_hover_style(group, style);
@@ -149,25 +149,29 @@ where
impl<V, F> Click for Svg<V, Identified, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
}
impl<V, F> Active for Svg<V, Identified, F>
where
V: 'static + Send + Sync,
- F: ElementFocusability,
+ F: ElementFocusability<V>,
{
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
self.base.set_active_style(group, style)
}
}
-impl<V, I> Focus for Svg<V, I, Focusable>
+impl<V, I> Focus for Svg<V, I, Focusable<V>>
where
V: 'static + Send + Sync,
I: ElementIdentity,
{
+ fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
+ self.base.focus_listeners()
+ }
+
fn set_focus_style(&mut self, style: StyleRefinement) {
self.base.set_focus_style(style)
}
@@ -1,290 +0,0 @@
-use crate::{
- point, Action, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point,
- ViewContext,
-};
-use smallvec::SmallVec;
-use std::{
- any::{Any, TypeId},
- ops::Deref,
- sync::Arc,
-};
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct KeyDownEvent {
- pub keystroke: Keystroke,
- pub is_held: bool,
-}
-
-#[derive(Clone, Debug)]
-pub struct KeyUpEvent {
- pub keystroke: Keystroke,
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct ModifiersChangedEvent {
- pub modifiers: Modifiers,
-}
-
-impl Deref for ModifiersChangedEvent {
- type Target = Modifiers;
-
- fn deref(&self) -> &Self::Target {
- &self.modifiers
- }
-}
-
-/// The phase of a touch motion event.
-/// Based on the winit enum of the same name.
-#[derive(Clone, Copy, Debug)]
-pub enum TouchPhase {
- Started,
- Moved,
- Ended,
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct MouseDownEvent {
- pub button: MouseButton,
- pub position: Point<Pixels>,
- pub modifiers: Modifiers,
- pub click_count: usize,
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct MouseUpEvent {
- pub button: MouseButton,
- pub position: Point<Pixels>,
- pub modifiers: Modifiers,
- pub click_count: usize,
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct MouseClickEvent {
- pub down: MouseDownEvent,
- pub up: MouseUpEvent,
-}
-
-#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
-pub enum MouseButton {
- Left,
- Right,
- Middle,
- Navigate(NavigationDirection),
-}
-
-impl MouseButton {
- pub fn all() -> Vec<Self> {
- vec![
- MouseButton::Left,
- MouseButton::Right,
- MouseButton::Middle,
- MouseButton::Navigate(NavigationDirection::Back),
- MouseButton::Navigate(NavigationDirection::Forward),
- ]
- }
-}
-
-impl Default for MouseButton {
- fn default() -> Self {
- Self::Left
- }
-}
-
-#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
-pub enum NavigationDirection {
- Back,
- Forward,
-}
-
-impl Default for NavigationDirection {
- fn default() -> Self {
- Self::Back
- }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct MouseMoveEvent {
- pub position: Point<Pixels>,
- pub pressed_button: Option<MouseButton>,
- pub modifiers: Modifiers,
-}
-
-#[derive(Clone, Debug)]
-pub struct ScrollWheelEvent {
- pub position: Point<Pixels>,
- pub delta: ScrollDelta,
- pub modifiers: Modifiers,
- pub touch_phase: TouchPhase,
-}
-
-impl Deref for ScrollWheelEvent {
- type Target = Modifiers;
-
- fn deref(&self) -> &Self::Target {
- &self.modifiers
- }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub enum ScrollDelta {
- Pixels(Point<Pixels>),
- Lines(Point<f32>),
-}
-
-impl Default for ScrollDelta {
- fn default() -> Self {
- Self::Lines(Default::default())
- }
-}
-
-impl ScrollDelta {
- pub fn precise(&self) -> bool {
- match self {
- ScrollDelta::Pixels(_) => true,
- ScrollDelta::Lines(_) => false,
- }
- }
-
- pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
- match self {
- ScrollDelta::Pixels(delta) => *delta,
- ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
- }
- }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct MouseExitEvent {
- pub position: Point<Pixels>,
- pub pressed_button: Option<MouseButton>,
- pub modifiers: Modifiers,
-}
-
-impl Deref for MouseExitEvent {
- type Target = Modifiers;
-
- fn deref(&self) -> &Self::Target {
- &self.modifiers
- }
-}
-
-#[derive(Clone, Debug)]
-pub enum InputEvent {
- KeyDown(KeyDownEvent),
- KeyUp(KeyUpEvent),
- ModifiersChanged(ModifiersChangedEvent),
- MouseDown(MouseDownEvent),
- MouseUp(MouseUpEvent),
- MouseMoved(MouseMoveEvent),
- MouseExited(MouseExitEvent),
- ScrollWheel(ScrollWheelEvent),
-}
-
-impl InputEvent {
- pub fn position(&self) -> Option<Point<Pixels>> {
- match self {
- InputEvent::KeyDown { .. } => None,
- InputEvent::KeyUp { .. } => None,
- InputEvent::ModifiersChanged { .. } => None,
- InputEvent::MouseDown(event) => Some(event.position),
- InputEvent::MouseUp(event) => Some(event.position),
- InputEvent::MouseMoved(event) => Some(event.position),
- InputEvent::MouseExited(event) => Some(event.position),
- InputEvent::ScrollWheel(event) => Some(event.position),
- }
- }
-
- pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
- match self {
- InputEvent::KeyDown { .. } => None,
- InputEvent::KeyUp { .. } => None,
- InputEvent::ModifiersChanged { .. } => None,
- InputEvent::MouseDown(event) => Some(event),
- InputEvent::MouseUp(event) => Some(event),
- InputEvent::MouseMoved(event) => Some(event),
- InputEvent::MouseExited(event) => Some(event),
- InputEvent::ScrollWheel(event) => Some(event),
- }
- }
-
- pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
- match self {
- InputEvent::KeyDown(event) => Some(event),
- InputEvent::KeyUp(event) => Some(event),
- InputEvent::ModifiersChanged(event) => Some(event),
- InputEvent::MouseDown(_) => None,
- InputEvent::MouseUp(_) => None,
- InputEvent::MouseMoved(_) => None,
- InputEvent::MouseExited(_) => None,
- InputEvent::ScrollWheel(_) => None,
- }
- }
-}
-
-pub struct FocusEvent {
- pub blurred: Option<FocusHandle>,
- pub focused: Option<FocusHandle>,
-}
-
-pub type MouseDownListener<V> = Arc<
- dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
- + Send
- + Sync
- + 'static,
->;
-pub type MouseUpListener<V> = Arc<
- dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
- + Send
- + Sync
- + 'static,
->;
-pub type MouseClickListener<V> =
- Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
-
-pub type MouseMoveListener<V> = Arc<
- dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
- + Send
- + Sync
- + 'static,
->;
-
-pub type ScrollWheelListener<V> = Arc<
- dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
- + Send
- + Sync
- + 'static,
->;
-
-pub type KeyListener<V> = Arc<
- dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) -> Option<Box<dyn Action>>
- + Send
- + Sync
- + 'static,
->;
-
-pub type FocusListener<V> =
- Arc<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]>,
- pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
- pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
- pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
- pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
- pub focus: SmallVec<[FocusListener<V>; 2]>,
-}
-
-impl<V> Default for EventListeners<V> {
- fn default() -> Self {
- Self {
- mouse_down: SmallVec::new(),
- mouse_up: SmallVec::new(),
- mouse_click: SmallVec::new(),
- mouse_move: SmallVec::new(),
- scroll_wheel: SmallVec::new(),
- key: SmallVec::new(),
- focus: SmallVec::new(),
- }
- }
-}
@@ -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<V> = SmallVec<[FocusListener<V>; 2]>;
+
+pub type FocusListener<V> =
+ Arc<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
+
+pub trait Focus: Element {
+ fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState>;
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
@@ -5,7 +5,6 @@ mod assets;
mod color;
mod element;
mod elements;
-mod events;
mod executor;
mod focus;
mod geometry;
@@ -33,7 +32,6 @@ pub use assets::*;
pub use color::*;
pub use element::*;
pub use elements::*;
-pub use events::*;
pub use executor::*;
pub use focus::*;
pub use geometry::*;
@@ -1,12 +1,17 @@
-use std::{any::TypeId, sync::Arc};
+use smallvec::SmallVec;
use crate::{
- DispatchPhase, Element, EventListeners, KeyDownEvent, KeyUpEvent, MouseButton, MouseClickEvent,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
+ point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
+ Modifiers, Pixels, Point, ViewContext,
+};
+use std::{
+ any::{Any, TypeId},
+ ops::Deref,
+ sync::Arc,
};
pub trait Interactive: Element {
- fn listeners(&mut self) -> &mut EventListeners<Self::ViewState>;
+ fn interactive_state(&mut self) -> &mut InteractiveState<Self::ViewState>;
fn on_mouse_down(
mut self,
@@ -19,16 +24,16 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
- .mouse_down
- .push(Arc::new(move |view, event, bounds, phase, cx| {
+ self.interactive_state().mouse_down.push(Arc::new(
+ move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
&& event.button == button
&& bounds.contains_point(&event.position)
{
handler(view, event, cx)
}
- }));
+ },
+ ));
self
}
@@ -43,7 +48,7 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
+ self.interactive_state()
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble
@@ -67,16 +72,16 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
- .mouse_down
- .push(Arc::new(move |view, event, bounds, phase, cx| {
+ self.interactive_state().mouse_down.push(Arc::new(
+ move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
&& event.button == button
&& !bounds.contains_point(&event.position)
{
handler(view, event, cx)
}
- }));
+ },
+ ));
self
}
@@ -91,7 +96,7 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
+ self.interactive_state()
.mouse_up
.push(Arc::new(move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Capture
@@ -114,13 +119,13 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
- .mouse_move
- .push(Arc::new(move |view, event, bounds, phase, cx| {
+ self.interactive_state().mouse_move.push(Arc::new(
+ move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
handler(view, event, cx);
}
- }));
+ },
+ ));
self
}
@@ -134,13 +139,13 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners()
- .scroll_wheel
- .push(Arc::new(move |view, event, bounds, phase, cx| {
+ self.interactive_state().scroll_wheel.push(Arc::new(
+ move |view, event, bounds, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
handler(view, event, cx);
}
- }));
+ },
+ ));
self
}
@@ -158,9 +163,9 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners().key.push((
+ self.interactive_state().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
@@ -179,9 +184,9 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners().key.push((
+ self.interactive_state().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
@@ -200,9 +205,9 @@ pub trait Interactive: Element {
where
Self: Sized,
{
- self.listeners().key.push((
+ self.interactive_state().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
@@ -223,9 +228,290 @@ pub trait Click: Interactive {
where
Self: Sized,
{
- self.listeners()
+ self.interactive_state()
.mouse_click
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
self
}
}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct KeyDownEvent {
+ pub keystroke: Keystroke,
+ pub is_held: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct KeyUpEvent {
+ pub keystroke: Keystroke,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct ModifiersChangedEvent {
+ pub modifiers: Modifiers,
+}
+
+impl Deref for ModifiersChangedEvent {
+ type Target = Modifiers;
+
+ fn deref(&self) -> &Self::Target {
+ &self.modifiers
+ }
+}
+
+/// The phase of a touch motion event.
+/// Based on the winit enum of the same name.
+#[derive(Clone, Copy, Debug)]
+pub enum TouchPhase {
+ Started,
+ Moved,
+ Ended,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseDownEvent {
+ pub button: MouseButton,
+ pub position: Point<Pixels>,
+ pub modifiers: Modifiers,
+ pub click_count: usize,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseUpEvent {
+ pub button: MouseButton,
+ pub position: Point<Pixels>,
+ pub modifiers: Modifiers,
+ pub click_count: usize,
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseClickEvent {
+ pub down: MouseDownEvent,
+ pub up: MouseUpEvent,
+}
+
+#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
+pub enum MouseButton {
+ Left,
+ Right,
+ Middle,
+ Navigate(NavigationDirection),
+}
+
+impl MouseButton {
+ pub fn all() -> Vec<Self> {
+ vec![
+ MouseButton::Left,
+ MouseButton::Right,
+ MouseButton::Middle,
+ MouseButton::Navigate(NavigationDirection::Back),
+ MouseButton::Navigate(NavigationDirection::Forward),
+ ]
+ }
+}
+
+impl Default for MouseButton {
+ fn default() -> Self {
+ Self::Left
+ }
+}
+
+#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
+pub enum NavigationDirection {
+ Back,
+ Forward,
+}
+
+impl Default for NavigationDirection {
+ fn default() -> Self {
+ Self::Back
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseMoveEvent {
+ pub position: Point<Pixels>,
+ pub pressed_button: Option<MouseButton>,
+ pub modifiers: Modifiers,
+}
+
+#[derive(Clone, Debug)]
+pub struct ScrollWheelEvent {
+ pub position: Point<Pixels>,
+ pub delta: ScrollDelta,
+ pub modifiers: Modifiers,
+ pub touch_phase: TouchPhase,
+}
+
+impl Deref for ScrollWheelEvent {
+ type Target = Modifiers;
+
+ fn deref(&self) -> &Self::Target {
+ &self.modifiers
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum ScrollDelta {
+ Pixels(Point<Pixels>),
+ Lines(Point<f32>),
+}
+
+impl Default for ScrollDelta {
+ fn default() -> Self {
+ Self::Lines(Default::default())
+ }
+}
+
+impl ScrollDelta {
+ pub fn precise(&self) -> bool {
+ match self {
+ ScrollDelta::Pixels(_) => true,
+ ScrollDelta::Lines(_) => false,
+ }
+ }
+
+ pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
+ match self {
+ ScrollDelta::Pixels(delta) => *delta,
+ ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
+ }
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct MouseExitEvent {
+ pub position: Point<Pixels>,
+ pub pressed_button: Option<MouseButton>,
+ pub modifiers: Modifiers,
+}
+
+impl Deref for MouseExitEvent {
+ type Target = Modifiers;
+
+ fn deref(&self) -> &Self::Target {
+ &self.modifiers
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum InputEvent {
+ KeyDown(KeyDownEvent),
+ KeyUp(KeyUpEvent),
+ ModifiersChanged(ModifiersChangedEvent),
+ MouseDown(MouseDownEvent),
+ MouseUp(MouseUpEvent),
+ MouseMoved(MouseMoveEvent),
+ MouseExited(MouseExitEvent),
+ ScrollWheel(ScrollWheelEvent),
+}
+
+impl InputEvent {
+ pub fn position(&self) -> Option<Point<Pixels>> {
+ match self {
+ InputEvent::KeyDown { .. } => None,
+ InputEvent::KeyUp { .. } => None,
+ InputEvent::ModifiersChanged { .. } => None,
+ InputEvent::MouseDown(event) => Some(event.position),
+ InputEvent::MouseUp(event) => Some(event.position),
+ InputEvent::MouseMoved(event) => Some(event.position),
+ InputEvent::MouseExited(event) => Some(event.position),
+ InputEvent::ScrollWheel(event) => Some(event.position),
+ }
+ }
+
+ pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
+ match self {
+ InputEvent::KeyDown { .. } => None,
+ InputEvent::KeyUp { .. } => None,
+ InputEvent::ModifiersChanged { .. } => None,
+ InputEvent::MouseDown(event) => Some(event),
+ InputEvent::MouseUp(event) => Some(event),
+ InputEvent::MouseMoved(event) => Some(event),
+ InputEvent::MouseExited(event) => Some(event),
+ InputEvent::ScrollWheel(event) => Some(event),
+ }
+ }
+
+ pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
+ match self {
+ InputEvent::KeyDown(event) => Some(event),
+ InputEvent::KeyUp(event) => Some(event),
+ InputEvent::ModifiersChanged(event) => Some(event),
+ InputEvent::MouseDown(_) => None,
+ InputEvent::MouseUp(_) => None,
+ InputEvent::MouseMoved(_) => None,
+ InputEvent::MouseExited(_) => None,
+ InputEvent::ScrollWheel(_) => None,
+ }
+ }
+}
+
+pub struct FocusEvent {
+ pub blurred: Option<FocusHandle>,
+ pub focused: Option<FocusHandle>,
+}
+
+pub type MouseDownListener<V> = Arc<
+ dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ + Send
+ + Sync
+ + 'static,
+>;
+pub type MouseUpListener<V> = Arc<
+ dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ + Send
+ + Sync
+ + 'static,
+>;
+pub type MouseClickListener<V> =
+ Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
+
+pub type MouseMoveListener<V> = Arc<
+ dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ + Send
+ + Sync
+ + 'static,
+>;
+
+pub type ScrollWheelListener<V> = Arc<
+ dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+ + Send
+ + Sync
+ + 'static,
+>;
+
+pub type KeyListener<V> = Arc<
+ dyn Fn(
+ &mut V,
+ &dyn Any,
+ &[&DispatchContext],
+ DispatchPhase,
+ &mut ViewContext<V>,
+ ) -> Option<Box<dyn Action>>
+ + Send
+ + Sync
+ + 'static,
+>;
+
+pub struct InteractiveState<V: 'static> {
+ pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
+ pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>,
+ pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
+ pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
+ pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
+ pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
+}
+
+impl<V> Default for InteractiveState<V> {
+ fn default() -> Self {
+ Self {
+ mouse_down: SmallVec::new(),
+ mouse_up: SmallVec::new(),
+ mouse_click: SmallVec::new(),
+ mouse_move: SmallVec::new(),
+ scroll_wheel: SmallVec::new(),
+ key: SmallVec::new(),
+ }
+ }
+}
@@ -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())
@@ -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()
@@ -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();
-
- 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]);
+ let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new();
+
+ 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);