1use gpui::{overlay, Action, AnyView, Overlay, Render, RenderOnce, VisualContext};
2use settings2::Settings;
3use theme2::{ActiveTheme, ThemeSettings};
4
5use crate::prelude::*;
6use crate::{h_stack, v_stack, Color, KeyBinding, Label, LabelSize, StyledExt};
7
8pub struct Tooltip {
9 title: SharedString,
10 meta: Option<SharedString>,
11 key_binding: Option<KeyBinding>,
12}
13
14impl Tooltip {
15 pub fn text(title: impl Into<SharedString>, cx: &mut WindowContext) -> AnyView {
16 cx.build_view(|cx| Self {
17 title: title.into(),
18 meta: None,
19 key_binding: None,
20 })
21 .into()
22 }
23
24 pub fn for_action(
25 title: impl Into<SharedString>,
26 action: &dyn Action,
27 cx: &mut WindowContext,
28 ) -> AnyView {
29 cx.build_view(|cx| Self {
30 title: title.into(),
31 meta: None,
32 key_binding: KeyBinding::for_action(action, cx),
33 })
34 .into()
35 }
36
37 pub fn with_meta(
38 title: impl Into<SharedString>,
39 action: Option<&dyn Action>,
40 meta: impl Into<SharedString>,
41 cx: &mut WindowContext,
42 ) -> AnyView {
43 cx.build_view(|cx| Self {
44 title: title.into(),
45 meta: Some(meta.into()),
46 key_binding: action.and_then(|action| KeyBinding::for_action(action, cx)),
47 })
48 .into()
49 }
50
51 pub fn new(title: impl Into<SharedString>) -> Self {
52 Self {
53 title: title.into(),
54 meta: None,
55 key_binding: None,
56 }
57 }
58
59 pub fn meta(mut self, meta: impl Into<SharedString>) -> Self {
60 self.meta = Some(meta.into());
61 self
62 }
63
64 pub fn key_binding(mut self, key_binding: impl Into<Option<KeyBinding>>) -> Self {
65 self.key_binding = key_binding.into();
66 self
67 }
68}
69
70impl Render for Tooltip {
71 type Element = Overlay;
72
73 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
74 let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();
75 overlay().child(
76 // padding to avoid mouse cursor
77 div().pl_2().pt_2p5().child(
78 v_stack()
79 .elevation_2(cx)
80 .font(ui_font)
81 .text_ui_sm()
82 .text_color(cx.theme().colors().text)
83 .py_1()
84 .px_2()
85 .child(
86 h_stack()
87 .child(self.title.clone())
88 .when_some(self.key_binding.clone(), |this, key_binding| {
89 this.justify_between().child(key_binding)
90 }),
91 )
92 .when_some(self.meta.clone(), |this, meta| {
93 this.child(Label::new(meta).size(LabelSize::Small).color(Color::Muted))
94 }),
95 ),
96 )
97 }
98}