use gpui::{
AnyView, App, AppContext as _, ClickEvent, ClipboardItem, Div, ElementId, InteractiveElement,
IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled,
Window, div, prelude::FluentBuilder as _, px, rgb,
};
use icons::IconName;
#[derive(IntoElement)]
pub struct Checkbox {
id: ElementId,
checked: bool,
disabled: bool,
on_click: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
}
impl Checkbox {
pub fn new(id: impl Into<ElementId>, checked: bool) -> Self {
Self {
id: id.into(),
checked,
disabled: false,
on_click: None,
}
}
pub fn disabled(mut self, disabled: bool) -> Self {
self.disabled = disabled;
self
}
pub fn on_click(mut self, on_click: impl Fn(&bool, &mut Window, &mut App) + 'static) -> Self {
self.on_click = Some(Box::new(on_click));
self
}
}
impl RenderOnce for Checkbox {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let checked = self.checked;
let disabled = self.disabled;
let on_click = self.on_click;
div()
.id(self.id)
.size(px(14.))
.flex()
.items_center()
.justify_center()
.rounded_xs()
.border_1()
.border_color(rgb(0x4A5568))
.when(checked, |this| this.bg(rgb(0x3B82F6)))
.when(!disabled, |this| this.cursor_pointer())
.when_some(on_click.filter(|_| !disabled), |this, on_click| {
this.on_click(move |_: &ClickEvent, window, cx| {
on_click(&!checked, window, cx);
})
})
.when(checked, |this| {
this.child(
div()
.size(px(8.))
.text_color(rgb(0xFFFFFF))
.child(SharedString::from("\u{2713}")),
)
})
}
}
#[derive(IntoElement)]
pub struct CopyButton {
id: ElementId,
text: SharedString,
icon: IconName,
}
impl CopyButton {
pub fn new(id: impl Into<ElementId>, text: impl Into<SharedString>) -> Self {
Self {
id: id.into(),
text: text.into(),
icon: IconName::Copy,
}
}
pub fn icon(mut self, icon: IconName) -> Self {
self.icon = icon;
self
}
}
impl RenderOnce for CopyButton {
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
let text = self.text;
div()
.id(self.id)
.flex()
.items_center()
.justify_center()
.size(px(20.))
.rounded_xs()
.cursor_pointer()
.hover(|this| this.bg(rgb(0x2D3748)))
.child(icon_svg(self.icon, px(14.), rgb(0xA0AEC0)))
.on_click(move |_: &ClickEvent, _window, cx| {
cx.write_to_clipboard(ClipboardItem::new_string(text.to_string()));
})
}
}
pub fn icon_svg(
icon: IconName,
size: impl Into<gpui::Pixels>,
color: impl Into<gpui::Hsla>,
) -> gpui::Svg {
gpui::svg()
.path(icon.path())
.size(size.into())
.text_color(color.into())
}
struct SimpleTooltip {
text: SharedString,
}
impl gpui::Render for SimpleTooltip {
fn render(&mut self, _window: &mut Window, _cx: &mut gpui::Context<Self>) -> impl IntoElement {
div()
.rounded_xs()
.bg(rgb(0x1A202C))
.text_color(rgb(0xE2E8F0))
.px_2()
.py_1()
.text_sm()
.child(self.text.clone())
}
}
pub fn simple_tooltip(text: impl Into<SharedString>) -> impl Fn(&mut Window, &mut App) -> AnyView {
let text = text.into();
move |_window, cx| cx.new(|_| SimpleTooltip { text: text.clone() }).into()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScrollAxes {
Vertical,
Horizontal,
Both,
}
pub trait WithScrollbar {
fn with_scrollbar(self, handle: &gpui::ScrollHandle, axes: ScrollAxes) -> Self;
}
impl WithScrollbar for gpui::Stateful<Div> {
fn with_scrollbar(self, handle: &gpui::ScrollHandle, axes: ScrollAxes) -> Self {
let this = match axes {
ScrollAxes::Vertical => self.overflow_y_scroll(),
ScrollAxes::Horizontal => self.overflow_x_scroll(),
ScrollAxes::Both => self.overflow_scroll(),
};
this.track_scroll(handle)
}
}