Move more tooltip logic into gpui2 & fix tooltip moving on paint
Co-Authored-By: Conrad Irwin <conrad@zed.dev>
This commit is contained in:
parent
3834e26f71
commit
4725cd2cd6
6 changed files with 61 additions and 54 deletions
|
@ -157,7 +157,7 @@ pub struct AppContext {
|
||||||
flushing_effects: bool,
|
flushing_effects: bool,
|
||||||
pending_updates: usize,
|
pending_updates: usize,
|
||||||
pub(crate) active_drag: Option<AnyDrag>,
|
pub(crate) active_drag: Option<AnyDrag>,
|
||||||
pub(crate) active_tooltip: Option<AnyView>,
|
pub(crate) active_tooltip: Option<AnyTooltip>,
|
||||||
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
||||||
pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>,
|
pub(crate) frame_consumers: HashMap<DisplayId, Task<()>>,
|
||||||
pub(crate) background_executor: BackgroundExecutor,
|
pub(crate) background_executor: BackgroundExecutor,
|
||||||
|
@ -898,3 +898,8 @@ pub(crate) struct AnyDrag {
|
||||||
pub view: AnyView,
|
pub view: AnyView,
|
||||||
pub cursor_offset: Point<Pixels>,
|
pub cursor_offset: Point<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct AnyTooltip {
|
||||||
|
pub view: AnyView,
|
||||||
|
pub cursor_offset: Point<Pixels>,
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn point<T: Clone + Debug + Default>(x: T, y: T) -> Point<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone + Debug + Default> Point<T> {
|
impl<T: Clone + Debug + Default> Point<T> {
|
||||||
pub fn new(x: T, y: T) -> Self {
|
pub const fn new(x: T, y: T) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
div, point, px, Action, AnyDrag, AnyView, AppContext, BorrowWindow, Bounds, Component,
|
div, point, px, Action, AnyDrag, AnyTooltip, AnyView, AppContext, BorrowWindow, Bounds,
|
||||||
DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke,
|
Component, DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch,
|
||||||
Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, StyleRefinement, View,
|
Keystroke, Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style,
|
||||||
ViewContext,
|
StyleRefinement, View, ViewContext,
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -17,9 +17,12 @@ use std::{
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DRAG_THRESHOLD: f64 = 2.;
|
const DRAG_THRESHOLD: f64 = 2.;
|
||||||
|
const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
|
||||||
|
const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
|
||||||
|
|
||||||
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
||||||
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V>;
|
fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V>;
|
||||||
|
@ -621,7 +624,7 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(tooltip_builder) = stateful.tooltip_builder.take() {
|
if let Some(tooltip_builder) = stateful.tooltip_builder.take() {
|
||||||
let tooltip_view = element_state.tooltip_view.clone();
|
let active_tooltip = element_state.active_tooltip.clone();
|
||||||
let pending_mouse_down = element_state.pending_mouse_down.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 |view_state, event: &MouseMoveEvent, phase, cx| {
|
||||||
|
@ -631,19 +634,44 @@ pub trait ElementInteraction<V: 'static>: 'static {
|
||||||
|
|
||||||
let is_hovered = bounds.contains_point(&event.position)
|
let is_hovered = bounds.contains_point(&event.position)
|
||||||
&& pending_mouse_down.lock().is_none();
|
&& pending_mouse_down.lock().is_none();
|
||||||
let mut tooltip_view = tooltip_view.lock();
|
let mut tooltip_lock = active_tooltip.lock();
|
||||||
|
|
||||||
if is_hovered {
|
if is_hovered {
|
||||||
if tooltip_view.is_none() {
|
if tooltip_lock.is_none() {
|
||||||
*tooltip_view = Some(tooltip_builder(view_state, cx));
|
*tooltip_lock = Some(ActiveTooltip {
|
||||||
|
view: tooltip_builder(view_state, cx),
|
||||||
|
visible: false,
|
||||||
|
coordinates: event.position,
|
||||||
|
});
|
||||||
|
|
||||||
|
let active_tooltip = active_tooltip.clone();
|
||||||
|
cx.spawn(move |view, mut cx| async move {
|
||||||
|
cx.background_executor().timer(TOOLTIP_DELAY).await;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
cx.notify();
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tooltip_view.take();
|
tooltip_lock.take();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(active_tooltip) = element_state.tooltip_view.lock().as_ref() {
|
if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() {
|
||||||
cx.active_tooltip = Some(active_tooltip.clone());
|
if active_tooltip.visible {
|
||||||
|
cx.active_tooltip = Some(AnyTooltip {
|
||||||
|
view: active_tooltip.view.clone(),
|
||||||
|
cursor_offset: active_tooltip.coordinates,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +862,13 @@ pub struct InteractiveElementState {
|
||||||
hover_state: Arc<Mutex<bool>>,
|
hover_state: Arc<Mutex<bool>>,
|
||||||
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||||
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||||
tooltip_view: Arc<Mutex<Option<AnyView>>>,
|
active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ActiveTooltip {
|
||||||
|
view: AnyView,
|
||||||
|
visible: bool,
|
||||||
|
coordinates: Point<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InteractiveElementState {
|
impl InteractiveElementState {
|
||||||
|
|
|
@ -989,14 +989,11 @@ impl<'a> WindowContext<'a> {
|
||||||
});
|
});
|
||||||
} else if let Some(active_tooltip) = self.app.active_tooltip.take() {
|
} else if let Some(active_tooltip) = self.app.active_tooltip.take() {
|
||||||
self.stack(1, |cx| {
|
self.stack(1, |cx| {
|
||||||
cx.with_element_offset(
|
cx.with_element_offset(Some(active_tooltip.cursor_offset), |cx| {
|
||||||
Some(cx.mouse_position() + Point::new(px(8.0), px(8.0))),
|
let available_space =
|
||||||
|cx| {
|
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||||
let available_space =
|
active_tooltip.view.draw(available_space, cx);
|
||||||
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
});
|
||||||
active_tooltip.draw(available_space, cx);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,16 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use gpui2::{
|
use gpui2::{div, px, Div, ParentElement, Render, SharedString, Styled, ViewContext};
|
||||||
div, px, Component, Div, ParentElement, Render, SharedString, Styled, View, ViewContext,
|
|
||||||
VisualContext, WindowContext,
|
|
||||||
};
|
|
||||||
use theme2::ActiveTheme;
|
use theme2::ActiveTheme;
|
||||||
|
|
||||||
const DELAY: Duration = Duration::from_millis(500);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TextTooltip {
|
pub struct TextTooltip {
|
||||||
title: SharedString,
|
title: SharedString,
|
||||||
visible: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextTooltip {
|
impl TextTooltip {
|
||||||
pub fn new(str: SharedString) -> Self {
|
pub fn new(str: SharedString) -> Self {
|
||||||
Self {
|
Self { title: str }
|
||||||
title: str,
|
|
||||||
visible: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_view(str: SharedString, cx: &mut WindowContext) -> View<Self> {
|
|
||||||
let view = cx.build_view(|cx| TextTooltip::new(str));
|
|
||||||
|
|
||||||
let handle = view.downgrade();
|
|
||||||
cx.spawn(|mut cx| async move {
|
|
||||||
cx.background_executor().timer(DELAY).await;
|
|
||||||
|
|
||||||
handle
|
|
||||||
.update(&mut cx, |this, cx| {
|
|
||||||
this.visible = true;
|
|
||||||
cx.notify();
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
view
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +20,6 @@ impl Render for TextTooltip {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
div()
|
div()
|
||||||
.when(!self.visible, |this| this.invisible())
|
|
||||||
.bg(theme.colors().background)
|
.bg(theme.colors().background)
|
||||||
.rounded(px(8.))
|
.rounded(px(8.))
|
||||||
.border()
|
.border()
|
||||||
|
|
|
@ -1399,7 +1399,7 @@ impl Pane {
|
||||||
.id(item.id())
|
.id(item.id())
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
.when_some(item.tab_tooltip_text(cx), |div, text| {
|
.when_some(item.tab_tooltip_text(cx), |div, text| {
|
||||||
div.tooltip(move |_, cx| TextTooltip::build_view(text.clone(), cx))
|
div.tooltip(move |_, cx| cx.build_view(|cx| TextTooltip::new(text.clone())))
|
||||||
})
|
})
|
||||||
// .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
|
// .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
|
||||||
// .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
|
// .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue