use std::rc::Rc; use gpui::ClickEvent; use ui::{IconButtonShape, Tooltip, prelude::*}; use crate::context::{ContextKind, ContextSnapshot}; #[derive(IntoElement)] pub enum ContextPill { Added { context: ContextSnapshot, dupe_name: bool, focused: bool, on_click: Option>, on_remove: Option>, }, Suggested { name: SharedString, icon_path: Option, kind: ContextKind, focused: bool, on_click: Option>, }, } impl ContextPill { pub fn added( context: ContextSnapshot, dupe_name: bool, focused: bool, on_remove: Option>, ) -> Self { Self::Added { context, dupe_name, on_remove, focused, on_click: None, } } pub fn suggested( name: SharedString, icon_path: Option, kind: ContextKind, focused: bool, ) -> Self { Self::Suggested { name, icon_path, kind, focused, on_click: None, } } pub fn on_click(mut self, listener: Rc) -> Self { match &mut self { ContextPill::Added { on_click, .. } => { *on_click = Some(listener); } ContextPill::Suggested { on_click, .. } => { *on_click = Some(listener); } } self } pub fn id(&self) -> ElementId { match self { Self::Added { context, .. } => { ElementId::NamedInteger("context-pill".into(), context.id.0) } Self::Suggested { .. } => "suggested-context-pill".into(), } } pub fn icon(&self) -> Icon { match self { Self::Added { context, .. } => match &context.icon_path { Some(icon_path) => Icon::from_path(icon_path), None => Icon::new(context.kind.icon()), }, Self::Suggested { icon_path: Some(icon_path), .. } => Icon::from_path(icon_path), Self::Suggested { kind, icon_path: None, .. } => Icon::new(kind.icon()), } } } impl RenderOnce for ContextPill { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { let color = cx.theme().colors(); let base_pill = h_flex() .id(self.id()) .pl_1() .pb(px(1.)) .border_1() .rounded_sm() .gap_1() .child(self.icon().size(IconSize::XSmall).color(Color::Muted)); match &self { ContextPill::Added { context, dupe_name, on_remove, focused, on_click, } => base_pill .bg(color.element_background) .border_color(if *focused { color.border_focused } else { color.border.opacity(0.5) }) .pr(if on_remove.is_some() { px(2.) } else { px(4.) }) .child( h_flex() .id("context-data") .gap_1() .child( div().max_w_64().child( Label::new(context.name.clone()) .size(LabelSize::Small) .truncate(), ), ) .when_some(context.parent.as_ref(), |element, parent_name| { if *dupe_name { element.child( Label::new(parent_name.clone()) .size(LabelSize::XSmall) .color(Color::Muted), ) } else { element } }) .when_some(context.tooltip.clone(), |element, tooltip| { element.tooltip(Tooltip::text(tooltip.clone())) }), ) .when_some(on_remove.as_ref(), |element, on_remove| { element.child( IconButton::new(("remove", context.id.0), IconName::Close) .shape(IconButtonShape::Square) .icon_size(IconSize::XSmall) .tooltip(Tooltip::text("Remove Context")) .on_click({ let on_remove = on_remove.clone(); move |event, window, cx| on_remove(event, window, cx) }), ) }) .when_some(on_click.as_ref(), |element, on_click| { let on_click = on_click.clone(); element .cursor_pointer() .on_click(move |event, window, cx| on_click(event, window, cx)) }), ContextPill::Suggested { name, icon_path: _, kind, focused, on_click, } => base_pill .cursor_pointer() .pr_1() .when(*focused, |this| { this.bg(color.element_background.opacity(0.5)) }) .border_dashed() .border_color(if *focused { color.border_focused } else { color.border }) .hover(|style| style.bg(color.element_hover.opacity(0.5))) .child( div().px_0p5().max_w_64().child( Label::new(name.clone()) .size(LabelSize::Small) .color(Color::Muted) .truncate(), ), ) .child( Label::new(match kind { ContextKind::File => "Active Tab", ContextKind::Thread | ContextKind::Directory | ContextKind::FetchedUrl | ContextKind::Symbol => "Active", }) .size(LabelSize::XSmall) .color(Color::Muted), ) .child( Icon::new(IconName::Plus) .size(IconSize::XSmall) .into_any_element(), ) .tooltip(|window, cx| { Tooltip::with_meta("Suggested Context", None, "Click to add it", window, cx) }) .when_some(on_click.as_ref(), |element, on_click| { let on_click = on_click.clone(); element.on_click(move |event, window, cx| on_click(event, window, cx)) }), } } }