diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index 273bb588af..8aba1d3e54 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -92,6 +92,8 @@ impl View for ContextMenu { .boxed(); Overlay::new(expanded_menu) + .hoverable(true) + .align_to_fit(true) .with_abs_position(self.position) .boxed() } diff --git a/crates/gpui/src/elements/overlay.rs b/crates/gpui/src/elements/overlay.rs index d841bcbc04..6010cfcd6a 100644 --- a/crates/gpui/src/elements/overlay.rs +++ b/crates/gpui/src/elements/overlay.rs @@ -10,6 +10,8 @@ use crate::{ pub struct Overlay { child: ElementBox, abs_position: Option, + align_to_fit: bool, + hoverable: bool, } impl Overlay { @@ -17,6 +19,8 @@ impl Overlay { Self { child, abs_position: None, + align_to_fit: false, + hoverable: false, } } @@ -24,6 +28,16 @@ impl Overlay { self.abs_position = Some(position); self } + + pub fn align_to_fit(mut self, align_to_fit: bool) -> Self { + self.align_to_fit = align_to_fit; + self + } + + pub fn hoverable(mut self, hoverable: bool) -> Self { + self.hoverable = hoverable; + self + } } impl Element for Overlay { @@ -51,15 +65,30 @@ impl Element for Overlay { size: &mut Self::LayoutState, cx: &mut PaintContext, ) { - let origin = self.abs_position.unwrap_or(bounds.origin()); - let visible_bounds = RectF::new(origin, *size); + let mut bounds = RectF::new(self.abs_position.unwrap_or(bounds.origin()), *size); cx.scene.push_stacking_context(None); - cx.scene.push_mouse_region(MouseRegion { - view_id: cx.current_view_id(), - bounds: visible_bounds, - ..Default::default() - }); - self.child.paint(origin, visible_bounds, cx); + + if self.hoverable { + cx.scene.push_mouse_region(MouseRegion { + view_id: cx.current_view_id(), + bounds, + ..Default::default() + }); + } + + if self.align_to_fit { + // Align overlay to the left if its bounds overflow the window width. + if bounds.lower_right().x() > cx.window_size.x() { + bounds.set_origin_x(bounds.origin_x() - bounds.width()); + } + + // Align overlay to the top if its bounds overflow the window height. + if bounds.lower_right().y() > cx.window_size.y() { + bounds.set_origin_y(bounds.origin_y() - bounds.height()); + } + } + + self.child.paint(bounds.origin(), bounds, cx); cx.scene.pop_stacking_context(); } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 9ed0f5cba6..a1b91a9faa 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -1,6 +1,6 @@ use super::{ - ContainerStyle, Element, ElementBox, Flex, KeystrokeLabel, MouseEventHandler, ParentElement, - Text, + ContainerStyle, Element, ElementBox, Flex, KeystrokeLabel, MouseEventHandler, Overlay, + ParentElement, Text, }; use crate::{ fonts::TextStyle, @@ -21,7 +21,7 @@ const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500); pub struct Tooltip { child: ElementBox, tooltip: Option, - state: ElementStateHandle>, + _state: ElementStateHandle>, } #[derive(Default)] @@ -68,15 +68,20 @@ impl Tooltip { ) .boxed(); Some( - Self::render_tooltip(text, style, action, false) - .constrained() - .dynamically(move |constraint, cx| { - SizeConstraint::strict_along( - Axis::Vertical, - collapsed_tooltip.layout(constraint, cx).y(), - ) - }) - .boxed(), + Overlay::new( + Self::render_tooltip(text, style, action, false) + .constrained() + .dynamically(move |constraint, cx| { + SizeConstraint::strict_along( + Axis::Vertical, + collapsed_tooltip.layout(constraint, cx).y(), + ) + }) + .boxed(), + ) + .align_to_fit(true) + .with_abs_position(state.position.get()) + .boxed(), ) } else { None @@ -111,7 +116,7 @@ impl Tooltip { Self { child, tooltip, - state: state_handle, + _state: state_handle, } } @@ -171,22 +176,7 @@ impl Element for Tooltip { ) { self.child.paint(bounds.origin(), visible_bounds, cx); if let Some(tooltip) = self.tooltip.as_mut() { - let origin = self.state.read(cx).position.get(); - let mut bounds = RectF::new(origin, tooltip.size()); - - // Align tooltip to the left if its bounds overflow the window width. - if bounds.lower_right().x() > cx.window_size.x() { - bounds.set_origin_x(bounds.origin_x() - bounds.width()); - } - - // Align tooltip to the top if its bounds overflow the window height. - if bounds.lower_right().y() > cx.window_size.y() { - bounds.set_origin_y(bounds.origin_y() - bounds.height()); - } - - cx.scene.push_stacking_context(None); - tooltip.paint(bounds.origin(), bounds, cx); - cx.scene.pop_stacking_context(); + tooltip.paint(bounds.origin(), visible_bounds, cx); } }