Checkpoint
This commit is contained in:
parent
0fbf84e6bc
commit
dd7e1c505c
8 changed files with 207 additions and 191 deletions
|
@ -1,11 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, LayoutId,
|
BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners, KeyDownEvent,
|
||||||
MouseDownEvent, Pixels, Point, Style, StyleRefinement, ViewContext, WindowContext,
|
KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener, MouseDownEvent,
|
||||||
|
MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent, MouseUpListener, Pixels,
|
||||||
|
Point, ScrollWheelEvent, ScrollWheelListener, Style, StyleRefinement, ViewContext,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
use parking_lot::Mutex;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
pub(crate) use smallvec::SmallVec;
|
pub(crate) use smallvec::SmallVec;
|
||||||
use std::{marker::PhantomData, mem};
|
use std::{any::TypeId, mem, sync::Arc};
|
||||||
|
|
||||||
pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
||||||
type ViewState: 'static + Send + Sync;
|
type ViewState: 'static + Send + Sync;
|
||||||
|
@ -40,19 +44,98 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
||||||
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
|
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
|
||||||
|
|
||||||
pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
|
pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
|
||||||
|
fn as_stateless(&self) -> &StatelessInteractivity<V>;
|
||||||
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
|
||||||
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||||
|
cx: &mut ViewContext<V>,
|
||||||
|
) {
|
||||||
|
let stateless = self.as_stateless();
|
||||||
|
for listener in stateless.mouse_down_listeners.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||||
|
listener(state, event, &bounds, phase, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for listener in stateless.mouse_up_listeners.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||||
|
listener(state, event, &bounds, phase, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for listener in stateless.mouse_move_listeners.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||||
|
listener(state, event, &bounds, phase, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for listener in stateless.scroll_wheel_listeners.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||||
|
listener(state, event, &bounds, phase, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(stateful) = self.as_stateful() {
|
||||||
|
let click_listeners = stateful.mouse_click_listeners.clone();
|
||||||
|
|
||||||
|
let mouse_down = pending_click.lock().clone();
|
||||||
|
if let Some(mouse_down) = mouse_down {
|
||||||
|
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
|
let mouse_click = MouseClickEvent {
|
||||||
|
down: mouse_down.clone(),
|
||||||
|
up: event.clone(),
|
||||||
|
};
|
||||||
|
for listener in &click_listeners {
|
||||||
|
listener(state, &mouse_click, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pending_click.lock() = None;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
||||||
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
|
*pending_click.lock() = Some(event.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn initialize<R>(
|
fn initialize<R>(
|
||||||
&self,
|
&mut self,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
f: impl FnOnce(Option<GlobalElementId>, &mut ViewContext<V>) -> R,
|
f: impl FnOnce(&mut ViewContext<V>) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
if let Some(identified) = self.as_stateful() {
|
if let Some(stateful) = self.as_stateful_mut() {
|
||||||
cx.with_element_id(identified.id.clone(), |global_id, cx| {
|
cx.with_element_id(stateful.id.clone(), |global_id, cx| {
|
||||||
f(Some(global_id), cx)
|
stateful.key_listeners.push((
|
||||||
|
TypeId::of::<KeyDownEvent>(),
|
||||||
|
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, context)
|
||||||
|
{
|
||||||
|
return Some(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
let result = stateful.stateless.initialize(cx, f);
|
||||||
|
stateful.key_listeners.pop();
|
||||||
|
result
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
f(None, cx)
|
cx.with_key_listeners(&self.as_stateless().key_listeners, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +145,8 @@ pub struct StatefulInteractivity<V: 'static + Send + Sync> {
|
||||||
pub id: ElementId,
|
pub id: ElementId,
|
||||||
#[deref]
|
#[deref]
|
||||||
#[deref_mut]
|
#[deref_mut]
|
||||||
common: StatelessInteractivity<V>,
|
stateless: StatelessInteractivity<V>,
|
||||||
|
pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
|
impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
|
||||||
|
@ -72,6 +156,18 @@ where
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||||
Some(self)
|
Some(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||||
|
&self.stateless
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
|
&mut self.stateless
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> From<ElementId> for StatefulInteractivity<V>
|
impl<V> From<ElementId> for StatefulInteractivity<V>
|
||||||
|
@ -81,16 +177,29 @@ where
|
||||||
fn from(id: ElementId) -> Self {
|
fn from(id: ElementId) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
common: StatelessInteractivity::default(),
|
stateless: StatelessInteractivity::default(),
|
||||||
|
mouse_click_listeners: SmallVec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StatelessInteractivity<V>(PhantomData<V>);
|
pub struct StatelessInteractivity<V> {
|
||||||
|
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||||
|
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||||
|
pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||||
|
pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||||
|
pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<V> Default for StatelessInteractivity<V> {
|
impl<V> Default for StatelessInteractivity<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(PhantomData)
|
Self {
|
||||||
|
mouse_down_listeners: SmallVec::new(),
|
||||||
|
mouse_up_listeners: SmallVec::new(),
|
||||||
|
mouse_move_listeners: SmallVec::new(),
|
||||||
|
scroll_wheel_listeners: SmallVec::new(),
|
||||||
|
key_listeners: SmallVec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +210,18 @@ where
|
||||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
|
pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
Active, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
|
Active, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
|
||||||
ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners,
|
ElementFocusability, ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners,
|
||||||
Focusable, GlobalElementId, Hover, Interactive, Interactivity, IntoAnyElement, KeyDownEvent,
|
Focusable, GlobalElementId, Hover, IntoAnyElement, LayoutId, MouseDownEvent, MouseMoveEvent,
|
||||||
KeyMatch, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow,
|
MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString,
|
||||||
ParentElement, Pixels, Point, SharedString, StatefulInteractivity, StatelessInteractivity,
|
StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive,
|
||||||
Style, StyleRefinement, Styled, ViewContext,
|
Style, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use refineable::Refineable;
|
use refineable::Refineable;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{any::TypeId, mem, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DivState {
|
pub struct DivState {
|
||||||
|
@ -66,9 +66,8 @@ pub struct Div<
|
||||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||||
F: ElementFocusability<V> = NonFocusable,
|
F: ElementFocusability<V> = NonFocusable,
|
||||||
> {
|
> {
|
||||||
identity: I,
|
interactivity: I,
|
||||||
focusability: F,
|
focusability: F,
|
||||||
interactivity: Interactivity<V>,
|
|
||||||
children: SmallVec<[AnyElement<V>; 2]>,
|
children: SmallVec<[AnyElement<V>; 2]>,
|
||||||
group: Option<SharedString>,
|
group: Option<SharedString>,
|
||||||
base_style: StyleRefinement,
|
base_style: StyleRefinement,
|
||||||
|
@ -83,9 +82,8 @@ where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
Div {
|
Div {
|
||||||
identity: StatelessInteractivity::default(),
|
interactivity: StatelessInteractivity::default(),
|
||||||
focusability: NonFocusable,
|
focusability: NonFocusable,
|
||||||
interactivity: Interactivity::default(),
|
|
||||||
children: SmallVec::new(),
|
children: SmallVec::new(),
|
||||||
group: None,
|
group: None,
|
||||||
base_style: StyleRefinement::default(),
|
base_style: StyleRefinement::default(),
|
||||||
|
@ -108,9 +106,8 @@ where
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
|
||||||
Div {
|
Div {
|
||||||
identity: id.into().into(),
|
interactivity: id.into().into(),
|
||||||
focusability: self.focusability,
|
focusability: self.focusability,
|
||||||
interactivity: self.interactivity,
|
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
base_style: self.base_style,
|
base_style: self.base_style,
|
||||||
|
@ -277,7 +274,7 @@ where
|
||||||
{
|
{
|
||||||
pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {
|
pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {
|
||||||
Div {
|
Div {
|
||||||
identity: self.identity,
|
interactivity: self.interactivity,
|
||||||
focusability: handle.clone().into(),
|
focusability: handle.clone().into(),
|
||||||
children: self.children,
|
children: self.children,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
|
@ -286,7 +283,6 @@ where
|
||||||
group_hover: self.group_hover,
|
group_hover: self.group_hover,
|
||||||
active_style: self.active_style,
|
active_style: self.active_style,
|
||||||
group_active: self.group_active,
|
group_active: self.group_active,
|
||||||
interactivity: self.interactivity,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +323,7 @@ where
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
|
|
||||||
fn id(&self) -> Option<ElementId> {
|
fn id(&self) -> Option<ElementId> {
|
||||||
self.identity
|
self.interactivity
|
||||||
.as_stateful()
|
.as_stateful()
|
||||||
.map(|identified| identified.id.clone())
|
.map(|identified| identified.id.clone())
|
||||||
}
|
}
|
||||||
|
@ -338,39 +334,14 @@ where
|
||||||
element_state: Option<Self::ElementState>,
|
element_state: Option<Self::ElementState>,
|
||||||
cx: &mut ViewContext<Self::ViewState>,
|
cx: &mut ViewContext<Self::ViewState>,
|
||||||
) -> Self::ElementState {
|
) -> Self::ElementState {
|
||||||
self.with_element_id(cx, |this, global_id, cx| {
|
self.interactivity.initialize(cx, |cx| {
|
||||||
let element_state = element_state.unwrap_or_default();
|
self.focusability.initialize(cx, |cx| {
|
||||||
|
for child in &mut self.children {
|
||||||
let mut key_listeners = mem::take(&mut this.interactivity.key);
|
child.initialize(view_state, cx);
|
||||||
if let Some(global_id) = global_id {
|
}
|
||||||
key_listeners.push((
|
|
||||||
TypeId::of::<KeyDownEvent>(),
|
|
||||||
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, context)
|
|
||||||
{
|
|
||||||
return Some(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
cx.with_key_listeners(&key_listeners, |cx| {
|
|
||||||
this.focusability.initialize(cx, |cx| {
|
|
||||||
for child in &mut this.children {
|
|
||||||
child.initialize(view_state, cx);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
this.interactivity.key = key_listeners;
|
});
|
||||||
|
element_state.unwrap_or_default()
|
||||||
element_state
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
|
@ -490,14 +461,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I, F> Interactive for Div<V, I, F>
|
impl<V, I, F> StatelesslyInteractive for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementInteractivity<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn interactivity(&mut self) -> &mut Interactivity<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
&mut self.interactivity
|
self.interactivity.as_stateless_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,11 +487,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Click for Div<V, StatefulInteractivity<V>, F>
|
impl<V, F> StatefullyInteractive for Div<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
|
||||||
|
&mut self.interactivity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Div<V, StatefulInteractivity<V>, F>
|
impl<V, F> Active for Div<V, StatefulInteractivity<V>, F>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
div, Active, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
|
div, Active, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocusability,
|
||||||
ElementFocusability, ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover,
|
ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement,
|
||||||
Interactive, Interactivity, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString,
|
LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive,
|
||||||
StatefulInteractivity, StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
@ -150,14 +150,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I, F> Interactive for Img<V, I, F>
|
impl<V, I, F> StatelesslyInteractive for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementInteractivity<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn interactivity(&mut self) -> &mut Interactivity<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self.base.interactivity()
|
self.base.stateless_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +172,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Click for Img<V, StatefulInteractivity<V>, F>
|
impl<V, F> StatefullyInteractive for Img<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
|
||||||
|
self.base.stateful_interactivity()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>
|
impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
div, Active, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability, ElementId,
|
div, Active, AnyElement, Bounds, Div, DivState, Element, ElementFocusability, ElementId,
|
||||||
ElementInteractivity, Focus, FocusListeners, Focusable, Hover, Interactive, Interactivity,
|
ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement, LayoutId,
|
||||||
IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity,
|
NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive,
|
||||||
StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
|
@ -124,14 +124,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I, F> Interactive for Svg<V, I, F>
|
impl<V, I, F> StatelesslyInteractive for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementInteractivity<V>,
|
I: ElementInteractivity<V>,
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn interactivity(&mut self) -> &mut Interactivity<V> {
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||||
self.base.interactivity()
|
self.base.stateless_interactivity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,11 +146,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Click for Svg<V, StatefulInteractivity<V>, F>
|
impl<V, F> StatefullyInteractive for Svg<V, StatefulInteractivity<V>, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability<V>,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
|
||||||
|
self.base.stateful_interactivity()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F>
|
impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F>
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
use parking_lot::Mutex;
|
|
||||||
use smallvec::SmallVec;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
|
point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
|
||||||
Modifiers, Pixels, Point, ViewContext,
|
Modifiers, Pixels, Point, StatefulInteractivity, StatelessInteractivity, ViewContext,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
mem,
|
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interactive: Element {
|
pub trait StatelesslyInteractive: Element {
|
||||||
fn interactivity(&mut self) -> &mut Interactivity<Self::ViewState>;
|
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<Self::ViewState>;
|
||||||
|
|
||||||
fn on_mouse_down(
|
fn on_mouse_down(
|
||||||
mut self,
|
mut self,
|
||||||
|
@ -26,8 +22,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.mouse_down
|
.mouse_down_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble
|
if phase == DispatchPhase::Bubble
|
||||||
&& event.button == button
|
&& event.button == button
|
||||||
|
@ -50,8 +46,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.mouse_up
|
.mouse_up_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble
|
if phase == DispatchPhase::Bubble
|
||||||
&& event.button == button
|
&& event.button == button
|
||||||
|
@ -74,8 +70,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.mouse_down
|
.mouse_down_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture
|
if phase == DispatchPhase::Capture
|
||||||
&& event.button == button
|
&& event.button == button
|
||||||
|
@ -98,8 +94,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.mouse_up
|
.mouse_up_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture
|
if phase == DispatchPhase::Capture
|
||||||
&& event.button == button
|
&& event.button == button
|
||||||
|
@ -121,8 +117,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.mouse_move
|
.mouse_move_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
handler(view, event, cx);
|
handler(view, event, cx);
|
||||||
|
@ -141,8 +137,8 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateless_interactivity()
|
||||||
.scroll_wheel
|
.scroll_wheel_listeners
|
||||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||||
handler(view, event, cx);
|
handler(view, event, cx);
|
||||||
|
@ -165,7 +161,7 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity().key.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<KeyDownEvent>(),
|
TypeId::of::<KeyDownEvent>(),
|
||||||
Arc::new(move |view, event, _, phase, cx| {
|
Arc::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
|
@ -186,7 +182,7 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity().key.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<KeyUpEvent>(),
|
TypeId::of::<KeyUpEvent>(),
|
||||||
Arc::new(move |view, event, _, phase, cx| {
|
Arc::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
|
@ -207,7 +203,7 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity().key.push((
|
self.stateless_interactivity().key_listeners.push((
|
||||||
TypeId::of::<A>(),
|
TypeId::of::<A>(),
|
||||||
Arc::new(move |view, event, _, phase, cx| {
|
Arc::new(move |view, event, _, phase, cx| {
|
||||||
let event = event.downcast_ref().unwrap();
|
let event = event.downcast_ref().unwrap();
|
||||||
|
@ -219,7 +215,9 @@ pub trait Interactive: Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Click: Interactive {
|
pub trait StatefullyInteractive: StatelesslyInteractive {
|
||||||
|
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState>;
|
||||||
|
|
||||||
fn on_click(
|
fn on_click(
|
||||||
mut self,
|
mut self,
|
||||||
handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
|
handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
|
||||||
|
@ -230,8 +228,8 @@ pub trait Click: Interactive {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interactivity()
|
self.stateful_interactivity()
|
||||||
.mouse_click
|
.mouse_click_listeners
|
||||||
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -495,86 +493,3 @@ pub type KeyListener<V> = Arc<
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
pub struct Interactivity<V> {
|
|
||||||
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 Interactivity<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(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V> Interactivity<V>
|
|
||||||
where
|
|
||||||
V: 'static + Send + Sync,
|
|
||||||
{
|
|
||||||
pub fn paint(
|
|
||||||
&mut self,
|
|
||||||
bounds: Bounds<Pixels>,
|
|
||||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
|
||||||
cx: &mut ViewContext<V>,
|
|
||||||
) {
|
|
||||||
let click_listeners = mem::take(&mut self.mouse_click);
|
|
||||||
|
|
||||||
let mouse_down = pending_click.lock().clone();
|
|
||||||
if let Some(mouse_down) = mouse_down {
|
|
||||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
|
||||||
let mouse_click = MouseClickEvent {
|
|
||||||
down: mouse_down.clone(),
|
|
||||||
up: event.clone(),
|
|
||||||
};
|
|
||||||
for listener in &click_listeners {
|
|
||||||
listener(state, &mouse_click, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*pending_click.lock() = None;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
|
||||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
|
||||||
*pending_click.lock() = Some(event.clone());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for listener in mem::take(&mut self.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.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.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.scroll_wheel) {
|
|
||||||
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
|
||||||
listener(state, event, &bounds, phase, cx);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use gpui3::{Interactive, MouseButton};
|
use gpui3::{MouseButton, StatelesslyInteractive};
|
||||||
|
|
||||||
use crate::{h_stack, prelude::*};
|
use crate::{h_stack, prelude::*};
|
||||||
use crate::{theme, ClickHandler, Icon, IconColor, IconElement};
|
use crate::{theme, ClickHandler, Icon, IconColor, IconElement};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use gpui3::{DefiniteLength, Hsla, Interactive, MouseButton, WindowContext};
|
use gpui3::{DefiniteLength, Hsla, MouseButton, StatelesslyInteractive, WindowContext};
|
||||||
|
|
||||||
use crate::settings::user_settings;
|
use crate::settings::user_settings;
|
||||||
use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor};
|
use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub use gpui3::{
|
pub use gpui3::{
|
||||||
div, Active, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString,
|
div, Click, Element, Hover, IntoAnyElement, ParentElement, ScrollState, SharedString,
|
||||||
Styled, ViewContext, WindowContext,
|
StatefullyInteractivee, Styled, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::settings::user_settings;
|
use crate::settings::user_settings;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue