diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 9e454dc6529fae93fc799d23f5ff43c52e3ed834..bc9101fa0cc18b6a826e45b1230bfc31d3223578 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -899,6 +899,7 @@ pub(crate) struct AnyDrag { pub cursor_offset: Point, } +#[derive(Clone)] pub(crate) struct AnyTooltip { pub view: AnyView, pub cursor_offset: Point, diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index dd09ad512bf25d2e3049efa63ea032256df35d7e..da208b38131f8ddd0e297c47bc504065af232d15 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -2,7 +2,7 @@ use crate::{ div, point, px, Action, AnyDrag, AnyTooltip, AnyView, AppContext, BorrowWindow, Bounds, Component, DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, - StyleRefinement, View, ViewContext, + StyleRefinement, Task, View, ViewContext, }; use collections::HashMap; use derive_more::{Deref, DerefMut}; @@ -627,50 +627,48 @@ pub trait ElementInteraction: 'static { let active_tooltip = element_state.active_tooltip.clone(); let pending_mouse_down = element_state.pending_mouse_down.clone(); - cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| { + cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } let is_hovered = bounds.contains_point(&event.position) && pending_mouse_down.lock().is_none(); - let mut tooltip_lock = active_tooltip.lock(); - - if is_hovered { - if tooltip_lock.is_none() { - *tooltip_lock = Some(ActiveTooltip { - view: tooltip_builder(view_state, cx), - visible: false, - coordinates: event.position, - }); + if !is_hovered { + active_tooltip.lock().take(); + return; + } + if active_tooltip.lock().is_none() { + let task = cx.spawn({ let active_tooltip = active_tooltip.clone(); - cx.spawn(move |view, mut cx| async move { - cx.background_executor().timer(TOOLTIP_DELAY).await; + let tooltip_builder = tooltip_builder.clone(); - view.update(&mut cx, |_, cx| { - if let Some(active_tooltip) = active_tooltip.lock().as_mut() { - active_tooltip.visible = true; - active_tooltip.coordinates = - cx.mouse_position() + TOOLTIP_OFFSET; - } + move |view, mut cx| async move { + cx.background_executor().timer(TOOLTIP_DELAY).await; + view.update(&mut cx, move |view_state, cx| { + active_tooltip.lock().replace(ActiveTooltip { + waiting: None, + tooltip: Some(AnyTooltip { + view: tooltip_builder(view_state, cx), + cursor_offset: cx.mouse_position() + TOOLTIP_OFFSET, + }), + }); cx.notify(); }) - .ok() - }) - .detach(); - } - } else { - tooltip_lock.take(); + .ok(); + } + }); + active_tooltip.lock().replace(ActiveTooltip { + waiting: Some(task), + tooltip: None, + }); } }); if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() { - if active_tooltip.visible { - cx.active_tooltip = Some(AnyTooltip { - view: active_tooltip.view.clone(), - cursor_offset: active_tooltip.coordinates, - }); + if active_tooltip.tooltip.is_some() { + cx.active_tooltip = active_tooltip.tooltip.clone() } } } @@ -866,9 +864,9 @@ pub struct InteractiveElementState { } struct ActiveTooltip { - view: AnyView, - visible: bool, - coordinates: Point, + #[allow(unused)] // used to drop the task + waiting: Option>, + tooltip: Option, } impl InteractiveElementState { diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index 0bc00a9be1120e80c2b840bc064ddf3ee584a1c0..c05214eea4e8d977ab85d875b341e1165a785b3a 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use gpui2::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext}; use theme2::ActiveTheme;