Unified · Split
| @@ -1,11 +1,15 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, LayoutId, | 2 | BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, KeyDownEvent, |
| 3 | MouseDownEvent, Pixels, Point, Style, StyleRefinement, ViewContext, WindowContext, | 3 | KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener, MouseDownEvent, |
| 4 | MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent, MouseUpListener, Pixels, | ||
| 5 | Point, ScrollWheelEvent, ScrollWheelListener, Style, StyleRefinement, ViewContext, | ||
| 6 | WindowContext, | ||
| 4 | }; | 7 | }; |
| 5 | use derive_more::{Deref, DerefMut}; | 8 | use derive_more::{Deref, DerefMut}; |
| 9 | use parking_lot::Mutex; | ||
| 6 | use refineable::Refineable; | 10 | use refineable::Refineable; |
| 7 | pub(crate) use smallvec::SmallVec; | 11 | pub(crate) use smallvec::SmallVec; |
| 8 | use std::{marker::PhantomData, mem}; | 12 | use std::{any::TypeId, mem, sync::Arc}; |
| 9 | 13 | ||
| 10 | pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> { | 14 | pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> { |
| 11 | type ViewState: 'static + Send + Sync; | 15 | type ViewState: 'static + Send + Sync; |
| @@ -40,19 +44,98 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> { · 28 unmodified lines | |||
| 40 | pub struct GlobalElementId(SmallVec<[ElementId; 32]>); | 44 | pub struct GlobalElementId(SmallVec<[ElementId; 32]>); |
| 41 | 45 | ||
| 42 | pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync { | 46 | pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync { |
| 47 | fn as_stateless(&self) -> &StatelessInteractivity<V>; | ||
| 48 | fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>; | ||
| 43 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>; | 49 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>; |
| 50 | fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>; | ||
| 51 | |||
| 52 | fn paint( | ||
| 53 | &mut self, | ||
| 54 | bounds: Bounds<Pixels>, | ||
| 55 | pending_click: Arc<Mutex<Option<MouseDownEvent>>>, | ||
| 56 | cx: &mut ViewContext<V>, | ||
| 57 | ) { | ||
| 58 | let stateless = self.as_stateless(); | ||
| 59 | for listener in stateless.mouse_down_listeners.iter().cloned() { | ||
| 60 | cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| { | ||
| 61 | listener(state, event, &bounds, phase, cx); | ||
| 62 | }) | ||
| 63 | } | ||
| 64 | |||
| 65 | for listener in stateless.mouse_up_listeners.iter().cloned() { | ||
| 66 | cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| { | ||
| 67 | listener(state, event, &bounds, phase, cx); | ||
| 68 | }) | ||
| 69 | } | ||
| 70 | |||
| 71 | for listener in stateless.mouse_move_listeners.iter().cloned() { | ||
| 72 | cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| { | ||
| 73 | listener(state, event, &bounds, phase, cx); | ||
| 74 | }) | ||
| 75 | } | ||
| 76 | |||
| 77 | for listener in stateless.scroll_wheel_listeners.iter().cloned() { | ||
| 78 | cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| { | ||
| 79 | listener(state, event, &bounds, phase, cx); | ||
| 80 | }) | ||
| 81 | } | ||
| 82 | |||
| 83 | if let Some(stateful) = self.as_stateful() { | ||
| 84 | let click_listeners = stateful.mouse_click_listeners.clone(); | ||
| 85 | |||
| 86 | let mouse_down = pending_click.lock().clone(); | ||
| 87 | if let Some(mouse_down) = mouse_down { | ||
| 88 | cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| { | ||
| 89 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | ||
| 90 | let mouse_click = MouseClickEvent { | ||
| 91 | down: mouse_down.clone(), | ||
| 92 | up: event.clone(), | ||
| 93 | }; | ||
| 94 | for listener in &click_listeners { | ||
| 95 | listener(state, &mouse_click, cx); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | *pending_click.lock() = None; | ||
| 100 | }); | ||
| 101 | } else { | ||
| 102 | cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| { | ||
| 103 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | ||
| 104 | *pending_click.lock() = Some(event.clone()); | ||
| 105 | } | ||
| 106 | }); | ||
| 107 | }; | ||
| 108 | } | ||
| 109 | } | ||
| 44 | 110 | ||
| 45 | fn initialize<R>( | 111 | fn initialize<R>( |
| 46 | &self, | 112 | &mut self, |
| 47 | cx: &mut ViewContext<V>, | 113 | cx: &mut ViewContext<V>, |
| 48 | f: impl FnOnce(Option<GlobalElementId>, &mut ViewContext<V>) -> R, | 114 | f: impl FnOnce(&mut ViewContext<V>) -> R, |
| 49 | ) -> R { | 115 | ) -> R { |
| 50 | if let Some(identified) = self.as_stateful() { | 116 | if let Some(stateful) = self.as_stateful_mut() { |
| 51 | cx.with_element_id(identified.id.clone(), |global_id, cx| { | 117 | cx.with_element_id(stateful.id.clone(), |global_id, cx| { |
| 52 | f(Some(global_id), cx) | 118 | stateful.key_listeners.push(( |
| 119 | TypeId::of::<KeyDownEvent>(), | ||
| 120 | Arc::new(move |_, key_down, context, phase, cx| { | ||
| 121 | if phase == DispatchPhase::Bubble { | ||
| 122 | let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap(); | ||
| 123 | if let KeyMatch::Some(action) = | ||
| 124 | cx.match_keystroke(&global_id, &key_down.keystroke, context) | ||
| 125 | { | ||
| 126 | return Some(action); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | None | ||
| 131 | }), | ||
| 132 | )); | ||
| 133 | let result = stateful.stateless.initialize(cx, f); | ||
| 134 | stateful.key_listeners.pop(); | ||
| 135 | result | ||
| 53 | }) | 136 | }) |
| 54 | } else { | 137 | } else { |
| 55 | f(None, cx) | 138 | cx.with_key_listeners(&self.as_stateless().key_listeners, f) |
| 56 | } | 139 | } |
| 57 | } | 140 | } |
| 58 | } | 141 | } |
| @@ -62,7 +145,8 @@ pub struct StatefulInteractivity<V: 'static + Send + Sync> { · 3 unmodified lines | |||
| 62 | pub id: ElementId, | 145 | pub id: ElementId, |
| 63 | #[deref] | 146 | #[deref] |
| 64 | #[deref_mut] | 147 | #[deref_mut] |
| 65 | common: StatelessInteractivity<V>, | 148 | stateless: StatelessInteractivity<V>, |
| 149 | pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>, | ||
| 66 | } | 150 | } |
| 67 | 151 | ||
| 68 | impl<V> ElementInteractivity<V> for StatefulInteractivity<V> | 152 | impl<V> ElementInteractivity<V> for StatefulInteractivity<V> |
| @@ -72,6 +156,18 @@ where · 3 unmodified lines | |||
| 72 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> { | 156 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> { |
| 73 | Some(self) | 157 | Some(self) |
| 74 | } | 158 | } |
| 159 | |||
| 160 | fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> { | ||
| 161 | Some(self) | ||
| 162 | } | ||
| 163 | |||
| 164 | fn as_stateless(&self) -> &StatelessInteractivity<V> { | ||
| 165 | &self.stateless | ||
| 166 | } | ||
| 167 | |||
| 168 | fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> { | ||
| 169 | &mut self.stateless | ||
| 170 | } | ||
| 75 | } | 171 | } |
| 76 | 172 | ||
| 77 | impl<V> From<ElementId> for StatefulInteractivity<V> | 173 | impl<V> From<ElementId> for StatefulInteractivity<V> |
| @@ -81,16 +177,29 @@ where · 3 unmodified lines | |||
| 81 | fn from(id: ElementId) -> Self { | 177 | fn from(id: ElementId) -> Self { |
| 82 | Self { | 178 | Self { |
| 83 | id, | 179 | id, |
| 84 | common: StatelessInteractivity::default(), | 180 | stateless: StatelessInteractivity::default(), |
| 181 | mouse_click_listeners: SmallVec::new(), | ||
| 85 | } | 182 | } |
| 86 | } | 183 | } |
| 87 | } | 184 | } |
| 88 | 185 | ||
| 89 | pub struct StatelessInteractivity<V>(PhantomData<V>); | 186 | pub struct StatelessInteractivity<V> { |
| 187 | pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>, | ||
| 188 | pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>, | ||
| 189 | pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>, | ||
| 190 | pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>, | ||
| 191 | pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>, | ||
| 192 | } | ||
| 90 | 193 | ||
| 91 | impl<V> Default for StatelessInteractivity<V> { | 194 | impl<V> Default for StatelessInteractivity<V> { |
| 92 | fn default() -> Self { | 195 | fn default() -> Self { |
| 93 | Self(PhantomData) | 196 | Self { |
| 197 | mouse_down_listeners: SmallVec::new(), | ||
| 198 | mouse_up_listeners: SmallVec::new(), | ||
| 199 | mouse_move_listeners: SmallVec::new(), | ||
| 200 | scroll_wheel_listeners: SmallVec::new(), | ||
| 201 | key_listeners: SmallVec::new(), | ||
| 202 | } | ||
| 94 | } | 203 | } |
| 95 | } | 204 | } |
| 96 | 205 | ||
| @@ -101,6 +210,18 @@ where · 4 unmodified lines | |||
| 101 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> { | 210 | fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> { |
| 102 | None | 211 | None |
| 103 | } | 212 | } |
| 213 | |||
| 214 | fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> { | ||
| 215 | None | ||
| 216 | } | ||
| 217 | |||
| 218 | fn as_stateless(&self) -> &StatelessInteractivity<V> { | ||
| 219 | self | ||
| 220 | } | ||
| 221 | |||
| 222 | fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> { | ||
| 223 | self | ||
| 224 | } | ||
| 104 | } | 225 | } |
| 105 | 226 | ||
| 106 | pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync { | 227 | pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync { |
| @@ -1,16 +1,16 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | Active, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element, | 2 | Active, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element, |
| 3 | ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, | 3 | ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, |
| 4 | Focusable, GlobalElementId, Hover, Interactive, Interactivity, IntoAnyElement, KeyDownEvent, | 4 | Focusable, GlobalElementId, Hover, IntoAnyElement, LayoutId, MouseDownEvent, MouseMoveEvent, |
| 5 | KeyMatch, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow, | 5 | MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString, |
| 6 | ParentElement, Pixels, Point, SharedString, StatefulInteractivity, StatelessInteractivity, | 6 | StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive, |
| 7 | Style, StyleRefinement, Styled, ViewContext, | 7 | Style, StyleRefinement, Styled, ViewContext, |
| 8 | }; | 8 | }; |
| 9 | use collections::HashMap; | 9 | use collections::HashMap; |
| 10 | use parking_lot::Mutex; | 10 | use parking_lot::Mutex; |
| 11 | use refineable::Refineable; | 11 | use refineable::Refineable; |
| 12 | use smallvec::SmallVec; | 12 | use smallvec::SmallVec; |
| 13 | use std::{any::TypeId, mem, sync::Arc}; | 13 | use std::sync::Arc; |
| 14 | 14 | ||
| 15 | #[derive(Default)] | 15 | #[derive(Default)] |
| 16 | pub struct DivState { | 16 | pub struct DivState { |
| @@ -66,9 +66,8 @@ pub struct Div< · 49 unmodified lines | |||
| 66 | I: ElementInteractivity<V> = StatelessInteractivity<V>, | 66 | I: ElementInteractivity<V> = StatelessInteractivity<V>, |
| 67 | F: ElementFocusability<V> = NonFocusable, | 67 | F: ElementFocusability<V> = NonFocusable, |
| 68 | > { | 68 | > { |
| 69 | identity: I, | 69 | interactivity: I, |
| 70 | focusability: F, | 70 | focusability: F, |
| 71 | interactivity: Interactivity<V>, | ||
| 72 | children: SmallVec<[AnyElement<V>; 2]>, | 71 | children: SmallVec<[AnyElement<V>; 2]>, |
| 73 | group: Option<SharedString>, | 72 | group: Option<SharedString>, |
| 74 | base_style: StyleRefinement, | 73 | base_style: StyleRefinement, |
| @@ -83,9 +82,8 @@ where · 8 unmodified lines | |||
| 83 | V: 'static + Send + Sync, | 82 | V: 'static + Send + Sync, |
| 84 | { | 83 | { |
| 85 | Div { | 84 | Div { |
| 86 | identity: StatelessInteractivity::default(), | 85 | interactivity: StatelessInteractivity::default(), |
| 87 | focusability: NonFocusable, | 86 | focusability: NonFocusable, |
| 88 | interactivity: Interactivity::default(), | ||
| 89 | children: SmallVec::new(), | 87 | children: SmallVec::new(), |
| 90 | group: None, | 88 | group: None, |
| 91 | base_style: StyleRefinement::default(), | 89 | base_style: StyleRefinement::default(), |
| @@ -108,9 +106,8 @@ where · 16 unmodified lines | |||
| 108 | { | 106 | { |
| 109 | pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> { | 107 | pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> { |
| 110 | Div { | 108 | Div { |
| 111 | identity: id.into().into(), | 109 | interactivity: id.into().into(), |
| 112 | focusability: self.focusability, | 110 | focusability: self.focusability, |
| 113 | interactivity: self.interactivity, | ||
| 114 | children: self.children, | 111 | children: self.children, |
| 115 | group: self.group, | 112 | group: self.group, |
| 116 | base_style: self.base_style, | 113 | base_style: self.base_style, |
| @@ -277,7 +274,7 @@ where · 160 unmodified lines | |||
| 277 | { | 274 | { |
| 278 | pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> { | 275 | pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> { |
| 279 | Div { | 276 | Div { |
| 280 | identity: self.identity, | 277 | interactivity: self.interactivity, |
| 281 | focusability: handle.clone().into(), | 278 | focusability: handle.clone().into(), |
| 282 | children: self.children, | 279 | children: self.children, |
| 283 | group: self.group, | 280 | group: self.group, |
| @@ -286,7 +283,6 @@ where · 2 unmodified lines | |||
| 286 | group_hover: self.group_hover, | 283 | group_hover: self.group_hover, |
| 287 | active_style: self.active_style, | 284 | active_style: self.active_style, |
| 288 | group_active: self.group_active, | 285 | group_active: self.group_active, |
| 289 | interactivity: self.interactivity, | ||
| 290 | } | 286 | } |
| 291 | } | 287 | } |
| 292 | } | 288 | } |
| @@ -327,7 +323,7 @@ where · 34 unmodified lines | |||
| 327 | type ElementState = DivState; | 323 | type ElementState = DivState; |
| 328 | 324 | ||
| 329 | fn id(&self) -> Option<ElementId> { | 325 | fn id(&self) -> Option<ElementId> { |
| 330 | self.identity | 326 | self.interactivity |
| 331 | .as_stateful() | 327 | .as_stateful() |
| 332 | .map(|identified| identified.id.clone()) | 328 | .map(|identified| identified.id.clone()) |
| 333 | } | 329 | } |
| @@ -338,39 +334,14 @@ where · 4 unmodified lines | |||
| 338 | element_state: Option<Self::ElementState>, | 334 | element_state: Option<Self::ElementState>, |
| 339 | cx: &mut ViewContext<Self::ViewState>, | 335 | cx: &mut ViewContext<Self::ViewState>, |
| 340 | ) -> Self::ElementState { | 336 | ) -> Self::ElementState { |
| 341 | self.with_element_id(cx, |this, global_id, cx| { | 337 | self.interactivity.initialize(cx, |cx| { |
| 342 | let element_state = element_state.unwrap_or_default(); | 338 | self.focusability.initialize(cx, |cx| { |
| 343 | 339 | for child in &mut self.children { | |
| 344 | let mut key_listeners = mem::take(&mut this.interactivity.key); | 340 | child.initialize(view_state, cx); |
| 345 | if let Some(global_id) = global_id { | 341 | } |
| 346 | key_listeners.push(( | ||
| 347 | TypeId::of::<KeyDownEvent>(), | ||
| 348 | Arc::new(move |_, key_down, context, phase, cx| { | ||
| 349 | if phase == DispatchPhase::Bubble { | ||
| 350 | let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap(); | ||
| 351 | if let KeyMatch::Some(action) = | ||
| 352 | cx.match_keystroke(&global_id, &key_down.keystroke, context) | ||
| 353 | { | ||
| 354 | return Some(action); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | None | ||
| 359 | }), | ||
| 360 | )); | ||
| 361 | } | ||
| 362 | |||
| 363 | cx.with_key_listeners(&key_listeners, |cx| { | ||
| 364 | this.focusability.initialize(cx, |cx| { | ||
| 365 | for child in &mut this.children { | ||
| 366 | child.initialize(view_state, cx); | ||
| 367 | } | ||
| 368 | }); | ||
| 369 | }); | 342 | }); |
| 370 | this.interactivity.key = key_listeners; | 343 | }); |
| 371 | 344 | element_state.unwrap_or_default() | |
| 372 | element_state | ||
| 373 | }) | ||
| 374 | } | 345 | } |
| 375 | 346 | ||
| 376 | fn layout( | 347 | fn layout( |
| @@ -490,14 +461,14 @@ where · 113 unmodified lines | |||
| 490 | } | 461 | } |
| 491 | } | 462 | } |
| 492 | 463 | ||
| 493 | impl<V, I, F> Interactive for Div<V, I, F> | 464 | impl<V, I, F> StatelesslyInteractive for Div<V, I, F> |
| 494 | where | 465 | where |
| 495 | I: ElementInteractivity<V>, | 466 | I: ElementInteractivity<V>, |
| 496 | F: ElementFocusability<V>, | 467 | F: ElementFocusability<V>, |
| 497 | V: 'static + Send + Sync, | 468 | V: 'static + Send + Sync, |
| 498 | { | 469 | { |
| 499 | fn interactivity(&mut self) -> &mut Interactivity<V> { | 470 | fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> { |
| 500 | &mut self.interactivity | 471 | self.interactivity.as_stateless_mut() |
| 501 | } | 472 | } |
| 502 | } | 473 | } |
| 503 | 474 | ||
| @@ -516,11 +487,14 @@ where · 12 unmodified lines | |||
| 516 | } | 487 | } |
| 517 | } | 488 | } |
| 518 | 489 | ||
| 519 | impl<V, F> Click for Div<V, StatefulInteractivity<V>, F> | 490 | impl<V, F> StatefullyInteractive for Div<V, StatefulInteractivity<V>, F> |
| 520 | where | 491 | where |
| 521 | F: ElementFocusability<V>, | 492 | F: ElementFocusability<V>, |
| 522 | V: 'static + Send + Sync, | 493 | V: 'static + Send + Sync, |
| 523 | { | 494 | { |
| 495 | fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> { | ||
| 496 | &mut self.interactivity | ||
| 497 | } | ||
| 524 | } | 498 | } |
| 525 | 499 | ||
| 526 | impl<V, F> Active for Div<V, StatefulInteractivity<V>, F> | 500 | impl<V, F> Active for Div<V, StatefulInteractivity<V>, F> |
| @@ -1,8 +1,8 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | div, Active, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element, | 2 | div, Active, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocusability, |
| 3 | ElementFocusability, ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover, | 3 | ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement, |
| 4 | Interactive, Interactivity, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, | 4 | LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive, |
| 5 | StatefulInteractivity, StatelessInteractivity, StyleRefinement, Styled, ViewContext, | 5 | StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext, |
| 6 | }; | 6 | }; |
| 7 | use futures::FutureExt; | 7 | use futures::FutureExt; |
| 8 | use util::ResultExt; | 8 | use util::ResultExt; |
| @@ -150,14 +150,14 @@ where · 141 unmodified lines | |||
| 150 | } | 150 | } |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | impl<V, I, F> Interactive for Img<V, I, F> | 153 | impl<V, I, F> StatelesslyInteractive for Img<V, I, F> |
| 154 | where | 154 | where |
| 155 | V: 'static + Send + Sync, | 155 | V: 'static + Send + Sync, |
| 156 | I: ElementInteractivity<V>, | 156 | I: ElementInteractivity<V>, |
| 157 | F: ElementFocusability<V>, | 157 | F: ElementFocusability<V>, |
| 158 | { | 158 | { |
| 159 | fn interactivity(&mut self) -> &mut Interactivity<V> { | 159 | fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> { |
| 160 | self.base.interactivity() | 160 | self.base.stateless_interactivity() |
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| @@ -172,11 +172,14 @@ where · 8 unmodified lines | |||
| 172 | } | 172 | } |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | impl<V, F> Click for Img<V, StatefulInteractivity<V>, F> | 175 | impl<V, F> StatefullyInteractive for Img<V, StatefulInteractivity<V>, F> |
| 176 | where | 176 | where |
| 177 | V: 'static + Send + Sync, | 177 | V: 'static + Send + Sync, |
| 178 | F: ElementFocusability<V>, | 178 | F: ElementFocusability<V>, |
| 179 | { | 179 | { |
| 180 | fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> { | ||
| 181 | self.base.stateful_interactivity() | ||
| 182 | } | ||
| 180 | } | 183 | } |
| 181 | 184 | ||
| 182 | impl<V, F> Active for Img<V, StatefulInteractivity<V>, F> | 185 | impl<V, F> Active for Img<V, StatefulInteractivity<V>, F> |
| @@ -1,8 +1,8 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | div, Active, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability, ElementId, | 2 | div, Active, AnyElement, Bounds, Div, DivState, Element, ElementFocusability, ElementId, |
| 3 | ElementInteractivity, Focus, FocusListeners, Focusable, Hover, Interactive, Interactivity, | 3 | ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement, LayoutId, |
| 4 | IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity, | 4 | NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive, |
| 5 | StatelessInteractivity, StyleRefinement, Styled, ViewContext, | 5 | StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext, |
| 6 | }; | 6 | }; |
| 7 | use util::ResultExt; | 7 | use util::ResultExt; |
| 8 | 8 | ||
| @@ -124,14 +124,14 @@ where · 115 unmodified lines | |||
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | impl<V, I, F> Interactive for Svg<V, I, F> | 127 | impl<V, I, F> StatelesslyInteractive for Svg<V, I, F> |
| 128 | where | 128 | where |
| 129 | V: 'static + Send + Sync, | 129 | V: 'static + Send + Sync, |
| 130 | I: ElementInteractivity<V>, | 130 | I: ElementInteractivity<V>, |
| 131 | F: ElementFocusability<V>, | 131 | F: ElementFocusability<V>, |
| 132 | { | 132 | { |
| 133 | fn interactivity(&mut self) -> &mut Interactivity<V> { | 133 | fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> { |
| 134 | self.base.interactivity() | 134 | self.base.stateless_interactivity() |
| 135 | } | 135 | } |
| 136 | } | 136 | } |
| 137 | 137 | ||
| @@ -146,11 +146,14 @@ where · 8 unmodified lines | |||
| 146 | } | 146 | } |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | impl<V, F> Click for Svg<V, StatefulInteractivity<V>, F> | 149 | impl<V, F> StatefullyInteractive for Svg<V, StatefulInteractivity<V>, F> |
| 150 | where | 150 | where |
| 151 | V: 'static + Send + Sync, | 151 | V: 'static + Send + Sync, |
| 152 | F: ElementFocusability<V>, | 152 | F: ElementFocusability<V>, |
| 153 | { | 153 | { |
| 154 | fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> { | ||
| 155 | self.base.stateful_interactivity() | ||
| 156 | } | ||
| 154 | } | 157 | } |
| 155 | 158 | ||
| 156 | impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F> | 159 | impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F> |
| @@ -1,19 +1,15 @@ | |||
| 1 | use parking_lot::Mutex; | ||
| 2 | use smallvec::SmallVec; | ||
| 3 | |||
| 4 | use crate::{ | 1 | use crate::{ |
| 5 | point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke, | 2 | point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke, |
| 6 | Modifiers, Pixels, Point, ViewContext, | 3 | Modifiers, Pixels, Point, StatefulInteractivity, StatelessInteractivity, ViewContext, |
| 7 | }; | 4 | }; |
| 8 | use std::{ | 5 | use std::{ |
| 9 | any::{Any, TypeId}, | 6 | any::{Any, TypeId}, |
| 10 | mem, | ||
| 11 | ops::Deref, | 7 | ops::Deref, |
| 12 | sync::Arc, | 8 | sync::Arc, |
| 13 | }; | 9 | }; |
| 14 | 10 | ||
| 15 | pub trait Interactive: Element { | 11 | pub trait StatelesslyInteractive: Element { |
| 16 | fn interactivity(&mut self) -> &mut Interactivity<Self::ViewState>; | 12 | fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<Self::ViewState>; |
| 17 | 13 | ||
| 18 | fn on_mouse_down( | 14 | fn on_mouse_down( |
| 19 | mut self, | 15 | mut self, |
| @@ -26,8 +22,8 @@ pub trait Interactive: Element { · 6 unmodified lines | |||
| 26 | where | 22 | where |
| 27 | Self: Sized, | 23 | Self: Sized, |
| 28 | { | 24 | { |
| 29 | self.interactivity() | 25 | self.stateless_interactivity() |
| 30 | .mouse_down | 26 | .mouse_down_listeners |
| 31 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 27 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 32 | if phase == DispatchPhase::Bubble | 28 | if phase == DispatchPhase::Bubble |
| 33 | && event.button == button | 29 | && event.button == button |
| @@ -50,8 +46,8 @@ pub trait Interactive: Element { · 16 unmodified lines | |||
| 50 | where | 46 | where |
| 51 | Self: Sized, | 47 | Self: Sized, |
| 52 | { | 48 | { |
| 53 | self.interactivity() | 49 | self.stateless_interactivity() |
| 54 | .mouse_up | 50 | .mouse_up_listeners |
| 55 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 51 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 56 | if phase == DispatchPhase::Bubble | 52 | if phase == DispatchPhase::Bubble |
| 57 | && event.button == button | 53 | && event.button == button |
| @@ -74,8 +70,8 @@ pub trait Interactive: Element { · 16 unmodified lines | |||
| 74 | where | 70 | where |
| 75 | Self: Sized, | 71 | Self: Sized, |
| 76 | { | 72 | { |
| 77 | self.interactivity() | 73 | self.stateless_interactivity() |
| 78 | .mouse_down | 74 | .mouse_down_listeners |
| 79 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 75 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 80 | if phase == DispatchPhase::Capture | 76 | if phase == DispatchPhase::Capture |
| 81 | && event.button == button | 77 | && event.button == button |
| @@ -98,8 +94,8 @@ pub trait Interactive: Element { · 16 unmodified lines | |||
| 98 | where | 94 | where |
| 99 | Self: Sized, | 95 | Self: Sized, |
| 100 | { | 96 | { |
| 101 | self.interactivity() | 97 | self.stateless_interactivity() |
| 102 | .mouse_up | 98 | .mouse_up_listeners |
| 103 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 99 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 104 | if phase == DispatchPhase::Capture | 100 | if phase == DispatchPhase::Capture |
| 105 | && event.button == button | 101 | && event.button == button |
| @@ -121,8 +117,8 @@ pub trait Interactive: Element { · 15 unmodified lines | |||
| 121 | where | 117 | where |
| 122 | Self: Sized, | 118 | Self: Sized, |
| 123 | { | 119 | { |
| 124 | self.interactivity() | 120 | self.stateless_interactivity() |
| 125 | .mouse_move | 121 | .mouse_move_listeners |
| 126 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 122 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 127 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | 123 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { |
| 128 | handler(view, event, cx); | 124 | handler(view, event, cx); |
| @@ -141,8 +137,8 @@ pub trait Interactive: Element { · 12 unmodified lines | |||
| 141 | where | 137 | where |
| 142 | Self: Sized, | 138 | Self: Sized, |
| 143 | { | 139 | { |
| 144 | self.interactivity() | 140 | self.stateless_interactivity() |
| 145 | .scroll_wheel | 141 | .scroll_wheel_listeners |
| 146 | .push(Arc::new(move |view, event, bounds, phase, cx| { | 142 | .push(Arc::new(move |view, event, bounds, phase, cx| { |
| 147 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | 143 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { |
| 148 | handler(view, event, cx); | 144 | handler(view, event, cx); |
| @@ -165,7 +161,7 @@ pub trait Interactive: Element { · 16 unmodified lines | |||
| 165 | where | 161 | where |
| 166 | Self: Sized, | 162 | Self: Sized, |
| 167 | { | 163 | { |
| 168 | self.interactivity().key.push(( | 164 | self.stateless_interactivity().key_listeners.push(( |
| 169 | TypeId::of::<KeyDownEvent>(), | 165 | TypeId::of::<KeyDownEvent>(), |
| 170 | Arc::new(move |view, event, _, phase, cx| { | 166 | Arc::new(move |view, event, _, phase, cx| { |
| 171 | let event = event.downcast_ref().unwrap(); | 167 | let event = event.downcast_ref().unwrap(); |
| @@ -186,7 +182,7 @@ pub trait Interactive: Element { · 14 unmodified lines | |||
| 186 | where | 182 | where |
| 187 | Self: Sized, | 183 | Self: Sized, |
| 188 | { | 184 | { |
| 189 | self.interactivity().key.push(( | 185 | self.stateless_interactivity().key_listeners.push(( |
| 190 | TypeId::of::<KeyUpEvent>(), | 186 | TypeId::of::<KeyUpEvent>(), |
| 191 | Arc::new(move |view, event, _, phase, cx| { | 187 | Arc::new(move |view, event, _, phase, cx| { |
| 192 | let event = event.downcast_ref().unwrap(); | 188 | let event = event.downcast_ref().unwrap(); |
| @@ -207,7 +203,7 @@ pub trait Interactive: Element { · 14 unmodified lines | |||
| 207 | where | 203 | where |
| 208 | Self: Sized, | 204 | Self: Sized, |
| 209 | { | 205 | { |
| 210 | self.interactivity().key.push(( | 206 | self.stateless_interactivity().key_listeners.push(( |
| 211 | TypeId::of::<A>(), | 207 | TypeId::of::<A>(), |
| 212 | Arc::new(move |view, event, _, phase, cx| { | 208 | Arc::new(move |view, event, _, phase, cx| { |
| 213 | let event = event.downcast_ref().unwrap(); | 209 | let event = event.downcast_ref().unwrap(); |
| @@ -219,7 +215,9 @@ pub trait Interactive: Element { · 5 unmodified lines | |||
| 219 | } | 215 | } |
| 220 | } | 216 | } |
| 221 | 217 | ||
| 222 | pub trait Click: Interactive { | 218 | pub trait StatefullyInteractive: StatelesslyInteractive { |
| 219 | fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState>; | ||
| 220 | |||
| 223 | fn on_click( | 221 | fn on_click( |
| 224 | mut self, | 222 | mut self, |
| 225 | handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>) | 223 | handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>) |
| @@ -230,8 +228,8 @@ pub trait Click: Interactive { · 4 unmodified lines | |||
| 230 | where | 228 | where |
| 231 | Self: Sized, | 229 | Self: Sized, |
| 232 | { | 230 | { |
| 233 | self.interactivity() | 231 | self.stateful_interactivity() |
| 234 | .mouse_click | 232 | .mouse_click_listeners |
| 235 | .push(Arc::new(move |view, event, cx| handler(view, event, cx))); | 233 | .push(Arc::new(move |view, event, cx| handler(view, event, cx))); |
| 236 | self | 234 | self |
| 237 | } | 235 | } |
| @@ -495,86 +493,3 @@ pub type KeyListener<V> = Arc< · 257 unmodified lines | |||
| 495 | + Sync | 493 | + Sync |
| 496 | + 'static, | 494 | + 'static, |
| 497 | >; | 495 | >; |
| 498 | |||
| 499 | pub struct Interactivity<V> { | ||
| 500 | pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>, | ||
| 501 | pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>, | ||
| 502 | pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>, | ||
| 503 | pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>, | ||
| 504 | pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>, | ||
| 505 | pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>, | ||
| 506 | } | ||
| 507 | |||
| 508 | impl<V> Default for Interactivity<V> { | ||
| 509 | fn default() -> Self { | ||
| 510 | Self { | ||
| 511 | mouse_down: SmallVec::new(), | ||
| 512 | mouse_up: SmallVec::new(), | ||
| 513 | mouse_click: SmallVec::new(), | ||
| 514 | mouse_move: SmallVec::new(), | ||
| 515 | scroll_wheel: SmallVec::new(), | ||
| 516 | key: SmallVec::new(), | ||
| 517 | } | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | impl<V> Interactivity<V> | ||
| 522 | where | ||
| 523 | V: 'static + Send + Sync, | ||
| 524 | { | ||
| 525 | pub fn paint( | ||
| 526 | &mut self, | ||
| 527 | bounds: Bounds<Pixels>, | ||
| 528 | pending_click: Arc<Mutex<Option<MouseDownEvent>>>, | ||
| 529 | cx: &mut ViewContext<V>, | ||
| 530 | ) { | ||
| 531 | let click_listeners = mem::take(&mut self.mouse_click); | ||
| 532 | |||
| 533 | let mouse_down = pending_click.lock().clone(); | ||
| 534 | if let Some(mouse_down) = mouse_down { | ||
| 535 | cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| { | ||
| 536 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | ||
| 537 | let mouse_click = MouseClickEvent { | ||
| 538 | down: mouse_down.clone(), | ||
| 539 | up: event.clone(), | ||
| 540 | }; | ||
| 541 | for listener in &click_listeners { | ||
| 542 | listener(state, &mouse_click, cx); | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | *pending_click.lock() = None; | ||
| 547 | }); | ||
| 548 | } else { | ||
| 549 | cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| { | ||
| 550 | if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { | ||
| 551 | *pending_click.lock() = Some(event.clone()); | ||
| 552 | } | ||
| 553 | }); | ||
| 554 | } | ||
| 555 | |||
| 556 | for listener in mem::take(&mut self.mouse_down) { | ||
| 557 | cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| { | ||
| 558 | listener(state, event, &bounds, phase, cx); | ||
| 559 | }) | ||
| 560 | } | ||
| 561 | |||
| 562 | for listener in mem::take(&mut self.mouse_up) { | ||
| 563 | cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| { | ||
| 564 | listener(state, event, &bounds, phase, cx); | ||
| 565 | }) | ||
| 566 | } | ||
| 567 | |||
| 568 | for listener in mem::take(&mut self.mouse_move) { | ||
| 569 | cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| { | ||
| 570 | listener(state, event, &bounds, phase, cx); | ||
| 571 | }) | ||
| 572 | } | ||
| 573 | |||
| 574 | for listener in mem::take(&mut self.scroll_wheel) { | ||
| 575 | cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| { | ||
| 576 | listener(state, event, &bounds, phase, cx); | ||
| 577 | }) | ||
| 578 | } | ||
| 579 | } | ||
| 580 | } | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | use std::marker::PhantomData; | 1 | use std::marker::PhantomData; |
| 2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
| 3 | 3 | ||
| 4 | use gpui3::{Interactive, MouseButton}; | 4 | use gpui3::{MouseButton, StatelesslyInteractive}; |
| 5 | 5 | ||
| 6 | use crate::{h_stack, prelude::*}; | 6 | use crate::{h_stack, prelude::*}; |
| 7 | use crate::{theme, ClickHandler, Icon, IconColor, IconElement}; | 7 | use crate::{theme, ClickHandler, Icon, IconColor, IconElement}; |
| @@ -1,7 +1,7 @@ | |||
| 1 | use std::marker::PhantomData; | 1 | use std::marker::PhantomData; |
| 2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
| 3 | 3 | ||
| 4 | use gpui3::{DefiniteLength, Hsla, Interactive, MouseButton, WindowContext}; | 4 | use gpui3::{DefiniteLength, Hsla, MouseButton, StatelesslyInteractive, WindowContext}; |
| 5 | 5 | ||
| 6 | use crate::settings::user_settings; | 6 | use crate::settings::user_settings; |
| 7 | use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor}; | 7 | use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor}; |
| @@ -1,6 +1,6 @@ | |||
| 1 | pub use gpui3::{ | 1 | pub use gpui3::{ |
| 2 | div, Active, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString, | 2 | div, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString, |
| 3 | Styled, ViewContext, WindowContext, | 3 | StatefullyInteractivee, Styled, ViewContext, WindowContext, |
| 4 | }; | 4 | }; |
| 5 | 5 | ||
| 6 | use crate::settings::user_settings; | 6 | use crate::settings::user_settings; |