Add basic mouse event handling
This commit is contained in:
parent
f763ed9a7e
commit
8074e6b46a
6 changed files with 70 additions and 43 deletions
|
@ -1,13 +1,11 @@
|
||||||
mod div;
|
mod div;
|
||||||
mod img;
|
mod img;
|
||||||
mod interactive;
|
|
||||||
mod stateless;
|
mod stateless;
|
||||||
mod svg;
|
mod svg;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
pub use div::*;
|
pub use div::*;
|
||||||
pub use img::*;
|
pub use img::*;
|
||||||
pub use interactive::*;
|
|
||||||
pub use stateless::*;
|
pub use stateless::*;
|
||||||
pub use svg::*;
|
pub use svg::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, Bounds, Element, LayoutId, Overflow, ParentElement, Pixels, Point, Refineable,
|
AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
|
||||||
RefinementCascade, Result, Style, StyleHelpers, Styled, ViewContext,
|
ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, StyleHelpers,
|
||||||
|
Styled, ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -9,7 +10,7 @@ use util::ResultExt;
|
||||||
|
|
||||||
pub struct Div<S: 'static> {
|
pub struct Div<S: 'static> {
|
||||||
styles: RefinementCascade<Style>,
|
styles: RefinementCascade<Style>,
|
||||||
// handlers: InteractionHandlers<V>,
|
listeners: MouseEventListeners<S>,
|
||||||
children: SmallVec<[AnyElement<S>; 2]>,
|
children: SmallVec<[AnyElement<S>; 2]>,
|
||||||
scroll_state: Option<ScrollState>,
|
scroll_state: Option<ScrollState>,
|
||||||
}
|
}
|
||||||
|
@ -17,7 +18,7 @@ pub struct Div<S: 'static> {
|
||||||
pub fn div<S>() -> Div<S> {
|
pub fn div<S>() -> Div<S> {
|
||||||
Div {
|
Div {
|
||||||
styles: Default::default(),
|
styles: Default::default(),
|
||||||
// handlers: Default::default(),
|
listeners: Default::default(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
scroll_state: None,
|
scroll_state: None,
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,7 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
|
||||||
&mut self,
|
&mut self,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
child_layouts: &mut Self::FrameState,
|
child_layout_ids: &mut Self::FrameState,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let style = self.computed_style();
|
let style = self.computed_style();
|
||||||
|
@ -51,10 +52,13 @@ impl<S: 'static + Send + Sync> Element for Div<S> {
|
||||||
let overflow = &style.overflow;
|
let overflow = &style.overflow;
|
||||||
style.apply_text_style(cx, |cx| {
|
style.apply_text_style(cx, |cx| {
|
||||||
cx.stack(1, |cx| {
|
cx.stack(1, |cx| {
|
||||||
style.apply_overflow(bounds, cx, |cx| self.paint_children(overflow, state, cx))
|
style.apply_overflow(bounds, cx, |cx| {
|
||||||
|
self.listeners.paint(bounds, cx);
|
||||||
|
self.paint_children(overflow, state, cx)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
self.handle_scroll(bounds, style.overflow.clone(), child_layouts, cx);
|
self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
|
||||||
|
|
||||||
// todo!("enable inspector")
|
// todo!("enable inspector")
|
||||||
// if cx.is_inspector_enabled() {
|
// if cx.is_inspector_enabled() {
|
||||||
|
@ -247,11 +251,11 @@ impl<V> Styled for Div<V> {
|
||||||
|
|
||||||
impl<V> StyleHelpers for Div<V> {}
|
impl<V> StyleHelpers for Div<V> {}
|
||||||
|
|
||||||
// impl<V> Interactive<V> for Div<V> {
|
impl<V: Send + Sync + 'static> Interactive<V> for Div<V> {
|
||||||
// fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
|
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
|
||||||
// &mut self.handlers
|
&mut self.listeners
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
impl<V: 'static> ParentElement<V> for Div<V> {
|
impl<V: 'static> ParentElement<V> for Div<V> {
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod elements;
|
||||||
mod executor;
|
mod executor;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
mod image_cache;
|
mod image_cache;
|
||||||
|
mod interactive;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod scene;
|
mod scene;
|
||||||
mod style;
|
mod style;
|
||||||
|
@ -28,6 +29,7 @@ pub use executor::*;
|
||||||
pub use geometry::*;
|
pub use geometry::*;
|
||||||
pub use gpui3_macros::*;
|
pub use gpui3_macros::*;
|
||||||
pub use image_cache::*;
|
pub use image_cache::*;
|
||||||
|
pub use interactive::*;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
pub use refineable::*;
|
pub use refineable::*;
|
||||||
pub use scene::*;
|
pub use scene::*;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use smallvec::SmallVec;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub trait Interactive<S: 'static + Send + Sync> {
|
pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
fn interaction_listeners(&mut self) -> &mut InteractionHandlers<S>;
|
fn listeners(&mut self) -> &mut MouseEventListeners<S>;
|
||||||
|
|
||||||
fn on_mouse_down(
|
fn on_mouse_down(
|
||||||
mut self,
|
mut self,
|
||||||
|
@ -16,10 +16,13 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interaction_listeners()
|
self.listeners()
|
||||||
.mouse_down
|
.mouse_down
|
||||||
.push(Arc::new(move |view, event, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && event.button == button {
|
if phase == DispatchPhase::Bubble
|
||||||
|
&& event.button == button
|
||||||
|
&& bounds.contains_point(event.position)
|
||||||
|
{
|
||||||
handler(view, event, cx)
|
handler(view, event, cx)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -34,10 +37,13 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interaction_listeners()
|
self.listeners()
|
||||||
.mouse_up
|
.mouse_up
|
||||||
.push(Arc::new(move |view, event, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Bubble && event.button == button {
|
if phase == DispatchPhase::Bubble
|
||||||
|
&& event.button == button
|
||||||
|
&& bounds.contains_point(event.position)
|
||||||
|
{
|
||||||
handler(view, event, cx)
|
handler(view, event, cx)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -52,10 +58,13 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interaction_listeners()
|
self.listeners()
|
||||||
.mouse_down
|
.mouse_down
|
||||||
.push(Arc::new(move |view, event, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if phase == DispatchPhase::Capture && event.button == button {
|
if phase == DispatchPhase::Capture
|
||||||
|
&& event.button == button
|
||||||
|
&& !bounds.contains_point(event.position)
|
||||||
|
{
|
||||||
handler(view, event, cx)
|
handler(view, event, cx)
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -70,10 +79,13 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.interaction_listeners()
|
self.listeners()
|
||||||
.mouse_up
|
.mouse_up
|
||||||
.push(Arc::new(move |view, event, phase, cx| {
|
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||||
if event.button == button && phase == DispatchPhase::Capture {
|
if phase == DispatchPhase::Capture
|
||||||
|
&& event.button == button
|
||||||
|
&& !bounds.contains_point(event.position)
|
||||||
|
{
|
||||||
handler(view, event, cx);
|
handler(view, event, cx);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -83,7 +95,7 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
fn on_click(
|
fn on_click(
|
||||||
self,
|
self,
|
||||||
button: MouseButton,
|
button: MouseButton,
|
||||||
handler: impl Fn(&mut S, &MouseDownEvent, &MouseUpEvent, &mut ViewContext<S>)
|
handler: impl Fn(&mut S, (&MouseDownEvent, &MouseUpEvent), &mut ViewContext<S>)
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
@ -106,43 +118,50 @@ pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
})
|
})
|
||||||
.on_mouse_up(button, move |view, event, cx| {
|
.on_mouse_up(button, move |view, event, cx| {
|
||||||
if let Some(down_event) = down_event.lock().take() {
|
if let Some(down_event) = down_event.lock().take() {
|
||||||
handler(view, &down_event, event, cx);
|
handler(view, (&down_event, event), cx);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MouseDownHandler<V> = Arc<
|
type MouseDownHandler<V> = Arc<
|
||||||
dyn Fn(&mut V, &MouseDownEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
|
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
>;
|
||||||
|
type MouseUpHandler<V> = Arc<
|
||||||
|
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
type MouseUpHandler<V> =
|
|
||||||
Arc<dyn Fn(&mut V, &MouseUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
|
||||||
|
|
||||||
pub struct InteractionHandlers<V: 'static> {
|
pub struct MouseEventListeners<V: 'static> {
|
||||||
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||||
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Send + Sync + 'static> InteractionHandlers<S> {
|
impl<S: Send + Sync + 'static> MouseEventListeners<S> {
|
||||||
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
|
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
|
||||||
for handler in self.mouse_down.iter().cloned() {
|
for handler in self.mouse_down.iter().cloned() {
|
||||||
cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
|
cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
|
||||||
if bounds.contains_point(event.position) {
|
if bounds.contains_point(event.position) {
|
||||||
handler(view, event, phase, cx);
|
handler(view, event, &bounds, phase, cx);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for handler in self.mouse_up.iter().cloned() {
|
for handler in self.mouse_up.iter().cloned() {
|
||||||
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
|
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
|
||||||
if bounds.contains_point(event.position) {
|
if bounds.contains_point(event.position) {
|
||||||
handler(view, event, phase, cx);
|
handler(view, event, &bounds, phase, cx);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Default for InteractionHandlers<V> {
|
impl<V> Default for MouseEventListeners<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mouse_down: Default::default(),
|
mouse_down: Default::default(),
|
|
@ -278,7 +278,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
self.window.rem_size
|
self.window.rem_size
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_event_propagation(&mut self) {
|
pub fn stop_propagation(&mut self) {
|
||||||
self.window.propagate_event = false;
|
self.window.propagate_event = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,10 +625,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
.mouse_event_handlers
|
.mouse_event_handlers
|
||||||
.remove(&any_mouse_event.type_id())
|
.remove(&any_mouse_event.type_id())
|
||||||
{
|
{
|
||||||
// We sort these every time, because handlers may add handlers. Probably fast enough.
|
// Because handlers may add other handlers, we sort every time.
|
||||||
handlers.sort_by(|(a, _), (b, _)| a.cmp(b));
|
handlers.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
// Handlers may set this to false by calling `stop_propagation`;
|
// Handlers may set this to false by calling `stop_propagation`
|
||||||
self.window.propagate_event = true;
|
self.window.propagate_event = true;
|
||||||
|
|
||||||
// Capture phase, events bubble from back to front. Handlers for this phase are used for
|
// Capture phase, events bubble from back to front. Handlers for this phase are used for
|
||||||
|
@ -640,7 +640,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bubble phase
|
// Bubble phase, where most normal handlers do their work.
|
||||||
if self.window.propagate_event {
|
if self.window.propagate_event {
|
||||||
for (_, handler) in handlers.iter().rev() {
|
for (_, handler) in handlers.iter().rev() {
|
||||||
handler(any_mouse_event, DispatchPhase::Bubble, self);
|
handler(any_mouse_event, DispatchPhase::Bubble, self);
|
||||||
|
@ -650,6 +650,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Just in case any handlers added new handlers, which is weird, but possible.
|
||||||
handlers.extend(
|
handlers.extend(
|
||||||
self.window
|
self.window
|
||||||
.mouse_event_handlers
|
.mouse_event_handlers
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::theme::{theme, Theme};
|
use crate::theme::{theme, Theme};
|
||||||
use gpui3::{
|
use gpui3::{
|
||||||
div, img, svg, view, AppContext, Context, Element, IntoAnyElement, ParentElement, ScrollState,
|
div, img, svg, view, AppContext, Context, Element, Interactive, IntoAnyElement, MouseButton,
|
||||||
SharedString, StyleHelpers, View, ViewContext, WindowContext,
|
ParentElement, ScrollState, SharedString, StyleHelpers, View, ViewContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CollabPanel {
|
pub struct CollabPanel {
|
||||||
|
@ -44,6 +44,9 @@ impl CollabPanel {
|
||||||
// List Container
|
// List Container
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
.on_click(MouseButton::Left, |_, _, _| {
|
||||||
|
dbg!("click!");
|
||||||
|
})
|
||||||
.fill(theme.lowest.base.default.background)
|
.fill(theme.lowest.base.default.background)
|
||||||
.pb_1()
|
.pb_1()
|
||||||
.border_color(theme.lowest.base.default.border)
|
.border_color(theme.lowest.base.default.border)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue