diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 6a6afd5461b6abb1b2944635216b5fd8ff5270a2..74ca292ecf8b712588ab0f1713c2a93d9619d92d 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -22,10 +22,11 @@ use collections::{BTreeMap, HashMap}; use gpui::{ div, point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace, BorrowWindow, Bounds, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, - ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, IntoElement, LineLayout, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce, - ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, - TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine, + ElementInputHandler, Entity, EntityId, Hsla, InteractiveBounds, InteractiveElement, + IntoElement, LineLayout, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, + ParentElement, Pixels, RenderOnce, ScrollWheelEvent, ShapedLine, SharedString, Size, + StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, View, + ViewContext, WeakView, WindowContext, WrappedLine, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; @@ -316,6 +317,7 @@ impl EditorElement { position_map: &PositionMap, text_bounds: Bounds, gutter_bounds: Bounds, + stacking_order: &StackingOrder, cx: &mut ViewContext, ) -> bool { let mut click_count = event.click_count; @@ -326,6 +328,9 @@ impl EditorElement { } else if !text_bounds.contains_point(&event.position) { return false; } + if !cx.was_top_layer(&event.position, stacking_order) { + return false; + } let point_for_position = position_map.point_for_position(text_bounds, event.position); let position = point_for_position.previous_valid; @@ -384,6 +389,7 @@ impl EditorElement { event: &MouseUpEvent, position_map: &PositionMap, text_bounds: Bounds, + stacking_order: &StackingOrder, cx: &mut ViewContext, ) -> bool { let end_selection = editor.has_pending_selection(); @@ -396,6 +402,7 @@ impl EditorElement { if !pending_nonempty_selections && event.modifiers.command && text_bounds.contains_point(&event.position) + && cx.was_top_layer(&event.position, stacking_order) { let point = position_map.point_for_position(text_bounds, event.position); let could_be_inlay = point.as_valid().is_none(); @@ -418,6 +425,7 @@ impl EditorElement { position_map: &PositionMap, text_bounds: Bounds, gutter_bounds: Bounds, + stacking_order: &StackingOrder, cx: &mut ViewContext, ) -> bool { let modifiers = event.modifiers; @@ -457,10 +465,12 @@ impl EditorElement { let text_hovered = text_bounds.contains_point(&event.position); let gutter_hovered = gutter_bounds.contains_point(&event.position); + let was_top = cx.was_top_layer(&event.position, stacking_order); + editor.set_gutter_hovered(gutter_hovered, cx); // Don't trigger hover popover if mouse is hovering over context menu - if text_hovered { + if text_hovered && was_top { let point_for_position = position_map.point_for_position(text_bounds, event.position); match point_for_position.as_valid() { @@ -490,7 +500,7 @@ impl EditorElement { } else { update_go_to_definition_link(editor, None, modifiers.command, modifiers.shift, cx); hover_at(editor, None, cx); - gutter_hovered + gutter_hovered && was_top } } @@ -498,10 +508,10 @@ impl EditorElement { editor: &mut Editor, event: &ScrollWheelEvent, position_map: &PositionMap, - bounds: Bounds, + bounds: &InteractiveBounds, cx: &mut ViewContext, ) -> bool { - if !bounds.contains_point(&event.position) { + if !bounds.visibly_contains(&event.position, cx) { return false; } @@ -2282,10 +2292,15 @@ impl EditorElement { cx: &mut WindowContext, ) { let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO); + let interactive_bounds = InteractiveBounds { + bounds: bounds.intersect(&cx.content_mask().bounds), + stacking_order: cx.stacking_order().clone(), + }; cx.on_mouse_event({ let position_map = layout.position_map.clone(); let editor = self.editor.clone(); + let interactive_bounds = interactive_bounds.clone(); move |event: &ScrollWheelEvent, phase, cx| { if phase != DispatchPhase::Bubble { @@ -2293,7 +2308,7 @@ impl EditorElement { } let should_cancel = editor.update(cx, |editor, cx| { - Self::scroll(editor, event, &position_map, bounds, cx) + Self::scroll(editor, event, &position_map, &interactive_bounds, cx) }); if should_cancel { cx.stop_propagation(); @@ -2304,6 +2319,7 @@ impl EditorElement { cx.on_mouse_event({ let position_map = layout.position_map.clone(); let editor = self.editor.clone(); + let stacking_order = cx.stacking_order().clone(); move |event: &MouseDownEvent, phase, cx| { if phase != DispatchPhase::Bubble { @@ -2311,7 +2327,15 @@ impl EditorElement { } let should_cancel = editor.update(cx, |editor, cx| { - Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) + Self::mouse_down( + editor, + event, + &position_map, + text_bounds, + gutter_bounds, + &stacking_order, + cx, + ) }); if should_cancel { @@ -2323,9 +2347,18 @@ impl EditorElement { cx.on_mouse_event({ let position_map = layout.position_map.clone(); let editor = self.editor.clone(); + let stacking_order = cx.stacking_order().clone(); + move |event: &MouseUpEvent, phase, cx| { let should_cancel = editor.update(cx, |editor, cx| { - Self::mouse_up(editor, event, &position_map, text_bounds, cx) + Self::mouse_up( + editor, + event, + &position_map, + text_bounds, + &stacking_order, + cx, + ) }); if should_cancel { @@ -2351,13 +2384,23 @@ impl EditorElement { cx.on_mouse_event({ let position_map = layout.position_map.clone(); let editor = self.editor.clone(); + let stacking_order = cx.stacking_order().clone(); + move |event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } let stop_propogating = editor.update(cx, |editor, cx| { - Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) + Self::mouse_moved( + editor, + event, + &position_map, + text_bounds, + gutter_bounds, + &stacking_order, + cx, + ) }); if stop_propogating { @@ -2617,9 +2660,11 @@ impl Element for EditorElement { // We call with_z_index to establish a new stacking context. cx.with_z_index(0, |cx| { cx.with_content_mask(Some(ContentMask { bounds }), |cx| { - // Paint mouse listeners first, so any elements we paint on top of the editor + // Paint mouse listeners at z-index 0 so any elements we paint on top of the editor // take precedence. - self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx); + cx.with_z_index(0, |cx| { + self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx); + }); let input_handler = ElementInputHandler::new(bounds, self.editor.clone(), cx); cx.handle_input(&focus_handle, input_handler); diff --git a/crates/editor2/src/hover_popover.rs b/crates/editor2/src/hover_popover.rs index 37c7df650b126c859c28339a09077a96f4844bf2..f80168ed250d3f3bdcbedb7ad1d61e9e173f15ef 100644 --- a/crates/editor2/src/hover_popover.rs +++ b/crates/editor2/src/hover_popover.rs @@ -483,9 +483,6 @@ impl InfoPopover { // Prevent a mouse move on the popover from being propagated to the editor, // because that would dismiss the popover. .on_mouse_move(|_, cx| cx.stop_propagation()) - // Prevent a mouse down on the popover from being propagated to the editor, - // because that would move the cursor. - .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation()) .child(crate::render_parsed_markdown( "content", &self.parsed_content, diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 6185cd644364794eec85f6218c62c7e3643f5cb8..635e8b634f0f6982fffa2d35ca46da5bfb736e90 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -723,12 +723,12 @@ pub struct Interactivity { #[derive(Clone)] pub struct InteractiveBounds { - bounds: Bounds, - stacking_order: StackingOrder, + pub bounds: Bounds, + pub stacking_order: StackingOrder, } impl InteractiveBounds { - fn visibly_contains(&self, point: &Point, cx: &WindowContext) -> bool { + pub fn visibly_contains(&self, point: &Point, cx: &WindowContext) -> bool { self.bounds.contains_point(point) && cx.was_top_layer(&point, &self.stacking_order) } } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 0d444d762ecd80c7846aa71c062dcfeb755e5a7d..6f342f70654653808d6b9797c898682ba4c532e8 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -12,7 +12,7 @@ use crate::{ VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Context as _, Result}; -use collections::{BTreeMap, HashMap}; +use collections::HashMap; use derive_more::{Deref, DerefMut}; use futures::{ channel::{mpsc, oneshot}, @@ -243,7 +243,7 @@ pub(crate) struct Frame { pub(crate) dispatch_tree: DispatchTree, pub(crate) focus_listeners: Vec, pub(crate) scene_builder: SceneBuilder, - pub(crate) depth_map: BTreeMap>, + pub(crate) depth_map: Vec<(StackingOrder, Bounds)>, pub(crate) z_index_stack: StackingOrder, content_mask_stack: Vec>, element_offset_stack: Vec>, @@ -811,10 +811,10 @@ impl<'a> WindowContext<'a> { /// Called during painting to track which z-index is on top at each pixel position pub fn add_opaque_layer(&mut self, bounds: Bounds) { let stacking_order = self.window.current_frame.z_index_stack.clone(); - self.window - .current_frame - .depth_map - .insert(stacking_order, bounds); + let depth_map = &mut self.window.current_frame.depth_map; + match depth_map.binary_search_by(|(level, _)| stacking_order.cmp(&level)) { + Ok(i) | Err(i) => depth_map.insert(i, (stacking_order, bounds)), + } } /// Returns true if the top-most opaque layer painted over this point was part of the diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 50f8611c4cc645c414ad68c030867ab4b8f07dab..6fa722f7757615ad01acdddfc8d527f457f94411 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -2640,12 +2640,11 @@ impl Workspace { .flex_col() .justify_end() .gap_2() - .children(self.notifications.iter().map(|(_, _, notification)| { - div() - .on_any_mouse_down(|_, cx| cx.stop_propagation()) - .on_any_mouse_up(|_, cx| cx.stop_propagation()) - .child(notification.to_any()) - })), + .children( + self.notifications + .iter() + .map(|(_, _, notification)| notification.to_any()), + ), ) } }