1use crate::ActiveTheme;
3use gpui_kit::rems;
4use gpui_kit::{
5 App, AppContext, Context, Render, SharedString, StatefulInteractiveElement, Window, prelude::*,
6};
7use std::time::Duration;
8
9pub fn tooltip(text: impl Into<SharedString>, cx: &App) -> gpui_kit::base::Tooltip {
11 let t = cx.macos();
12 gpui_kit::base::Tooltip::new("macos-tooltip")
13 .max_w(rems(20.))
14 .px(rems(0.625))
15 .py(rems(0.375))
16 .border_1()
17 .rounded(rems(0.375))
18 .border_color(t.glass_border())
19 .bg(t.glass_fill())
20 .shadow(t.control_shadow())
21 .text_color(t.foreground)
22 .font_family(t.font.clone())
23 .text_size(rems(0.6875))
24 .child(text.into())
25}
26
27pub fn with_tooltip<T: StatefulInteractiveElement>(control: T, text: impl Into<SharedString>) -> T {
31 let text = text.into();
32 control
33 .tooltip_show_delay(Duration::from_millis(400))
34 .tooltip(move |_, cx| cx.new(|_| TooltipText(text.clone())).into())
35}
36
37struct TooltipText(SharedString);
38impl Render for TooltipText {
39 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
40 gpui_kit::div()
41 .debug_selector(|| "macos-tooltip-surface".into())
42 .child(tooltip(self.0.clone(), cx))
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use gpui_kit::px;
50 use gpui_kit::{Render, TestAppContext, point};
51 struct Harness;
52 impl Render for Harness {
53 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
54 gpui_kit::div().size_full().child(with_tooltip(
55 crate::button("favorite", "Favorite", crate::ButtonVariant::Secondary, cx),
56 "Add to favorites",
57 ))
58 }
59 }
60 #[gpui_kit::test]
61 fn tooltip_waits_for_hover_and_hides_on_pointer_leave(cx: &mut TestAppContext) {
62 cx.update(crate::init);
63 let (_, cx) = cx.add_window_view(|_, _| Harness);
64 cx.update(|window, cx| {
65 window.draw(cx).clear(cx);
66 });
67 cx.simulate_event(gpui_kit::MouseMoveEvent {
68 position: point(px(10.), px(10.)),
69 pressed_button: None,
70 modifiers: Default::default(),
71 });
72 cx.update(|window, cx| {
73 window.draw(cx).clear(cx);
74 });
75 cx.dispatcher.advance_clock(Duration::from_millis(399));
76 cx.run_until_parked();
77 cx.update(|window, cx| {
78 window.draw(cx).clear(cx);
79 });
80 assert!(cx.debug_bounds("macos-tooltip-surface").is_none());
81 cx.dispatcher.advance_clock(Duration::from_millis(1));
82 cx.run_until_parked();
83 cx.update(|window, cx| {
84 window.draw(cx).clear(cx);
85 });
86 assert!(cx.debug_bounds("macos-tooltip-surface").is_some());
87 cx.simulate_event(gpui_kit::MouseMoveEvent {
88 position: point(px(400.), px(400.)),
89 pressed_button: None,
90 modifiers: Default::default(),
91 });
92 cx.dispatcher.advance_clock(Duration::from_secs(1));
93 cx.run_until_parked();
94 cx.update(|window, cx| {
95 window.draw(cx).clear(cx);
96 });
97 assert!(cx.debug_bounds("macos-tooltip-surface").is_none());
98 }
99}