Merge branch 'gpui2' of github.com:zed-industries/zed into gpui2
This commit is contained in:
commit
2bbce2f0fd
12 changed files with 661 additions and 542 deletions
|
@ -10,14 +10,14 @@ pub trait Action: Any + Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct ActionContext {
|
pub struct DispatchContext {
|
||||||
set: HashSet<SharedString>,
|
set: HashSet<SharedString>,
|
||||||
map: HashMap<SharedString, SharedString>,
|
map: HashMap<SharedString, SharedString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionContext {
|
impl DispatchContext {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ActionContext {
|
DispatchContext {
|
||||||
set: HashSet::default(),
|
set: HashSet::default(),
|
||||||
map: HashMap::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 {
|
let Some(context) = contexts.first() else {
|
||||||
return false;
|
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 derive_more::{Deref, DerefMut};
|
||||||
|
use refineable::Refineable;
|
||||||
pub(crate) use smallvec::SmallVec;
|
pub(crate) use smallvec::SmallVec;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -55,34 +59,94 @@ impl ElementIdentity for Anonymous {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ElementFocusability: 'static + Send + Sync {
|
pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
|
||||||
fn focus_handle(&self) -> Option<&FocusHandle>;
|
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 refine_style(&self, style: &mut Style, cx: &WindowContext) {
|
||||||
fn as_ref(&self) -> &FocusHandle {
|
if let Some(focusable) = self.as_focusable() {
|
||||||
&self.0
|
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 {
|
pub struct Focusable<V: 'static + Send + Sync> {
|
||||||
fn focus_handle(&self) -> Option<&FocusHandle> {
|
pub focus_handle: FocusHandle,
|
||||||
Some(&self.0)
|
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 {
|
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;
|
pub struct NonFocusable;
|
||||||
|
|
||||||
impl ElementFocusability for NonFocusable {
|
impl<V> ElementFocusability<V> for NonFocusable
|
||||||
fn focus_handle(&self) -> Option<&FocusHandle> {
|
where
|
||||||
|
V: 'static + Send + Sync,
|
||||||
|
{
|
||||||
|
fn as_focusable(&self) -> Option<&Focusable<V>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
|
Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
|
||||||
ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable,
|
ElementFocusability, ElementId, ElementIdentity, Focus, FocusHandle, FocusListeners, Focusable,
|
||||||
GlobalElementId, Hover, Identified, Interactive, IntoAnyElement, KeyDownEvent, KeyMatch,
|
GlobalElementId, Hover, Identified, Interactive, InteractiveState, IntoAnyElement,
|
||||||
LayoutId, MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable,
|
KeyDownEvent, KeyMatch, LayoutId, MouseClickEvent, MouseDownEvent, MouseMoveEvent,
|
||||||
Overflow, ParentElement, Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement,
|
MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, ScrollWheelEvent,
|
||||||
Styled, ViewContext,
|
SharedString, Style, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use parking_lot::Mutex;
|
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>
|
pub fn div<V>() -> Div<V, Anonymous, NonFocusable>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
|
@ -75,33 +92,10 @@ where
|
||||||
group_hover: None,
|
group_hover: None,
|
||||||
active_style: StyleRefinement::default(),
|
active_style: StyleRefinement::default(),
|
||||||
group_active: None,
|
group_active: None,
|
||||||
focus_style: StyleRefinement::default(),
|
interactive_state: InteractiveState::default(),
|
||||||
focus_in_style: StyleRefinement::default(),
|
|
||||||
in_focus_style: StyleRefinement::default(),
|
|
||||||
listeners: EventListeners::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 {
|
struct GroupStyle {
|
||||||
group: SharedString,
|
group: SharedString,
|
||||||
style: StyleRefinement,
|
style: StyleRefinement,
|
||||||
|
@ -109,7 +103,7 @@ struct GroupStyle {
|
||||||
|
|
||||||
impl<V, F> Div<V, Anonymous, F>
|
impl<V, F> Div<V, Anonymous, F>
|
||||||
where
|
where
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
|
||||||
|
@ -123,10 +117,7 @@ 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,
|
||||||
focus_style: self.focus_style,
|
interactive_state: self.interactive_state,
|
||||||
focus_in_style: self.focus_in_style,
|
|
||||||
in_focus_style: self.in_focus_style,
|
|
||||||
listeners: self.listeners,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +125,7 @@ where
|
||||||
impl<V, I, F> Div<V, I, F>
|
impl<V, I, F> Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||||
|
@ -206,19 +197,7 @@ where
|
||||||
let mut computed_style = Style::default();
|
let mut computed_style = Style::default();
|
||||||
computed_style.refine(&self.base_style);
|
computed_style.refine(&self.base_style);
|
||||||
|
|
||||||
if let Some(handle) = self.focusability.focus_handle() {
|
self.focusability.refine_style(&mut computed_style, cx);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mouse_position = cx.mouse_position();
|
let mouse_position = cx.mouse_position();
|
||||||
|
|
||||||
|
@ -296,7 +275,7 @@ where
|
||||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||||
cx: &mut ViewContext<V>,
|
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();
|
let mouse_down = pending_click.lock().clone();
|
||||||
if let Some(mouse_down) = mouse_down {
|
if let Some(mouse_down) = mouse_down {
|
||||||
|
@ -321,37 +300,25 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(focus_handle) = self.focusability.focus_handle() {
|
for listener in mem::take(&mut self.interactive_state.mouse_down) {
|
||||||
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) {
|
|
||||||
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||||
listener(state, event, &bounds, 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| {
|
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||||
listener(state, event, &bounds, 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| {
|
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||||
listener(state, event, &bounds, 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| {
|
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||||
listener(state, event, &bounds, phase, cx);
|
listener(state, event, &bounds, phase, cx);
|
||||||
})
|
})
|
||||||
|
@ -364,7 +331,7 @@ where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
V: 'static + Send + Sync,
|
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 {
|
Div {
|
||||||
identity: self.identity,
|
identity: self.identity,
|
||||||
focusability: handle.clone().into(),
|
focusability: handle.clone().into(),
|
||||||
|
@ -375,40 +342,41 @@ 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,
|
||||||
focus_style: self.focus_style,
|
interactive_state: self.interactive_state,
|
||||||
focus_in_style: self.focus_in_style,
|
|
||||||
in_focus_style: self.in_focus_style,
|
|
||||||
listeners: self.listeners,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I> Focus for Div<V, I, Focusable>
|
impl<V, I> Focus for Div<V, I, Focusable<V>>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
|
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||||
|
&mut self.focusability.focus_listeners
|
||||||
|
}
|
||||||
|
|
||||||
fn handle(&self) -> &FocusHandle {
|
fn handle(&self) -> &FocusHandle {
|
||||||
self.focusability.as_ref()
|
&self.focusability.focus_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
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) {
|
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) {
|
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>
|
impl<V, I, F> Element for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
type ViewState = V;
|
type ViewState = V;
|
||||||
|
@ -426,20 +394,16 @@ where
|
||||||
) -> Self::ElementState {
|
) -> Self::ElementState {
|
||||||
self.with_element_id(cx, |this, global_id, cx| {
|
self.with_element_id(cx, |this, global_id, cx| {
|
||||||
let element_state = element_state.unwrap_or_default();
|
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 {
|
if let Some(global_id) = global_id {
|
||||||
key_listeners.push((
|
key_listeners.push((
|
||||||
TypeId::of::<KeyDownEvent>(),
|
TypeId::of::<KeyDownEvent>(),
|
||||||
Arc::new(move |_, key_down, phase, cx| {
|
Arc::new(move |_, key_down, context, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble {
|
if phase == DispatchPhase::Bubble {
|
||||||
let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
|
let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
|
||||||
if let KeyMatch::Some(action) =
|
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);
|
return Some(action);
|
||||||
}
|
}
|
||||||
|
@ -451,19 +415,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.with_key_listeners(&key_listeners, |cx| {
|
cx.with_key_listeners(&key_listeners, |cx| {
|
||||||
if let Some(focus_handle) = this.focusability.focus_handle().cloned() {
|
this.focusability.initialize(cx, |cx| {
|
||||||
cx.with_focus(focus_handle, |cx| {
|
|
||||||
for child in &mut this.children {
|
|
||||||
child.initialize(view_state, cx);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
for child in &mut this.children {
|
for child in &mut this.children {
|
||||||
child.initialize(view_state, cx);
|
child.initialize(view_state, cx);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
this.listeners.key = key_listeners;
|
this.interactive_state.key = key_listeners;
|
||||||
|
|
||||||
element_state
|
element_state
|
||||||
})
|
})
|
||||||
|
@ -526,6 +484,7 @@ where
|
||||||
element_state.active_state.clone(),
|
element_state.active_state.clone(),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
this.focusability.paint(bounds, cx);
|
||||||
this.paint_event_listeners(bounds, element_state.pending_click.clone(), 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>
|
impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn into_any(self) -> AnyElement<V> {
|
fn into_any(self) -> AnyElement<V> {
|
||||||
|
@ -565,7 +524,7 @@ where
|
||||||
impl<V, I, F> ParentElement for Div<V, I, F>
|
impl<V, I, F> ParentElement for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
|
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>
|
impl<V, I, F> Styled for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
|
@ -587,18 +546,18 @@ where
|
||||||
impl<V, I, F> Interactive for Div<V, I, F>
|
impl<V, I, F> Interactive for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
fn interactive_state(&mut self) -> &mut InteractiveState<V> {
|
||||||
&mut self.listeners
|
&mut self.interactive_state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, I, F> Hover for Div<V, I, F>
|
impl<V, I, F> Hover for Div<V, I, F>
|
||||||
where
|
where
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
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>
|
impl<V, F> Click for Div<V, Identified, F>
|
||||||
where
|
where
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Div<V, Identified, F>
|
impl<V, F> Active for Div<V, Identified, F>
|
||||||
where
|
where
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
{
|
{
|
||||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
|
div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
|
||||||
ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover,
|
ElementFocusability, ElementId, ElementIdentity, Focus, FocusListeners, Focusable, Hover,
|
||||||
Identified, Interactive, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString,
|
Identified, Interactive, InteractiveState, IntoAnyElement, LayoutId, NonFocusable, Pixels,
|
||||||
StyleRefinement, Styled, ViewContext,
|
SharedString, StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
@ -10,7 +10,7 @@ use util::ResultExt;
|
||||||
pub struct Img<
|
pub struct Img<
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity = Anonymous,
|
I: ElementIdentity = Anonymous,
|
||||||
F: ElementFocusability = NonFocusable,
|
F: ElementFocusability<V> = NonFocusable,
|
||||||
> {
|
> {
|
||||||
base: Div<V, I, F>,
|
base: Div<V, I, F>,
|
||||||
uri: Option<SharedString>,
|
uri: Option<SharedString>,
|
||||||
|
@ -32,7 +32,7 @@ impl<V, I, F> Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
||||||
self.uri = Some(uri.into());
|
self.uri = Some(uri.into());
|
||||||
|
@ -48,7 +48,7 @@ where
|
||||||
impl<V, F> Img<V, Anonymous, F>
|
impl<V, F> Img<V, Anonymous, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified, F> {
|
||||||
Img {
|
Img {
|
||||||
|
@ -63,7 +63,7 @@ impl<V, I, F> IntoAnyElement<V> for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn into_any(self) -> AnyElement<V> {
|
fn into_any(self) -> AnyElement<V> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
|
@ -74,7 +74,7 @@ impl<V, I, F> Element for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: Send + Sync + 'static,
|
V: Send + Sync + 'static,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
type ViewState = V;
|
type ViewState = V;
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
|
@ -143,7 +143,7 @@ impl<V, I, F> Styled for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
self.base.style()
|
self.base.style()
|
||||||
|
@ -154,10 +154,10 @@ impl<V, I, F> Interactive for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
fn interactive_state(&mut self) -> &mut InteractiveState<V> {
|
||||||
self.base.listeners()
|
self.base.interactive_state()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ impl<V, I, F> Hover for Img<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||||
self.base.set_hover_style(group, style);
|
self.base.set_hover_style(group, style);
|
||||||
|
@ -175,25 +175,29 @@ where
|
||||||
impl<V, F> Click for Img<V, Identified, F>
|
impl<V, F> Click for Img<V, Identified, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Img<V, Identified, F>
|
impl<V, F> Active for Img<V, Identified, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||||
self.base.set_active_style(group, style)
|
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
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
{
|
{
|
||||||
|
fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
|
||||||
|
self.base.focus_listeners()
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||||
self.base.set_focus_style(style)
|
self.base.set_focus_style(style)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
div, Active, Anonymous, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability,
|
div, Active, Anonymous, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability,
|
||||||
ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover, Identified, Interactive,
|
ElementId, ElementIdentity, Focus, FocusListeners, Focusable, Hover, Identified, Interactive,
|
||||||
IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StyleRefinement, Styled,
|
InteractiveState, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString,
|
||||||
ViewContext,
|
StyleRefinement, Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct Svg<
|
pub struct Svg<
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity = Anonymous,
|
I: ElementIdentity = Anonymous,
|
||||||
F: ElementFocusability = NonFocusable,
|
F: ElementFocusability<V> = NonFocusable,
|
||||||
> {
|
> {
|
||||||
base: Div<V, I, F>,
|
base: Div<V, I, F>,
|
||||||
path: Option<SharedString>,
|
path: Option<SharedString>,
|
||||||
|
@ -29,7 +29,7 @@ impl<V, I, F> Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||||
self.path = Some(path.into());
|
self.path = Some(path.into());
|
||||||
|
@ -40,7 +40,7 @@ where
|
||||||
impl<V, F> Svg<V, Anonymous, F>
|
impl<V, F> Svg<V, Anonymous, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, Identified, F> {
|
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, Identified, F> {
|
||||||
Svg {
|
Svg {
|
||||||
|
@ -54,7 +54,7 @@ impl<V, I, F> IntoAnyElement<V> for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn into_any(self) -> AnyElement<V> {
|
fn into_any(self) -> AnyElement<V> {
|
||||||
AnyElement::new(self)
|
AnyElement::new(self)
|
||||||
|
@ -65,7 +65,7 @@ impl<V, I, F> Element for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
type ViewState = V;
|
type ViewState = V;
|
||||||
type ElementState = DivState;
|
type ElementState = DivState;
|
||||||
|
@ -117,7 +117,7 @@ impl<V, I, F> Styled for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn style(&mut self) -> &mut StyleRefinement {
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
self.base.style()
|
self.base.style()
|
||||||
|
@ -128,10 +128,10 @@ impl<V, I, F> Interactive for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
fn interactive_state(&mut self) -> &mut InteractiveState<V> {
|
||||||
self.base.listeners()
|
self.base.interactive_state()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ impl<V, I, F> Hover for Svg<V, I, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||||
self.base.set_hover_style(group, style);
|
self.base.set_hover_style(group, style);
|
||||||
|
@ -149,25 +149,29 @@ where
|
||||||
impl<V, F> Click for Svg<V, Identified, F>
|
impl<V, F> Click for Svg<V, Identified, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, F> Active for Svg<V, Identified, F>
|
impl<V, F> Active for Svg<V, Identified, F>
|
||||||
where
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
F: ElementFocusability,
|
F: ElementFocusability<V>,
|
||||||
{
|
{
|
||||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||||
self.base.set_active_style(group, style)
|
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
|
where
|
||||||
V: 'static + Send + Sync,
|
V: 'static + Send + Sync,
|
||||||
I: ElementIdentity,
|
I: ElementIdentity,
|
||||||
{
|
{
|
||||||
|
fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
|
||||||
|
self.base.focus_listeners()
|
||||||
|
}
|
||||||
|
|
||||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||||
self.base.set_focus_style(style)
|
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;
|
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_style(&mut self, style: StyleRefinement);
|
||||||
fn set_focus_in_style(&mut self, style: StyleRefinement);
|
fn set_focus_in_style(&mut self, style: StyleRefinement);
|
||||||
fn set_in_focus_style(&mut self, style: StyleRefinement);
|
fn set_in_focus_style(&mut self, style: StyleRefinement);
|
||||||
|
@ -42,8 +49,7 @@ pub trait Focus: Interactive {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let handle = self.handle().clone();
|
let handle = self.handle().clone();
|
||||||
self.listeners()
|
self.focus_listeners()
|
||||||
.focus
|
|
||||||
.push(Arc::new(move |view, event, cx| {
|
.push(Arc::new(move |view, event, cx| {
|
||||||
if event.focused.as_ref() == Some(&handle) {
|
if event.focused.as_ref() == Some(&handle) {
|
||||||
listener(view, event, cx)
|
listener(view, event, cx)
|
||||||
|
@ -63,8 +69,7 @@ pub trait Focus: Interactive {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let handle = self.handle().clone();
|
let handle = self.handle().clone();
|
||||||
self.listeners()
|
self.focus_listeners()
|
||||||
.focus
|
|
||||||
.push(Arc::new(move |view, event, cx| {
|
.push(Arc::new(move |view, event, cx| {
|
||||||
if event.blurred.as_ref() == Some(&handle) {
|
if event.blurred.as_ref() == Some(&handle) {
|
||||||
listener(view, event, cx)
|
listener(view, event, cx)
|
||||||
|
@ -84,8 +89,7 @@ pub trait Focus: Interactive {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let handle = self.handle().clone();
|
let handle = self.handle().clone();
|
||||||
self.listeners()
|
self.focus_listeners()
|
||||||
.focus
|
|
||||||
.push(Arc::new(move |view, event, cx| {
|
.push(Arc::new(move |view, event, cx| {
|
||||||
let descendant_blurred = event
|
let descendant_blurred = event
|
||||||
.blurred
|
.blurred
|
||||||
|
@ -114,8 +118,7 @@ pub trait Focus: Interactive {
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let handle = self.handle().clone();
|
let handle = self.handle().clone();
|
||||||
self.listeners()
|
self.focus_listeners()
|
||||||
.focus
|
|
||||||
.push(Arc::new(move |view, event, cx| {
|
.push(Arc::new(move |view, event, cx| {
|
||||||
let descendant_blurred = event
|
let descendant_blurred = event
|
||||||
.blurred
|
.blurred
|
||||||
|
|
|
@ -5,7 +5,6 @@ mod assets;
|
||||||
mod color;
|
mod color;
|
||||||
mod element;
|
mod element;
|
||||||
mod elements;
|
mod elements;
|
||||||
mod events;
|
|
||||||
mod executor;
|
mod executor;
|
||||||
mod focus;
|
mod focus;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
@ -33,7 +32,6 @@ pub use assets::*;
|
||||||
pub use color::*;
|
pub use color::*;
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
pub use elements::*;
|
pub use elements::*;
|
||||||
pub use events::*;
|
|
||||||
pub use executor::*;
|
pub use executor::*;
|
||||||
pub use focus::*;
|
pub use focus::*;
|
||||||
pub use geometry::*;
|
pub use geometry::*;
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
use std::{any::TypeId, sync::Arc};
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DispatchPhase, Element, EventListeners, KeyDownEvent, KeyUpEvent, MouseButton, MouseClickEvent,
|
point, Action, Bounds, DispatchContext, DispatchPhase, Element, FocusHandle, Keystroke,
|
||||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
|
Modifiers, Pixels, Point, ViewContext,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
ops::Deref,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Interactive: Element {
|
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(
|
fn on_mouse_down(
|
||||||
mut self,
|
mut self,
|
||||||
|
@ -19,16 +24,16 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state().mouse_down.push(Arc::new(
|
||||||
.mouse_down
|
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
|
||||||
&& bounds.contains_point(&event.position)
|
&& bounds.contains_point(&event.position)
|
||||||
{
|
{
|
||||||
handler(view, event, cx)
|
handler(view, event, cx)
|
||||||
}
|
}
|
||||||
}));
|
},
|
||||||
|
));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +48,7 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state()
|
||||||
.mouse_up
|
.mouse_up
|
||||||
.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
|
||||||
|
@ -67,16 +72,16 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state().mouse_down.push(Arc::new(
|
||||||
.mouse_down
|
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
|
||||||
&& !bounds.contains_point(&event.position)
|
&& !bounds.contains_point(&event.position)
|
||||||
{
|
{
|
||||||
handler(view, event, cx)
|
handler(view, event, cx)
|
||||||
}
|
}
|
||||||
}));
|
},
|
||||||
|
));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +96,7 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state()
|
||||||
.mouse_up
|
.mouse_up
|
||||||
.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
|
||||||
|
@ -114,13 +119,13 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state().mouse_move.push(Arc::new(
|
||||||
.mouse_move
|
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);
|
||||||
}
|
}
|
||||||
}));
|
},
|
||||||
|
));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,13 +139,13 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state().scroll_wheel.push(Arc::new(
|
||||||
.scroll_wheel
|
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);
|
||||||
}
|
}
|
||||||
}));
|
},
|
||||||
|
));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +163,9 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners().key.push((
|
self.interactive_state().key.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();
|
||||||
listener(view, event, phase, cx);
|
listener(view, event, phase, cx);
|
||||||
None
|
None
|
||||||
|
@ -179,9 +184,9 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners().key.push((
|
self.interactive_state().key.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();
|
||||||
listener(view, event, phase, cx);
|
listener(view, event, phase, cx);
|
||||||
None
|
None
|
||||||
|
@ -200,9 +205,9 @@ pub trait Interactive: Element {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners().key.push((
|
self.interactive_state().key.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();
|
||||||
listener(view, event, phase, cx);
|
listener(view, event, phase, cx);
|
||||||
None
|
None
|
||||||
|
@ -223,9 +228,290 @@ pub trait Click: Interactive {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.listeners()
|
self.interactive_state()
|
||||||
.mouse_click
|
.mouse_click
|
||||||
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
||||||
self
|
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 anyhow::Result;
|
||||||
use smallvec::SmallVec;
|
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
|
self.context_predicate
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|predicate| predicate.eval(contexts))
|
.map(|predicate| predicate.eval(contexts))
|
||||||
|
@ -42,7 +42,7 @@ impl KeyBinding {
|
||||||
pub fn match_keystrokes(
|
pub fn match_keystrokes(
|
||||||
&self,
|
&self,
|
||||||
pending_keystrokes: &[Keystroke],
|
pending_keystrokes: &[Keystroke],
|
||||||
contexts: &[ActionContext],
|
contexts: &[&DispatchContext],
|
||||||
) -> KeyMatch {
|
) -> KeyMatch {
|
||||||
if self.keystrokes.as_ref().starts_with(&pending_keystrokes)
|
if self.keystrokes.as_ref().starts_with(&pending_keystrokes)
|
||||||
&& self.matches_context(contexts)
|
&& self.matches_context(contexts)
|
||||||
|
@ -61,7 +61,7 @@ impl KeyBinding {
|
||||||
pub fn keystrokes_for_action(
|
pub fn keystrokes_for_action(
|
||||||
&self,
|
&self,
|
||||||
action: &dyn Action,
|
action: &dyn Action,
|
||||||
contexts: &[ActionContext],
|
contexts: &[&DispatchContext],
|
||||||
) -> Option<SmallVec<[Keystroke; 2]>> {
|
) -> Option<SmallVec<[Keystroke; 2]>> {
|
||||||
if self.action.eq(action) && self.matches_context(contexts) {
|
if self.action.eq(action) && self.matches_context(contexts) {
|
||||||
Some(self.keystrokes.clone())
|
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 parking_lot::RwLock;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -44,7 +44,7 @@ impl KeyMatcher {
|
||||||
pub fn match_keystroke(
|
pub fn match_keystroke(
|
||||||
&mut self,
|
&mut self,
|
||||||
keystroke: &Keystroke,
|
keystroke: &Keystroke,
|
||||||
context_stack: &[ActionContext],
|
context_stack: &[&DispatchContext],
|
||||||
) -> KeyMatch {
|
) -> KeyMatch {
|
||||||
let keymap = self.keymap.read();
|
let keymap = self.keymap.read();
|
||||||
// Clear pending keystrokes if the keymap has changed since the last matched keystroke.
|
// Clear pending keystrokes if the keymap has changed since the last matched keystroke.
|
||||||
|
@ -86,7 +86,7 @@ impl KeyMatcher {
|
||||||
pub fn keystrokes_for_action(
|
pub fn keystrokes_for_action(
|
||||||
&self,
|
&self,
|
||||||
action: &dyn Action,
|
action: &dyn Action,
|
||||||
contexts: &[ActionContext],
|
contexts: &[&DispatchContext],
|
||||||
) -> Option<SmallVec<[Keystroke; 2]>> {
|
) -> Option<SmallVec<[Keystroke; 2]>> {
|
||||||
self.keymap
|
self.keymap
|
||||||
.read()
|
.read()
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
px, size, Action, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
px, size, Action, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
|
||||||
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect,
|
BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext,
|
||||||
Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId, GlyphId, Handle, Hsla,
|
DisplayId, Edges, Effect, Element, EntityId, EventEmitter, FocusEvent, FontId, GlobalElementId,
|
||||||
ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, LayoutId,
|
GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher,
|
||||||
MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform,
|
Keystroke, LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path,
|
||||||
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
|
Pixels, Platform, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference,
|
||||||
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
|
||||||
Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
|
SharedString, Size, Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle,
|
||||||
WindowOptions, SUBPIXEL_VARIANTS,
|
WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
@ -47,7 +47,12 @@ pub enum DispatchPhase {
|
||||||
|
|
||||||
type AnyListener = Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
type AnyListener = Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||||
type AnyKeyListener = Arc<
|
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
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
@ -155,8 +160,8 @@ pub struct Window {
|
||||||
z_index_stack: StackingOrder,
|
z_index_stack: StackingOrder,
|
||||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
|
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
|
||||||
key_listeners: Vec<(TypeId, AnyKeyListener)>,
|
key_dispatch_stack: Vec<KeyDispatchStackFrame>,
|
||||||
key_events_enabled: bool,
|
freeze_key_dispatch_stack: bool,
|
||||||
focus_stack: Vec<FocusId>,
|
focus_stack: Vec<FocusId>,
|
||||||
focus_parents_by_child: HashMap<FocusId, FocusId>,
|
focus_parents_by_child: HashMap<FocusId, FocusId>,
|
||||||
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
||||||
|
@ -230,24 +235,32 @@ impl Window {
|
||||||
z_index_stack: StackingOrder(SmallVec::new()),
|
z_index_stack: StackingOrder(SmallVec::new()),
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
mouse_listeners: HashMap::default(),
|
mouse_listeners: HashMap::default(),
|
||||||
key_listeners: Vec::new(),
|
key_dispatch_stack: Vec::new(),
|
||||||
key_events_enabled: true,
|
freeze_key_dispatch_stack: false,
|
||||||
focus_stack: Vec::new(),
|
focus_stack: Vec::new(),
|
||||||
focus_parents_by_child: HashMap::default(),
|
focus_parents_by_child: HashMap::default(),
|
||||||
focus_listeners: Vec::new(),
|
focus_listeners: Vec::new(),
|
||||||
|
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
|
||||||
propagate: true,
|
propagate: true,
|
||||||
default_prevented: true,
|
default_prevented: true,
|
||||||
mouse_position,
|
mouse_position,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
scene_builder: SceneBuilder::new(),
|
scene_builder: SceneBuilder::new(),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
|
|
||||||
last_blur: None,
|
last_blur: None,
|
||||||
focus: None,
|
focus: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum KeyDispatchStackFrame {
|
||||||
|
Listener {
|
||||||
|
event_type: TypeId,
|
||||||
|
listener: AnyKeyListener,
|
||||||
|
},
|
||||||
|
Context(DispatchContext),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ContentMask<P: Clone + Default + Debug> {
|
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
|
// Clear focus state, because we determine what is focused when the new elements
|
||||||
// in the upcoming frame are initialized.
|
// in the upcoming frame are initialized.
|
||||||
window.focus_listeners.clear();
|
window.focus_listeners.clear();
|
||||||
window.key_listeners.clear();
|
window.key_dispatch_stack.clear();
|
||||||
window.focus_parents_by_child.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 {
|
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);
|
.insert(any_mouse_event.type_id(), handlers);
|
||||||
}
|
}
|
||||||
} else if let Some(any_key_event) = event.keyboard_event() {
|
} 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();
|
let key_event_type = any_key_event.type_id();
|
||||||
|
let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new();
|
||||||
|
|
||||||
for (ix, (listener_event_type, listener)) in key_listeners.iter().enumerate() {
|
for (ix, frame) in key_dispatch_stack.iter().enumerate() {
|
||||||
if key_event_type == *listener_event_type {
|
match frame {
|
||||||
if let Some(action) = listener(any_key_event, DispatchPhase::Capture, self) {
|
KeyDispatchStackFrame::Listener {
|
||||||
self.dispatch_action(action, &key_listeners[..ix]);
|
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 {
|
KeyDispatchStackFrame::Context(context) => {
|
||||||
break;
|
context_stack.push(&context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.window.propagate {
|
if self.window.propagate {
|
||||||
for (ix, (listener_event_type, listener)) in key_listeners.iter().enumerate().rev()
|
for (ix, frame) in key_dispatch_stack.iter().enumerate().rev() {
|
||||||
{
|
match frame {
|
||||||
if key_event_type == *listener_event_type {
|
KeyDispatchStackFrame::Listener {
|
||||||
if let Some(action) = listener(any_key_event, DispatchPhase::Bubble, self) {
|
event_type,
|
||||||
self.dispatch_action(action, &key_listeners[..ix]);
|
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 {
|
if !self.window.propagate {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeyDispatchStackFrame::Context(_) => {
|
||||||
|
context_stack.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window.key_listeners = key_listeners;
|
drop(context_stack);
|
||||||
|
self.window.key_dispatch_stack = key_dispatch_stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -927,13 +971,14 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
&mut self,
|
&mut self,
|
||||||
element_id: &GlobalElementId,
|
element_id: &GlobalElementId,
|
||||||
keystroke: &Keystroke,
|
keystroke: &Keystroke,
|
||||||
|
context_stack: &[&DispatchContext],
|
||||||
) -> KeyMatch {
|
) -> KeyMatch {
|
||||||
let key_match = self
|
let key_match = self
|
||||||
.window
|
.window
|
||||||
.key_matchers
|
.key_matchers
|
||||||
.get_mut(element_id)
|
.get_mut(element_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.match_keystroke(keystroke, &[]);
|
.match_keystroke(keystroke, context_stack);
|
||||||
|
|
||||||
if key_match.is_some() {
|
if key_match.is_some() {
|
||||||
for matcher in self.window.key_matchers.values_mut() {
|
for matcher in self.window.key_matchers.values_mut() {
|
||||||
|
@ -944,23 +989,39 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
key_match
|
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();
|
let action_type = action.as_any().type_id();
|
||||||
for (event_type, listener) in listeners {
|
for stack_frame in dispatch_stack {
|
||||||
if action_type == *event_type {
|
if let KeyDispatchStackFrame::Listener {
|
||||||
listener(action.as_any(), DispatchPhase::Capture, self);
|
event_type,
|
||||||
if !self.window.propagate {
|
listener,
|
||||||
break;
|
} = stack_frame
|
||||||
|
{
|
||||||
|
if action_type == *event_type {
|
||||||
|
listener(action.as_any(), &[], DispatchPhase::Capture, self);
|
||||||
|
if !self.window.propagate {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.window.propagate {
|
if self.window.propagate {
|
||||||
for (event_type, listener) in listeners.iter().rev() {
|
for stack_frame in dispatch_stack.iter().rev() {
|
||||||
if action_type == *event_type {
|
if let KeyDispatchStackFrame::Listener {
|
||||||
listener(action.as_any(), DispatchPhase::Bubble, self);
|
event_type,
|
||||||
if !self.window.propagate {
|
listener,
|
||||||
break;
|
} = 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>)],
|
key_listeners: &[(TypeId, KeyListener<V>)],
|
||||||
f: impl FnOnce(&mut Self) -> R,
|
f: impl FnOnce(&mut Self) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
if self.window.key_events_enabled {
|
if !self.window.freeze_key_dispatch_stack {
|
||||||
for (event_type, listener) in key_listeners.iter().cloned() {
|
for (event_type, listener) in key_listeners.iter().cloned() {
|
||||||
let handle = self.handle();
|
let handle = self.handle();
|
||||||
let listener = Arc::new(
|
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
|
handle
|
||||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
.update(cx, |view, cx| {
|
||||||
|
listener(view, event, context_stack, phase, cx)
|
||||||
|
})
|
||||||
.log_err()
|
.log_err()
|
||||||
.flatten()
|
.flatten()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.window.key_listeners.push((event_type, listener));
|
self.window
|
||||||
|
.key_dispatch_stack
|
||||||
|
.push(KeyDispatchStackFrame::Listener {
|
||||||
|
event_type,
|
||||||
|
listener,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
|
|
||||||
if self.window.key_events_enabled {
|
if !self.window.freeze_key_dispatch_stack {
|
||||||
let prev_len = self.window.key_listeners.len() - key_listeners.len();
|
let prev_len = self.window.key_dispatch_stack.len() - key_listeners.len();
|
||||||
self.window.key_listeners.truncate(prev_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
|
result
|
||||||
|
@ -1325,7 +1416,7 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||||
self.window.focus_stack.push(focus_handle.id);
|
self.window.focus_stack.push(focus_handle.id);
|
||||||
|
|
||||||
if Some(focus_handle.id) == self.window.focus {
|
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);
|
let result = f(self);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue