122 lines
3.9 KiB
Rust
122 lines
3.9 KiB
Rust
use gpui::{
|
|
div, prelude::FluentBuilder, px, Action, AnyElement, AnyView, App, AppContext, Context,
|
|
IntoElement, ParentElement, Render, SharedString, StyleRefinement, Styled, Window,
|
|
};
|
|
|
|
use crate::{h_flex, text::Text, ActiveTheme, Kbd, StyledExt};
|
|
|
|
enum TooltipContext {
|
|
Text(Text),
|
|
Element(Box<dyn Fn(&mut Window, &mut App) -> AnyElement>),
|
|
}
|
|
|
|
pub struct Tooltip {
|
|
style: StyleRefinement,
|
|
content: TooltipContext,
|
|
key_binding: Option<Kbd>,
|
|
action: Option<(Box<dyn Action>, Option<SharedString>)>,
|
|
}
|
|
|
|
impl Tooltip {
|
|
/// Create a Tooltip with a text content.
|
|
pub fn new(text: impl Into<Text>) -> Self {
|
|
Self {
|
|
style: StyleRefinement::default(),
|
|
content: TooltipContext::Text(text.into()),
|
|
key_binding: None,
|
|
action: None,
|
|
}
|
|
}
|
|
|
|
/// Create a Tooltip with a custom element.
|
|
pub fn element<E, F>(builder: F) -> Self
|
|
where
|
|
E: IntoElement,
|
|
F: Fn(&mut Window, &mut App) -> E + 'static,
|
|
{
|
|
Self {
|
|
style: StyleRefinement::default(),
|
|
key_binding: None,
|
|
action: None,
|
|
content: TooltipContext::Element(Box::new(move |window, cx| {
|
|
builder(window, cx).into_any_element()
|
|
})),
|
|
}
|
|
}
|
|
|
|
/// Set Action to display key binding information for the tooltip if it exists.
|
|
pub fn action(mut self, action: &dyn Action, context: Option<&str>) -> Self {
|
|
self.action = Some((action.boxed_clone(), context.map(SharedString::new)));
|
|
self
|
|
}
|
|
|
|
/// Set KeyBinding information for the tooltip.
|
|
pub fn key_binding(mut self, key_binding: Option<Kbd>) -> Self {
|
|
self.key_binding = key_binding;
|
|
self
|
|
}
|
|
|
|
/// Build the tooltip and return it as an `AnyView`.
|
|
pub fn build(self, _: &mut Window, cx: &mut App) -> AnyView {
|
|
cx.new(|_| self).into()
|
|
}
|
|
}
|
|
|
|
impl FluentBuilder for Tooltip {}
|
|
impl Styled for Tooltip {
|
|
fn style(&mut self) -> &mut StyleRefinement {
|
|
&mut self.style
|
|
}
|
|
}
|
|
impl Render for Tooltip {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let key_binding = if let Some(key_binding) = &self.key_binding {
|
|
Some(key_binding.clone())
|
|
} else {
|
|
if let Some((action, context)) = &self.action {
|
|
Kbd::binding_for_action(
|
|
action.as_ref(),
|
|
context.as_ref().map(|s| s.as_ref()),
|
|
window,
|
|
)
|
|
} else {
|
|
None
|
|
}
|
|
};
|
|
|
|
div().child(
|
|
// Wrap in a child, to ensure the left margin is applied to the tooltip
|
|
h_flex()
|
|
.font_family(".SystemUIFont")
|
|
.m_3()
|
|
.bg(cx.theme().popover)
|
|
.text_color(cx.theme().popover_foreground)
|
|
.bg(cx.theme().popover)
|
|
.border_1()
|
|
.border_color(cx.theme().border)
|
|
.shadow_md()
|
|
.rounded(px(6.))
|
|
.justify_between()
|
|
.py_0p5()
|
|
.px_2()
|
|
.text_sm()
|
|
.gap_3()
|
|
.refine_style(&self.style)
|
|
.map(|this| {
|
|
this.child(div().map(|this| match self.content {
|
|
TooltipContext::Text(ref text) => this.child(text.clone()),
|
|
TooltipContext::Element(ref builder) => this.child(builder(window, cx)),
|
|
}))
|
|
})
|
|
.when_some(key_binding, |this, kbd| {
|
|
this.child(
|
|
div()
|
|
.text_xs()
|
|
.flex_shrink_0()
|
|
.text_color(cx.theme().muted_foreground)
|
|
.child(kbd.appearance(false)),
|
|
)
|
|
}),
|
|
)
|
|
}
|
|
}
|