Store generic mouse regions on window that contain their event type id
This commit is contained in:
parent
812d3f6af6
commit
b95b2af3e0
8 changed files with 130 additions and 57 deletions
|
@ -11,8 +11,11 @@ use gpui::{
|
||||||
EngineLayout, EventContext, RenderContext, ViewContext,
|
EngineLayout, EventContext, RenderContext, ViewContext,
|
||||||
};
|
};
|
||||||
use playground_macros::tailwind_lengths;
|
use playground_macros::tailwind_lengths;
|
||||||
use smallvec::SmallVec;
|
use std::{
|
||||||
use std::{any::Any, cell::Cell, rc::Rc};
|
any::{Any, TypeId},
|
||||||
|
cell::Cell,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
pub use crate::paint_context::PaintContext;
|
pub use crate::paint_context::PaintContext;
|
||||||
pub use taffy::tree::NodeId;
|
pub use taffy::tree::NodeId;
|
||||||
|
@ -22,28 +25,32 @@ pub struct Layout<'a, E: ?Sized> {
|
||||||
pub from_element: &'a mut E,
|
pub from_element: &'a mut E,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ElementHandlers<V> {
|
|
||||||
mouse_button: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ElementMetadata<V> {
|
pub struct ElementMetadata<V> {
|
||||||
pub style: ElementStyle,
|
pub style: ElementStyle,
|
||||||
pub handlers: ElementHandlers<V>,
|
pub handlers: Vec<EventHandler<V>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EventHandler<V> {
|
||||||
|
handler: Rc<dyn Fn(&mut V, &dyn Any, &mut EventContext<V>)>,
|
||||||
|
event_type: TypeId,
|
||||||
|
outside_bounds: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> Clone for EventHandler<V> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
handler: self.handler.clone(),
|
||||||
|
event_type: self.event_type,
|
||||||
|
outside_bounds: self.outside_bounds,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Default for ElementMetadata<V> {
|
impl<V> Default for ElementMetadata<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
style: ElementStyle::default(),
|
style: ElementStyle::default(),
|
||||||
handlers: ElementHandlers::default(),
|
handlers: Vec::new(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V> Default for ElementHandlers<V> {
|
|
||||||
fn default() -> Self {
|
|
||||||
ElementHandlers {
|
|
||||||
mouse_button: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +59,8 @@ pub trait Element<V: 'static>: 'static {
|
||||||
type Layout: 'static;
|
type Layout: 'static;
|
||||||
|
|
||||||
fn style_mut(&mut self) -> &mut ElementStyle;
|
fn style_mut(&mut self) -> &mut ElementStyle;
|
||||||
fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
|
||||||
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
|
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
|
||||||
-> Result<(NodeId, Self::Layout)>;
|
-> Result<(NodeId, Self::Layout)>;
|
||||||
fn paint<'a>(
|
fn paint<'a>(
|
||||||
|
@ -96,6 +104,12 @@ pub trait Element<V: 'static>: 'static {
|
||||||
pressed.set(true);
|
pressed.set(true);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.mouse_up_outside(button, {
|
||||||
|
let pressed = pressed.clone();
|
||||||
|
move |_, _, _| {
|
||||||
|
pressed.set(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
.mouse_up(button, move |view, event, event_cx| {
|
.mouse_up(button, move |view, event, event_cx| {
|
||||||
if pressed.get() {
|
if pressed.get() {
|
||||||
pressed.set(false);
|
pressed.set(false);
|
||||||
|
@ -112,13 +126,37 @@ pub trait Element<V: 'static>: 'static {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.handlers_mut()
|
self.handlers_mut().push(EventHandler {
|
||||||
.mouse_button
|
handler: Rc::new(move |view, event, event_cx| {
|
||||||
.push(Rc::new(move |view, event, event_cx| {
|
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
|
||||||
if event.button == button && event.is_down {
|
if event.button == button && event.is_down {
|
||||||
handler(view, event, event_cx);
|
handler(view, event, event_cx);
|
||||||
}
|
}
|
||||||
}));
|
}),
|
||||||
|
event_type: TypeId::of::<MouseButtonEvent>(),
|
||||||
|
outside_bounds: false,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_down_outside(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.handlers_mut().push(EventHandler {
|
||||||
|
handler: Rc::new(move |view, event, event_cx| {
|
||||||
|
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
|
||||||
|
if event.button == button && event.is_down {
|
||||||
|
handler(view, event, event_cx);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
event_type: TypeId::of::<MouseButtonEvent>(),
|
||||||
|
outside_bounds: true,
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,13 +168,37 @@ pub trait Element<V: 'static>: 'static {
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.handlers_mut()
|
self.handlers_mut().push(EventHandler {
|
||||||
.mouse_button
|
handler: Rc::new(move |view, event, event_cx| {
|
||||||
.push(Rc::new(move |view, event, event_cx| {
|
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
|
||||||
if event.button == button && !event.is_down {
|
if event.button == button && !event.is_down {
|
||||||
handler(view, event, event_cx);
|
handler(view, event, event_cx);
|
||||||
}
|
}
|
||||||
}));
|
}),
|
||||||
|
event_type: TypeId::of::<MouseButtonEvent>(),
|
||||||
|
outside_bounds: false,
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_up_outside(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.handlers_mut().push(EventHandler {
|
||||||
|
handler: Rc::new(move |view, event, event_cx| {
|
||||||
|
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
|
||||||
|
if event.button == button && !event.is_down {
|
||||||
|
handler(view, event, event_cx);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
event_type: TypeId::of::<MouseButtonEvent>(),
|
||||||
|
outside_bounds: true,
|
||||||
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,7 +424,7 @@ pub trait Element<V: 'static>: 'static {
|
||||||
// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
|
// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
|
||||||
trait ElementObject<V> {
|
trait ElementObject<V> {
|
||||||
fn style_mut(&mut self) -> &mut ElementStyle;
|
fn style_mut(&mut self) -> &mut ElementStyle;
|
||||||
fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
|
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
|
||||||
-> Result<(NodeId, Box<dyn Any>)>;
|
-> Result<(NodeId, Box<dyn Any>)>;
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -378,7 +440,7 @@ impl<V: 'static, E: Element<V>> ElementObject<V> for E {
|
||||||
Element::style_mut(self)
|
Element::style_mut(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
|
||||||
Element::handlers_mut(self)
|
Element::handlers_mut(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,19 +516,27 @@ impl<V: 'static> AnyElement<V> {
|
||||||
from_element: element_layout.as_mut(),
|
from_element: element_layout.as_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for handler in self.element.handlers_mut().mouse_button.iter().cloned() {
|
for event_handler in self.element.handlers_mut().iter().cloned() {
|
||||||
let EngineLayout { order, bounds } = layout.from_engine;
|
let EngineLayout { order, bounds } = layout.from_engine;
|
||||||
|
|
||||||
let view_id = cx.view_id();
|
let view_id = cx.view_id();
|
||||||
cx.draw_interactive_region(
|
let view_event_handler = event_handler.handler.clone();
|
||||||
order,
|
|
||||||
bounds,
|
// TODO: Tuck this into a method on PaintContext.
|
||||||
move |view, event: &MouseButtonEvent, window_cx| {
|
cx.scene
|
||||||
let mut view_cx = ViewContext::mutable(window_cx, view_id);
|
.interactive_regions
|
||||||
let mut event_cx = EventContext::new(&mut view_cx);
|
.push(gpui::scene::InteractiveRegion {
|
||||||
(handler)(view, event, &mut event_cx);
|
order,
|
||||||
},
|
bounds,
|
||||||
);
|
outside_bounds: event_handler.outside_bounds,
|
||||||
|
event_handler: Rc::new(move |view, event, window_cx, view_id| {
|
||||||
|
let mut view_context = ViewContext::mutable(window_cx, view_id);
|
||||||
|
let mut event_context = EventContext::new(&mut view_context);
|
||||||
|
view_event_handler(view.downcast_mut().unwrap(), event, &mut event_context);
|
||||||
|
}),
|
||||||
|
event_type: event_handler.event_type,
|
||||||
|
view_id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.element.paint(layout, view, cx)?;
|
self.element.paint(layout, view, cx)?;
|
||||||
|
@ -485,7 +555,7 @@ impl<V: 'static> Element<V> for AnyElement<V> {
|
||||||
self.element.style_mut()
|
self.element.style_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
|
||||||
self.element.handlers_mut()
|
self.element.handlers_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
element::{
|
element::{
|
||||||
AnyElement, Element, ElementHandlers, IntoElement, Layout, LayoutContext, NodeId,
|
AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, PaintContext,
|
||||||
PaintContext,
|
|
||||||
},
|
},
|
||||||
style::ElementStyle,
|
style::ElementStyle,
|
||||||
};
|
};
|
||||||
|
@ -13,14 +12,14 @@ use playground_macros::IntoElement;
|
||||||
#[element_crate = "crate"]
|
#[element_crate = "crate"]
|
||||||
pub struct Frame<V: 'static> {
|
pub struct Frame<V: 'static> {
|
||||||
style: ElementStyle,
|
style: ElementStyle,
|
||||||
handlers: ElementHandlers<V>,
|
handlers: Vec<EventHandler<V>>,
|
||||||
children: Vec<AnyElement<V>>,
|
children: Vec<AnyElement<V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame<V>() -> Frame<V> {
|
pub fn frame<V>() -> Frame<V> {
|
||||||
Frame {
|
Frame {
|
||||||
style: ElementStyle::default(),
|
style: ElementStyle::default(),
|
||||||
handlers: ElementHandlers::default(),
|
handlers: Vec::new(),
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +31,7 @@ impl<V: 'static> Element<V> for Frame<V> {
|
||||||
&mut self.style
|
&mut self.style
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
|
||||||
&mut self.handlers
|
&mut self.handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,14 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||||
&mut self,
|
&mut self,
|
||||||
order: u32,
|
order: u32,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
outside_bounds: bool,
|
||||||
handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
|
handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
|
||||||
) {
|
) {
|
||||||
// We'll sort these by their order in `take_interactive_regions`.
|
// We'll sort these by their order in `take_interactive_regions`.
|
||||||
self.scene.interactive_regions.push(InteractiveRegion {
|
self.scene.interactive_regions.push(InteractiveRegion {
|
||||||
order,
|
order,
|
||||||
bounds,
|
bounds,
|
||||||
|
outside_bounds,
|
||||||
event_handler: Rc::new(move |view, event, window_cx, view_id| {
|
event_handler: Rc::new(move |view, event, window_cx, view_id| {
|
||||||
let mut cx = ViewContext::mutable(window_cx, view_id);
|
let mut cx = ViewContext::mutable(window_cx, view_id);
|
||||||
let mut cx = EventContext::new(&mut cx);
|
let mut cx = EventContext::new(&mut cx);
|
||||||
|
|
|
@ -49,12 +49,7 @@ fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||||
.h_full()
|
.h_full()
|
||||||
.w_half()
|
.w_half()
|
||||||
.fill(theme.success(0.5))
|
.fill(theme.success(0.5))
|
||||||
.child(
|
.child(button().label("Hello").click(|_, _, _| println!("click!")))
|
||||||
button()
|
|
||||||
.label("Hello")
|
|
||||||
.mouse_up(MouseButton::Left, |_, _, _| (println!("up!")))
|
|
||||||
.mouse_down(MouseButton::Left, |_, _, _| (println!("down!"))),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!()
|
// todo!()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::element::{Element, ElementMetadata, IntoElement};
|
use crate::element::{Element, ElementMetadata, EventHandler, IntoElement};
|
||||||
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
|
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -26,10 +26,6 @@ impl<V: 'static> Element<V> for Text<V> {
|
||||||
&mut self.metadata.style
|
&mut self.metadata.style
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
|
|
||||||
&mut self.metadata.handlers
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
|
@ -95,6 +91,10 @@ impl<V: 'static> Element<V> for Text<V> {
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
|
||||||
|
&mut self.metadata.handlers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextLayout {
|
pub struct TextLayout {
|
||||||
|
|
|
@ -83,7 +83,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
|
||||||
&mut self.metadata.style
|
&mut self.metadata.style
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlers_mut(&mut self) -> &mut #crate_name::element::ElementHandlers<V> {
|
fn handlers_mut(&mut self) -> &mut Vec<#crate_name::element::EventHandler<V>> {
|
||||||
&mut self.metadata.handlers
|
&mut self.metadata.handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,10 @@ impl Window {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("root_view called during window construction")
|
.expect("root_view called during window construction")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn take_interactive_regions(&mut self) -> Vec<InteractiveRegion> {
|
||||||
|
mem::take(&mut self.interactive_regions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowContext<'a> {
|
pub struct WindowContext<'a> {
|
||||||
|
@ -875,11 +879,13 @@ impl<'a> WindowContext<'a> {
|
||||||
fn dispatch_to_interactive_regions(&mut self, event: &Event) {
|
fn dispatch_to_interactive_regions(&mut self, event: &Event) {
|
||||||
if let Some(mouse_event) = event.mouse_event() {
|
if let Some(mouse_event) = event.mouse_event() {
|
||||||
let mouse_position = event.position().expect("mouse events must have a position");
|
let mouse_position = event.position().expect("mouse events must have a position");
|
||||||
let interactive_regions = std::mem::take(&mut self.window.interactive_regions);
|
let interactive_regions = self.window.take_interactive_regions();
|
||||||
|
|
||||||
for region in interactive_regions.iter().rev() {
|
for region in interactive_regions.iter().rev() {
|
||||||
if region.event_type == mouse_event.type_id() {
|
if region.event_type == mouse_event.type_id() {
|
||||||
if region.bounds.contains_point(mouse_position) {
|
let in_bounds = region.bounds.contains_point(mouse_position);
|
||||||
|
|
||||||
|
if in_bounds == !region.outside_bounds {
|
||||||
self.update_any_view(region.view_id, |view, window_cx| {
|
self.update_any_view(region.view_id, |view, window_cx| {
|
||||||
(region.event_handler)(
|
(region.event_handler)(
|
||||||
view.as_any_mut(),
|
view.as_any_mut(),
|
||||||
|
|
|
@ -711,6 +711,7 @@ impl MouseRegion {
|
||||||
pub struct InteractiveRegion {
|
pub struct InteractiveRegion {
|
||||||
pub order: u32,
|
pub order: u32,
|
||||||
pub bounds: RectF,
|
pub bounds: RectF,
|
||||||
|
pub outside_bounds: bool,
|
||||||
pub event_handler: Rc<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
|
pub event_handler: Rc<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
|
||||||
pub event_type: TypeId,
|
pub event_type: TypeId,
|
||||||
pub view_id: usize,
|
pub view_id: usize,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue