Skip to main content

guise/
actionicon.rs

1//! `ActionIcon` — a square icon-only button.
2
3use 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/// A compact, square icon button. The Mantine `ActionIcon`.
11#[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}