From cc028cca784b6b6fc82685c7559adce4dfd9a1c6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 2 Jun 2022 09:12:50 +0200 Subject: [PATCH] Simplify usage of tooltip Now you simply specify a text, an action and a style and GPUI will take of rendering it properly. This is simpler compared to always providing a custom element and should make tooltip more consistent across the UI. --- crates/diagnostics/src/diagnostics.rs | 23 +------ crates/gpui/src/elements.rs | 8 ++- crates/gpui/src/elements/tooltip.rs | 89 ++++++++++++++++++++++++--- crates/theme/src/theme.rs | 4 +- styles/src/styleTree/tooltip.ts | 10 ++- 5 files changed, 99 insertions(+), 35 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index a043e4eae3296df2b6f26d86d799b58df671a86b..501ac0fca932f101f3179c173eb231068e41b647 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -686,26 +686,9 @@ fn diagnostic_header_renderer(entry: DiagnosticEntry, path: ProjectPath) }) .with_tooltip( entry.diagnostic.group_id, - Flex::row() - .with_child( - Label::new( - "Jump to diagnostic (".to_string(), - tooltip_style.text.clone(), - ) - .boxed(), - ) - .with_child( - KeystrokeLabel::new( - Box::new(editor::OpenExcerpts), - Default::default(), - tooltip_style.text.clone(), - ) - .boxed(), - ) - .with_child(Label::new(")".to_string(), tooltip_style.text).boxed()) - .contained() - .with_style(tooltip_style.container) - .boxed(), + "Jump to diagnostic".to_string(), + Some(Box::new(editor::OpenExcerpts)), + tooltip_style, cx, ) .aligned() diff --git a/crates/gpui/src/elements.rs b/crates/gpui/src/elements.rs index 6b0e2a1af639d1c33ed605db5fd5c0b5b39bac7f..d2d254d93eb1d7da3949d60bbfdc011b7fa65293 100644 --- a/crates/gpui/src/elements.rs +++ b/crates/gpui/src/elements.rs @@ -31,7 +31,7 @@ use crate::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json, DebugContext, Event, EventContext, LayoutContext, PaintContext, RenderContext, + json, Action, DebugContext, Event, EventContext, LayoutContext, PaintContext, RenderContext, SizeConstraint, View, }; use core::panic; @@ -160,13 +160,15 @@ pub trait Element { fn with_tooltip( self, id: usize, - tooltip: ElementBox, + text: String, + action: Option>, + style: TooltipStyle, cx: &mut RenderContext, ) -> Tooltip where Self: 'static + Sized, { - Tooltip::new(id, self.boxed(), tooltip, cx) + Tooltip::new(id, text, action, style, self.boxed(), cx) } } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 9fc5894c63e66514e5843359299594a453eff0dd..9ed0f5cba6ac86f56c2ccee040608a461688fbec 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -1,14 +1,19 @@ -use std::{ - cell::{Cell, RefCell}, - rc::Rc, - time::Duration, +use super::{ + ContainerStyle, Element, ElementBox, Flex, KeystrokeLabel, MouseEventHandler, ParentElement, + Text, }; - -use super::{Element, ElementBox, MouseEventHandler}; use crate::{ + fonts::TextStyle, geometry::{rect::RectF, vector::Vector2F}, json::json, - ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, Task, View, + Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint, + Task, View, +}; +use serde::Deserialize; +use std::{ + cell::{Cell, RefCell}, + rc::Rc, + time::Duration, }; const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500); @@ -26,17 +31,53 @@ struct TooltipState { debounce: RefCell>>, } +#[derive(Clone, Deserialize, Default)] +pub struct TooltipStyle { + #[serde(flatten)] + container: ContainerStyle, + text: TextStyle, + keystroke: KeystrokeStyle, + max_text_width: f32, +} + +#[derive(Clone, Deserialize, Default)] +pub struct KeystrokeStyle { + #[serde(flatten)] + container: ContainerStyle, + #[serde(flatten)] + text: TextStyle, +} + impl Tooltip { pub fn new( id: usize, + text: String, + action: Option>, + style: TooltipStyle, child: ElementBox, - tooltip: ElementBox, cx: &mut RenderContext, ) -> Self { let state_handle = cx.element_state::>(id); let state = state_handle.read(cx).clone(); let tooltip = if state.visible.get() { - Some(tooltip) + let mut collapsed_tooltip = Self::render_tooltip( + text.clone(), + style.clone(), + action.as_ref().map(|a| a.boxed_clone()), + true, + ) + .boxed(); + Some( + Self::render_tooltip(text, style, action, false) + .constrained() + .dynamically(move |constraint, cx| { + SizeConstraint::strict_along( + Axis::Vertical, + collapsed_tooltip.layout(constraint, cx).y(), + ) + }) + .boxed(), + ) } else { None }; @@ -73,6 +114,36 @@ impl Tooltip { state: state_handle, } } + + fn render_tooltip( + text: String, + style: TooltipStyle, + action: Option>, + measure: bool, + ) -> impl Element { + Flex::row() + .with_child({ + let text = Text::new(text, style.text) + .constrained() + .with_max_width(style.max_text_width); + if measure { + text.flex(1., false).boxed() + } else { + text.flex(1., false).aligned().boxed() + } + }) + .with_children(action.map(|action| { + let keystroke_label = + KeystrokeLabel::new(action, style.keystroke.container, style.keystroke.text); + if measure { + keystroke_label.boxed() + } else { + keystroke_label.aligned().boxed() + } + })) + .contained() + .with_style(style.container) + } } impl Element for Tooltip { diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 9d3bb59bce2ebf4f2434f5b85b170b88543e0277..363912763347d6299b0d992d6643189ef25c021c 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -2,7 +2,7 @@ mod theme_registry; use gpui::{ color::Color, - elements::{ContainerStyle, ImageStyle, LabelStyle}, + elements::{ContainerStyle, ImageStyle, LabelStyle, TooltipStyle}, fonts::{HighlightStyle, TextStyle}, Border, MouseState, }; @@ -31,7 +31,7 @@ pub struct Theme { pub project_diagnostics: ProjectDiagnostics, pub breadcrumbs: ContainedText, pub contact_notification: ContactNotification, - pub tooltip: ContainedText, + pub tooltip: TooltipStyle, } #[derive(Deserialize, Default)] diff --git a/styles/src/styleTree/tooltip.ts b/styles/src/styleTree/tooltip.ts index 228d510ddd20166a0aa49f6e0dec97c2a5cf2345..bfceae168eaeb3e09997f4a6e6d064422dc04b21 100644 --- a/styles/src/styleTree/tooltip.ts +++ b/styles/src/styleTree/tooltip.ts @@ -9,6 +9,14 @@ export default function tooltip(theme: Theme) { margin: { top: 6, left: 6 }, shadow: shadow(theme), cornerRadius: 6, - ...text(theme, "sans", "secondary", { size: "xs", weight: "bold" }) + text: text(theme, "sans", "secondary", { size: "xs", weight: "bold" }), + keystroke: { + background: backgroundColor(theme, "on500"), + cornerRadius: 4, + margin: { left: 6 }, + padding: { left: 3, right: 3 }, + ...text(theme, "mono", "muted", { size: "xs", weight: "bold" }) + }, + maxTextWidth: 200, } } \ No newline at end of file