diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index e43e428fe6..c988bb330b 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -475,27 +475,33 @@ impl Presenter { if let MouseEvent::Down(e) = &mouse_event { if valid_region .handlers - .contains_handler(MouseEvent::click_disc(), Some(e.button)) + .contains(MouseEvent::click_disc(), Some(e.button)) || valid_region .handlers - .contains_handler(MouseEvent::drag_disc(), Some(e.button)) + .contains(MouseEvent::drag_disc(), Some(e.button)) { event_cx.handled = true; } } - if let Some(callback) = valid_region.handlers.get(&mouse_event.handler_key()) { - event_cx.handled = true; - event_cx.with_current_view(valid_region.id().view_id(), { - let region_event = mouse_event.clone(); - |cx| callback(region_event, cx) - }); + // `event_consumed` should only be true if there are any handlers for this event. + let mut event_consumed = false; + if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) { + event_consumed = true; + for callback in callbacks { + event_cx.handled = true; + event_cx.with_current_view(valid_region.id().view_id(), { + let region_event = mouse_event.clone(); + |cx| callback(region_event, cx) + }); + event_consumed &= event_cx.handled; + any_event_handled |= event_cx.handled; + } } - any_event_handled = any_event_handled || event_cx.handled; - // For bubbling events, if the event was handled, don't continue dispatching - // This only makes sense for local events. - if event_cx.handled && mouse_event.is_capturable() { + // For bubbling events, if the event was handled, don't continue dispatching. + // This only makes sense for local events which return false from is_capturable. + if event_consumed && mouse_event.is_capturable() { break; } } diff --git a/crates/gpui/src/scene/mouse_event.rs b/crates/gpui/src/scene/mouse_event.rs index d7370ac75f..00d1ddbf8b 100644 --- a/crates/gpui/src/scene/mouse_event.rs +++ b/crates/gpui/src/scene/mouse_event.rs @@ -5,7 +5,7 @@ use std::{ use pathfinder_geometry::{rect::RectF, vector::Vector2F}; -use crate::{MouseButton, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; +use crate::{scene::mouse_region::HandlerKey, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; #[derive(Debug, Default, Clone)] pub struct MouseMove { @@ -217,17 +217,17 @@ impl MouseEvent { discriminant(&MouseEvent::ScrollWheel(Default::default())) } - pub fn handler_key(&self) -> (Discriminant, Option) { + pub fn handler_key(&self) -> HandlerKey { match self { - MouseEvent::Move(_) => (Self::move_disc(), None), - MouseEvent::Drag(e) => (Self::drag_disc(), e.pressed_button), - MouseEvent::Hover(_) => (Self::hover_disc(), None), - MouseEvent::Down(e) => (Self::down_disc(), Some(e.button)), - MouseEvent::Up(e) => (Self::up_disc(), Some(e.button)), - MouseEvent::Click(e) => (Self::click_disc(), Some(e.button)), - MouseEvent::UpOut(e) => (Self::up_out_disc(), Some(e.button)), - MouseEvent::DownOut(e) => (Self::down_out_disc(), Some(e.button)), - MouseEvent::ScrollWheel(_) => (Self::scroll_wheel_disc(), None), + MouseEvent::Move(_) => HandlerKey::new(Self::move_disc(), None), + MouseEvent::Drag(e) => HandlerKey::new(Self::drag_disc(), e.pressed_button), + MouseEvent::Hover(_) => HandlerKey::new(Self::hover_disc(), None), + MouseEvent::Down(e) => HandlerKey::new(Self::down_disc(), Some(e.button)), + MouseEvent::Up(e) => HandlerKey::new(Self::up_disc(), Some(e.button)), + MouseEvent::Click(e) => HandlerKey::new(Self::click_disc(), Some(e.button)), + MouseEvent::UpOut(e) => HandlerKey::new(Self::up_out_disc(), Some(e.button)), + MouseEvent::DownOut(e) => HandlerKey::new(Self::down_out_disc(), Some(e.button)), + MouseEvent::ScrollWheel(_) => HandlerKey::new(Self::scroll_wheel_disc(), None), } } } diff --git a/crates/gpui/src/scene/mouse_region.rs b/crates/gpui/src/scene/mouse_region.rs index 4b5217cc2d..0fdc76ebbf 100644 --- a/crates/gpui/src/scene/mouse_region.rs +++ b/crates/gpui/src/scene/mouse_region.rs @@ -3,6 +3,7 @@ use std::{any::TypeId, fmt::Debug, mem::Discriminant, rc::Rc}; use collections::HashMap; use pathfinder_geometry::rect::RectF; +use smallvec::SmallVec; use crate::{EventContext, MouseButton}; @@ -177,61 +178,105 @@ impl MouseRegionId { } } +pub type HandlerCallback = Rc; + +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct HandlerKey { + event_kind: Discriminant, + button: Option, +} + +impl HandlerKey { + pub fn new(event_kind: Discriminant, button: Option) -> HandlerKey { + HandlerKey { event_kind, button } + } +} + #[derive(Clone, Default)] pub struct HandlerSet { - #[allow(clippy::type_complexity)] - pub set: HashMap< - (Discriminant, Option), - Rc, - >, + set: HashMap>, } impl HandlerSet { pub fn capture_all() -> Self { - #[allow(clippy::type_complexity)] - let mut set: HashMap< - (Discriminant, Option), - Rc, - > = Default::default(); + let mut set: HashMap> = HashMap::default(); - set.insert((MouseEvent::move_disc(), None), Rc::new(|_, _| {})); - set.insert((MouseEvent::hover_disc(), None), Rc::new(|_, _| {})); + set.insert( + HandlerKey::new(MouseEvent::move_disc(), None), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); + set.insert( + HandlerKey::new(MouseEvent::hover_disc(), None), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); for button in MouseButton::all() { - set.insert((MouseEvent::drag_disc(), Some(button)), Rc::new(|_, _| {})); - set.insert((MouseEvent::down_disc(), Some(button)), Rc::new(|_, _| {})); - set.insert((MouseEvent::up_disc(), Some(button)), Rc::new(|_, _| {})); - set.insert((MouseEvent::click_disc(), Some(button)), Rc::new(|_, _| {})); set.insert( - (MouseEvent::down_out_disc(), Some(button)), - Rc::new(|_, _| {}), + HandlerKey::new(MouseEvent::drag_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), ); set.insert( - (MouseEvent::up_out_disc(), Some(button)), - Rc::new(|_, _| {}), + HandlerKey::new(MouseEvent::down_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); + set.insert( + HandlerKey::new(MouseEvent::up_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); + set.insert( + HandlerKey::new(MouseEvent::click_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); + set.insert( + HandlerKey::new(MouseEvent::down_out_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); + set.insert( + HandlerKey::new(MouseEvent::up_out_disc(), Some(button)), + SmallVec::from_buf([Rc::new(|_, _| {})]), ); } - set.insert((MouseEvent::scroll_wheel_disc(), None), Rc::new(|_, _| {})); + set.insert( + HandlerKey::new(MouseEvent::scroll_wheel_disc(), None), + SmallVec::from_buf([Rc::new(|_, _| {})]), + ); HandlerSet { set } } - pub fn get( - &self, - key: &(Discriminant, Option), - ) -> Option> { - self.set.get(key).cloned() + pub fn get(&self, key: &HandlerKey) -> Option<&[HandlerCallback]> { + self.set.get(key).map(|vec| vec.as_slice()) } - pub fn contains_handler( + pub fn contains( &self, - event: Discriminant, + discriminant: Discriminant, button: Option, ) -> bool { - self.set.contains_key(&(event, button)) + self.set + .contains_key(&HandlerKey::new(discriminant, button)) + } + + fn insert( + &mut self, + event_kind: Discriminant, + button: Option, + callback: HandlerCallback, + ) { + use std::collections::hash_map::Entry; + + match self.set.entry(HandlerKey::new(event_kind, button)) { + Entry::Occupied(mut vec) => { + vec.get_mut().push(callback); + } + + Entry::Vacant(entry) => { + entry.insert(SmallVec::from_buf([callback])); + } + } } pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut EventContext) + 'static) -> Self { - self.set.insert((MouseEvent::move_disc(), None), + self.insert(MouseEvent::move_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Move(e) = region_event { handler(e, cx); @@ -249,7 +294,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseDown, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::down_disc(), Some(button)), + self.insert(MouseEvent::down_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Down(e) = region_event { handler(e, cx); @@ -267,7 +312,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseUp, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::up_disc(), Some(button)), + self.insert(MouseEvent::up_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Up(e) = region_event { handler(e, cx); @@ -285,7 +330,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseClick, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::click_disc(), Some(button)), + self.insert(MouseEvent::click_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Click(e) = region_event { handler(e, cx); @@ -303,7 +348,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseDownOut, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::down_out_disc(), Some(button)), + self.insert(MouseEvent::down_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::DownOut(e) = region_event { handler(e, cx); @@ -321,7 +366,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseUpOut, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::up_out_disc(), Some(button)), + self.insert(MouseEvent::up_out_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::UpOut(e) = region_event { handler(e, cx); @@ -339,7 +384,7 @@ impl HandlerSet { button: MouseButton, handler: impl Fn(MouseDrag, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::drag_disc(), Some(button)), + self.insert(MouseEvent::drag_disc(), Some(button), Rc::new(move |region_event, cx| { if let MouseEvent::Drag(e) = region_event { handler(e, cx); @@ -353,7 +398,7 @@ impl HandlerSet { } pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut EventContext) + 'static) -> Self { - self.set.insert((MouseEvent::hover_disc(), None), + self.insert(MouseEvent::hover_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::Hover(e) = region_event { handler(e, cx); @@ -370,7 +415,7 @@ impl HandlerSet { mut self, handler: impl Fn(MouseScrollWheel, &mut EventContext) + 'static, ) -> Self { - self.set.insert((MouseEvent::scroll_wheel_disc(), None), + self.insert(MouseEvent::scroll_wheel_disc(), None, Rc::new(move |region_event, cx| { if let MouseEvent::ScrollWheel(e) = region_event { handler(e, cx);