mention_crease.rs

  1use std::time::Duration;
  2
  3use gpui::{Animation, AnimationExt, AnyView, IntoElement, Window, pulsating_between};
  4use settings::Settings;
  5use theme::ThemeSettings;
  6use ui::{ButtonLike, TintColor, Tooltip, prelude::*};
  7
  8#[derive(IntoElement)]
  9pub struct MentionCrease {
 10    id: ElementId,
 11    icon: SharedString,
 12    label: SharedString,
 13    is_toggled: bool,
 14    is_loading: bool,
 15    tooltip: Option<SharedString>,
 16    image_preview: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
 17}
 18
 19impl MentionCrease {
 20    pub fn new(
 21        id: impl Into<ElementId>,
 22        icon: impl Into<SharedString>,
 23        label: impl Into<SharedString>,
 24    ) -> Self {
 25        Self {
 26            id: id.into(),
 27            icon: icon.into(),
 28            label: label.into(),
 29            is_toggled: false,
 30            is_loading: false,
 31            tooltip: None,
 32            image_preview: None,
 33        }
 34    }
 35
 36    pub fn is_toggled(mut self, is_toggled: bool) -> Self {
 37        self.is_toggled = is_toggled;
 38        self
 39    }
 40
 41    pub fn is_loading(mut self, is_loading: bool) -> Self {
 42        self.is_loading = is_loading;
 43        self
 44    }
 45
 46    pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
 47        self.tooltip = Some(tooltip.into());
 48        self
 49    }
 50
 51    pub fn image_preview(
 52        mut self,
 53        builder: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
 54    ) -> Self {
 55        self.image_preview = Some(Box::new(builder));
 56        self
 57    }
 58}
 59
 60impl RenderOnce for MentionCrease {
 61    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
 62        let settings = ThemeSettings::get_global(cx);
 63        let font_size = settings.agent_buffer_font_size(cx);
 64        let buffer_font = settings.buffer_font.clone();
 65        let is_loading = self.is_loading;
 66        let tooltip = self.tooltip;
 67        let image_preview = self.image_preview;
 68
 69        let button_height = DefiniteLength::Absolute(AbsoluteLength::Pixels(
 70            px(window.line_height().into()) - px(1.),
 71        ));
 72
 73        ButtonLike::new(self.id)
 74            .style(ButtonStyle::Outlined)
 75            .size(ButtonSize::Compact)
 76            .height(button_height)
 77            .selected_style(ButtonStyle::Tinted(TintColor::Accent))
 78            .toggle_state(self.is_toggled)
 79            .child(
 80                h_flex()
 81                    .pb_px()
 82                    .gap_1()
 83                    .font(buffer_font)
 84                    .text_size(font_size)
 85                    .child(
 86                        Icon::from_path(self.icon.clone())
 87                            .size(IconSize::XSmall)
 88                            .color(Color::Muted),
 89                    )
 90                    .child(self.label.clone())
 91                    .map(|this| {
 92                        if is_loading {
 93                            this.with_animation(
 94                                "loading-context-crease",
 95                                Animation::new(Duration::from_secs(2))
 96                                    .repeat()
 97                                    .with_easing(pulsating_between(0.4, 0.8)),
 98                                |label, delta| label.opacity(delta),
 99                            )
100                            .into_any()
101                        } else {
102                            this.into_any()
103                        }
104                    }),
105            )
106            .map(|button| {
107                if let Some(image_preview) = image_preview {
108                    button.hoverable_tooltip(image_preview)
109                } else {
110                    button.when_some(tooltip, |this, tooltip_text| {
111                        this.tooltip(Tooltip::text(tooltip_text))
112                    })
113                }
114            })
115    }
116}