From 70e2951e35d595086cef48aec528d8a20d8c7d64 Mon Sep 17 00:00:00 2001 From: K Simmons Date: Fri, 21 Oct 2022 15:53:43 -0700 Subject: [PATCH] add mouse region handler bool for adding the handler above the child --- crates/drag_and_drop/src/drag_and_drop.rs | 2 +- crates/editor/src/element.rs | 12 +- crates/gpui/src/elements/flex.rs | 2 +- .../gpui/src/elements/mouse_event_handler.rs | 72 +++-- crates/gpui/src/elements/overlay.rs | 35 ++- crates/gpui/src/elements/uniform_list.rs | 2 +- crates/gpui/src/presenter.rs | 6 +- crates/workspace/src/dock.rs | 39 +-- crates/workspace/src/pane.rs | 246 +++++++++--------- 9 files changed, 225 insertions(+), 191 deletions(-) diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 31265a16972267a57b15bc5683d0e1f47c6bb656..bb660c750f5a1676e8802d66f8c82f2a9e62b3b2 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -125,7 +125,7 @@ impl DragAndDrop { cx.defer(|cx| { cx.update_global::(|this, cx| this.stop_dragging(cx)); }); - cx.propogate_event(); + cx.propagate_event(); }) .on_up_out(MouseButton::Left, |_, cx| { cx.defer(|cx| { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index d8f5c83daffd4805ee089a5717229dbb88855e6b..5628b886fe8ce99ac038490ff0a7587c40cbfec9 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -137,7 +137,7 @@ impl EditorElement { gutter_bounds, cx, ) { - cx.propogate_event(); + cx.propagate_event(); } } }) @@ -150,7 +150,7 @@ impl EditorElement { text_bounds, cx, ) { - cx.propogate_event(); + cx.propagate_event(); } } }) @@ -167,7 +167,7 @@ impl EditorElement { text_bounds, cx, ) { - cx.propogate_event() + cx.propagate_event() } } }) @@ -182,7 +182,7 @@ impl EditorElement { text_bounds, cx, ) { - cx.propogate_event() + cx.propagate_event() } } }) @@ -190,7 +190,7 @@ impl EditorElement { let position_map = position_map.clone(); move |e, cx| { if !Self::mouse_moved(e.platform_event, &position_map, text_bounds, cx) { - cx.propogate_event() + cx.propagate_event() } } }) @@ -199,7 +199,7 @@ impl EditorElement { move |e, cx| { if !Self::scroll(e.position, e.delta, e.precise, &position_map, bounds, cx) { - cx.propogate_event() + cx.propagate_event() } } }), diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index 95477c75601452f7aa26400d5cc4cb880021deb6..129d36dadd3818e8d215ad4a1e85d5850c9add66 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -277,7 +277,7 @@ impl Element for Flex { cx.notify(); } else { - cx.propogate_event(); + cx.propagate_event(); } } }) diff --git a/crates/gpui/src/elements/mouse_event_handler.rs b/crates/gpui/src/elements/mouse_event_handler.rs index b3b18ec3d012ed36b0fb0ede56e712fc44749edd..01779fb362f061eb961419f85360e1849c72e1a2 100644 --- a/crates/gpui/src/elements/mouse_event_handler.rs +++ b/crates/gpui/src/elements/mouse_event_handler.rs @@ -23,10 +23,14 @@ pub struct MouseEventHandler { hoverable: bool, notify_on_hover: bool, notify_on_click: bool, + above: bool, padding: Padding, _tag: PhantomData, } +// MouseEventHandler::new +// MouseEventHandler::above + impl MouseEventHandler { pub fn new(region_id: usize, cx: &mut RenderContext, render_child: F) -> Self where @@ -45,11 +49,22 @@ impl MouseEventHandler { notify_on_hover, notify_on_click, hoverable: true, + above: false, padding: Default::default(), _tag: PhantomData, } } + pub fn above(region_id: usize, cx: &mut RenderContext, render_child: F) -> Self + where + V: View, + F: FnOnce(&mut MouseState, &mut RenderContext) -> ElementBox, + { + let mut handler = Self::new(region_id, cx, render_child); + handler.above = true; + handler + } + pub fn with_cursor_style(mut self, cursor: CursorStyle) -> Self { self.cursor_style = Some(cursor); self @@ -149,6 +164,29 @@ impl MouseEventHandler { ) .round_out() } + + fn paint_regions(&self, bounds: RectF, visible_bounds: RectF, cx: &mut PaintContext) { + let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); + let hit_bounds = self.hit_bounds(visible_bounds); + + if let Some(style) = self.cursor_style { + cx.scene.push_cursor_region(CursorRegion { + bounds: hit_bounds, + style, + }); + } + cx.scene.push_mouse_region( + MouseRegion::from_handlers::( + cx.current_view_id(), + self.region_id, + hit_bounds, + self.handlers.clone(), + ) + .with_hoverable(self.hoverable) + .with_notify_on_hover(self.notify_on_hover) + .with_notify_on_click(self.notify_on_click), + ); + } } impl Element for MouseEventHandler { @@ -170,30 +208,16 @@ impl Element for MouseEventHandler { _: &mut Self::LayoutState, cx: &mut PaintContext, ) -> Self::PaintState { - let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default(); - let hit_bounds = self.hit_bounds(visible_bounds); - - self.child.paint(bounds.origin(), visible_bounds, cx); - - cx.paint_stacking_context(None, |cx| { - if let Some(style) = self.cursor_style { - cx.scene.push_cursor_region(CursorRegion { - bounds: hit_bounds, - style, - }); - } - cx.scene.push_mouse_region( - MouseRegion::from_handlers::( - cx.current_view_id(), - self.region_id, - hit_bounds, - self.handlers.clone(), - ) - .with_hoverable(self.hoverable) - .with_notify_on_hover(self.notify_on_hover) - .with_notify_on_click(self.notify_on_click), - ); - }); + if self.above { + self.child.paint(bounds.origin(), visible_bounds, cx); + + cx.paint_layer(None, |cx| { + self.paint_regions(bounds, visible_bounds, cx); + }); + } else { + self.paint_regions(bounds, visible_bounds, cx); + self.child.paint(bounds.origin(), visible_bounds, cx); + } } fn rect_for_text_range( diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index 253c88f703a36abc30162053fa42b3c586738b6d..15d3d764f2a626d9a2b4e2530e284e44f85ec9f4 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -204,25 +204,24 @@ impl Element for Overlay { OverlayFitMode::None => {} } - cx.scene.push_stacking_context(None); - - if self.hoverable { - enum OverlayHoverCapture {} - // Block hovers in lower stacking contexts - cx.scene - .push_mouse_region(MouseRegion::new::( - cx.current_view_id(), - cx.current_view_id(), - bounds, - )); - } + cx.paint_stacking_context(None, |cx| { + if self.hoverable { + enum OverlayHoverCapture {} + // Block hovers in lower stacking contexts + cx.scene + .push_mouse_region(MouseRegion::new::( + cx.current_view_id(), + cx.current_view_id(), + bounds, + )); + } - self.child.paint( - bounds.origin(), - RectF::new(Vector2F::zero(), cx.window_size), - cx, - ); - cx.scene.pop_stacking_context(); + self.child.paint( + bounds.origin(), + RectF::new(Vector2F::zero(), cx.window_size), + cx, + ); + }); } fn rect_for_text_range( diff --git a/crates/gpui/src/elements/uniform_list.rs b/crates/gpui/src/elements/uniform_list.rs index ca3601491ab2a507bef84fdcbcdd53bd72d209b1..0eab7f0bc9baaee74a2090ecdcd4a00be051c83d 100644 --- a/crates/gpui/src/elements/uniform_list.rs +++ b/crates/gpui/src/elements/uniform_list.rs @@ -304,7 +304,7 @@ impl Element for UniformList { }, cx| { if !Self::scroll(state.clone(), position, delta, precise, scroll_max, cx) { - cx.propogate_event(); + cx.propagate_event(); } } }), diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index e1fa1349da5de89459d13f35cf30be51e2fb8184..453ee0d60d12dd2c8319eaf13d5bb2fce911b0b4 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -485,9 +485,7 @@ impl Presenter { 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); - } + |cx| callback(region_event, cx) }); } @@ -804,7 +802,7 @@ impl<'a> EventContext<'a> { self.notify_count } - pub fn propogate_event(&mut self) { + pub fn propagate_event(&mut self) { self.handled = false; } } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index aebb12727d87e2568d091ef3f16f6f8a4b5c9fc3..9b1dec8d2d54d5bdef6efb6d3f6582f964237975 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -1,7 +1,7 @@ use collections::HashMap; use gpui::{ actions, - elements::{ChildView, Container, Empty, MouseEventHandler, Side, Svg}, + elements::{ChildView, Container, Empty, MouseEventHandler, ParentElement, Side, Stack, Svg}, impl_internal_actions, Border, CursorStyle, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, View, ViewContext, ViewHandle, WeakViewHandle, }; @@ -308,25 +308,34 @@ impl Dock { DockAnchor::Expanded => { enum ExpandedDockWash {} enum ExpandedDockPane {} - Container::new( - MouseEventHandler::::new(0, cx, |_state, cx| { + Stack::new() + .with_child( + // Render wash under the dock which when clicked hides it + MouseEventHandler::::new(0, cx, |_, _| { + Empty::new() + .contained() + .with_background_color(style.wash_color) + .boxed() + }) + .capture_all() + .on_down(MouseButton::Left, |_, cx| { + cx.dispatch_action(HideDock); + }) + .with_cursor_style(CursorStyle::Arrow) + .boxed(), + ) + .with_child( MouseEventHandler::::new(0, cx, |_state, cx| { ChildView::new(&self.pane, cx).boxed() }) + // Make sure all events directly under the dock pane + // are captured .capture_all() .contained() .with_style(style.maximized) - .boxed() - }) - .capture_all() - .on_down(MouseButton::Left, |_, cx| { - cx.dispatch_action(HideDock); - }) - .with_cursor_style(CursorStyle::Arrow) - .boxed(), - ) - .with_background_color(style.wash_color) - .boxed() + .boxed(), + ) + .boxed() } }) } @@ -391,7 +400,7 @@ impl View for ToggleDockButton { .on_up(MouseButton::Left, move |_, cx| { let dock_pane = workspace.read(cx.app).dock_pane(); let drop_index = dock_pane.read(cx.app).items_len() + 1; - Pane::handle_dropped_item(&dock_pane.downgrade(), drop_index, cx); + Pane::handle_dropped_item(&dock_pane.downgrade(), drop_index, false, cx); }); if dock_position.is_visible() { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 4865b0aa51641120a3eabaec4c0eadbd14bece48..e3ac7a2947706ce75f0b074a067f1be771d80d7a 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1061,127 +1061,123 @@ impl Pane { enum Tab {} enum Filler {} let pane = cx.handle(); - MouseEventHandler::::new(0, cx, |_, cx| { - let autoscroll = if mem::take(&mut self.autoscroll) { - Some(self.active_item_index) - } else { - None - }; - - let pane_active = self.is_active; - - let mut row = Flex::row().scrollable::(1, autoscroll, cx); - for (ix, (item, detail)) in self - .items - .iter() - .cloned() - .zip(self.tab_details(cx)) - .enumerate() - { - let detail = if detail == 0 { None } else { Some(detail) }; - let tab_active = ix == self.active_item_index; + let autoscroll = if mem::take(&mut self.autoscroll) { + Some(self.active_item_index) + } else { + None + }; - row.add_child({ - MouseEventHandler::::new(ix, cx, { - let item = item.clone(); - let pane = pane.clone(); - let detail = detail.clone(); + let pane_active = self.is_active; + let mut row = Flex::row().scrollable::(1, autoscroll, cx); + for (ix, (item, detail)) in self + .items + .iter() + .cloned() + .zip(self.tab_details(cx)) + .enumerate() + { + let detail = if detail == 0 { None } else { Some(detail) }; + let tab_active = ix == self.active_item_index; + + row.add_child({ + MouseEventHandler::::above(ix, cx, { + let item = item.clone(); + let pane = pane.clone(); + let detail = detail.clone(); + + let theme = cx.global::().theme.clone(); + + move |mouse_state, cx| { + let tab_style = theme.workspace.tab_bar.tab_style(pane_active, tab_active); + let hovered = mouse_state.hovered(); + Self::render_tab( + &item, + pane, + ix == 0, + detail, + hovered, + Self::tab_overlay_color(hovered, theme.as_ref(), cx), + tab_style, + cx, + ) + } + }) + .with_cursor_style(if pane_active && tab_active { + CursorStyle::Arrow + } else { + CursorStyle::PointingHand + }) + .on_down(MouseButton::Left, move |_, cx| { + cx.dispatch_action(ActivateItem(ix)); + cx.propagate_event(); + }) + .on_click(MouseButton::Middle, { + let item = item.clone(); + let pane = pane.clone(); + move |_, cx: &mut EventContext| { + cx.dispatch_action(CloseItem { + item_id: item.id(), + pane: pane.clone(), + }) + } + }) + .on_up(MouseButton::Left, { + let pane = pane.clone(); + move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, ix, true, cx) + }) + .as_draggable( + DraggedItem { + item, + pane: pane.clone(), + }, + { let theme = cx.global::().theme.clone(); - move |mouse_state, cx| { - let tab_style = - theme.workspace.tab_bar.tab_style(pane_active, tab_active); - let hovered = mouse_state.hovered(); + let detail = detail.clone(); + move |dragged_item, cx: &mut RenderContext| { + let tab_style = &theme.workspace.tab_bar.dragged_tab; Self::render_tab( - &item, - pane, - ix == 0, + &dragged_item.item, + dragged_item.pane.clone(), + false, detail, - hovered, - Self::tab_overlay_color(hovered, theme.as_ref(), cx), - tab_style, + false, + None, + &tab_style, cx, ) } - }) - .with_cursor_style(if pane_active && tab_active { - CursorStyle::Arrow - } else { - CursorStyle::PointingHand - }) - .on_down(MouseButton::Left, move |_, cx| { - cx.dispatch_action(ActivateItem(ix)); - }) - .on_click(MouseButton::Middle, { - let item = item.clone(); - let pane = pane.clone(); - move |_, cx: &mut EventContext| { - cx.dispatch_action(CloseItem { - item_id: item.id(), - pane: pane.clone(), - }) - } - }) - .on_up(MouseButton::Left, { - let pane = pane.clone(); - move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, ix, cx) - }) - .as_draggable( - DraggedItem { - item, - pane: pane.clone(), - }, - { - let theme = cx.global::().theme.clone(); - - let detail = detail.clone(); - move |dragged_item, cx: &mut RenderContext| { - let tab_style = &theme.workspace.tab_bar.dragged_tab; - Self::render_tab( - &dragged_item.item, - dragged_item.pane.clone(), - false, - detail, - false, - None, - &tab_style, - cx, - ) - } - }, - ) - .boxed() - }) - } + }, + ) + .boxed() + }) + } - // Use the inactive tab style along with the current pane's active status to decide how to render - // the filler - let filler_style = theme.workspace.tab_bar.tab_style(pane_active, false); - row.add_child( - MouseEventHandler::::new(0, cx, |mouse_state, cx| { - let mut filler = Empty::new() - .contained() - .with_style(filler_style.container) - .with_border(filler_style.container.border); - - if let Some(overlay) = - Self::tab_overlay_color(mouse_state.hovered(), &theme, cx) - { - filler = filler.with_overlay_color(overlay); - } + // Use the inactive tab style along with the current pane's active status to decide how to render + // the filler + let filler_style = theme.workspace.tab_bar.tab_style(pane_active, false); + row.add_child( + MouseEventHandler::::new(0, cx, |mouse_state, cx| { + let mut filler = Empty::new() + .contained() + .with_style(filler_style.container) + .with_border(filler_style.container.border); + + if let Some(overlay) = Self::tab_overlay_color(mouse_state.hovered(), &theme, cx) { + filler = filler.with_overlay_color(overlay); + } - filler.boxed() - }) - .flex(1., true) - .named("filler"), - ); + filler.boxed() + }) + .on_up(MouseButton::Left, move |_, cx| { + Pane::handle_dropped_item(&pane, filler_index, true, cx) + }) + .flex(1., true) + .named("filler"), + ); - row.boxed() - }) - .on_up(MouseButton::Left, move |_, cx| { - Pane::handle_dropped_item(&pane, filler_index, cx) - }) + row } fn tab_details(&self, cx: &AppContext) -> Vec { @@ -1305,7 +1301,6 @@ impl Pane { }) } }) - .on_click(MouseButton::Middle, |_, cx| cx.propogate_event()) .named("close-tab-icon") } else { Empty::new().boxed() @@ -1325,19 +1320,26 @@ impl Pane { tab.constrained().with_height(tab_style.height).boxed() } - pub fn handle_dropped_item(pane: &WeakViewHandle, index: usize, cx: &mut EventContext) { + pub fn handle_dropped_item( + pane: &WeakViewHandle, + index: usize, + allow_same_pane: bool, + cx: &mut EventContext, + ) { if let Some((_, dragged_item)) = cx .global::>() .currently_dragged::(cx.window_id) { - cx.dispatch_action(MoveItem { - item_id: dragged_item.item.id(), - from: dragged_item.pane.clone(), - to: pane.clone(), - destination_index: index, - }) + if pane != &dragged_item.pane || allow_same_pane { + cx.dispatch_action(MoveItem { + item_id: dragged_item.item.id(), + from: dragged_item.pane.clone(), + to: pane.clone(), + destination_index: index, + }) + } } else { - cx.propogate_event(); + cx.propagate_event(); } } @@ -1448,7 +1450,7 @@ impl View for Pane { }) .with_child({ let drop_index = self.active_item_index + 1; - MouseEventHandler::::new( + MouseEventHandler::::above( 0, cx, |_, cx| { @@ -1469,7 +1471,7 @@ impl View for Pane { .on_up(MouseButton::Left, { let pane = cx.handle(); move |_, cx: &mut EventContext| { - Pane::handle_dropped_item(&pane, drop_index, cx) + Pane::handle_dropped_item(&pane, drop_index, false, cx) } }) .flex(1., true) @@ -1491,7 +1493,9 @@ impl View for Pane { }) .on_up(MouseButton::Left, { let pane = this.clone(); - move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, 0, cx) + move |_, cx: &mut EventContext| { + Pane::handle_dropped_item(&pane, 0, true, cx) + } }) .boxed() }