1use gpui::prelude::*;
4use gpui::{div, px, App, ClickEvent, ElementId, IntoElement, SharedString, Window};
5
6use crate::input::ClickHandler;
7use crate::style::{icon_size, surface, ColorValue, Variant};
8use crate::theme::{theme, ColorName, Size};
9
10#[derive(IntoElement)]
12pub struct ActionIcon {
13 id: ElementId,
14 icon: SharedString,
15 variant: Variant,
16 color: ColorValue,
17 size: Size,
18 radius: Option<Size>,
19 disabled: bool,
20 on_click: Option<ClickHandler>,
21}
22
23impl ActionIcon {
24 pub fn new(id: impl Into<ElementId>, icon: impl Into<SharedString>) -> Self {
25 ActionIcon {
26 id: id.into(),
27 icon: icon.into(),
28 variant: Variant::Subtle,
29 color: ColorValue::Named(ColorName::Gray),
30 size: Size::Md,
31 radius: None,
32 disabled: false,
33 on_click: None,
34 }
35 }
36
37 pub fn variant(mut self, variant: Variant) -> Self {
38 self.variant = variant;
39 self
40 }
41
42 pub fn color(mut self, color: impl Into<ColorValue>) -> Self {
43 self.color = color.into();
44 self
45 }
46
47 pub fn size(mut self, size: Size) -> Self {
48 self.size = size;
49 self
50 }
51
52 pub fn radius(mut self, radius: Size) -> Self {
53 self.radius = Some(radius);
54 self
55 }
56
57 pub fn disabled(mut self, disabled: bool) -> Self {
58 self.disabled = disabled;
59 self
60 }
61
62 pub fn on_click(
63 mut self,
64 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
65 ) -> Self {
66 self.on_click = Some(Box::new(handler));
67 self
68 }
69}
70
71impl RenderOnce for ActionIcon {
72 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
73 let t = theme(cx);
74 let s = surface(t, self.color, self.variant);
75 let dim = icon_size(self.size);
76 let radius = t.radius(self.radius.unwrap_or(t.default_radius));
77
78 let mut el = div()
79 .id(self.id)
80 .w(px(dim))
81 .h(px(dim))
82 .flex()
83 .items_center()
84 .justify_center()
85 .rounded(px(radius))
86 .bg(s.bg)
87 .text_color(s.fg)
88 .text_size(px(dim * 0.5))
89 .child(self.icon);
90 if let Some(border) = s.border {
91 el = el.border_1().border_color(border);
92 }
93
94 if self.disabled {
95 el.opacity(0.5)
96 } else {
97 let hover_bg = s.bg_hover;
98 el = el.hover(move |st| st.bg(hover_bg));
99 if let Some(handler) = self.on_click {
100 el = el.on_click(handler);
101 }
102 el
103 }
104 }
105}