icon_button.rs

 1use std::marker::PhantomData;
 2use std::sync::Arc;
 3
 4use gpui3::{MouseButton, StatelesslyInteractive};
 5
 6use crate::{h_stack, prelude::*};
 7use crate::{theme, ClickHandler, Icon, IconColor, IconElement};
 8
 9struct IconButtonHandlers<S: 'static + Send + Sync> {
10    click: Option<ClickHandler<S>>,
11}
12
13impl<S: 'static + Send + Sync> Default for IconButtonHandlers<S> {
14    fn default() -> Self {
15        Self { click: None }
16    }
17}
18
19#[derive(Element)]
20pub struct IconButton<S: 'static + Send + Sync> {
21    state_type: PhantomData<S>,
22    icon: Icon,
23    color: IconColor,
24    variant: ButtonVariant,
25    state: InteractionState,
26    handlers: IconButtonHandlers<S>,
27}
28
29impl<S: 'static + Send + Sync> IconButton<S> {
30    pub fn new(icon: Icon) -> Self {
31        Self {
32            state_type: PhantomData,
33            icon,
34            color: IconColor::default(),
35            variant: ButtonVariant::default(),
36            state: InteractionState::default(),
37            handlers: IconButtonHandlers::default(),
38        }
39    }
40
41    pub fn icon(mut self, icon: Icon) -> Self {
42        self.icon = icon;
43        self
44    }
45
46    pub fn color(mut self, color: IconColor) -> Self {
47        self.color = color;
48        self
49    }
50
51    pub fn variant(mut self, variant: ButtonVariant) -> Self {
52        self.variant = variant;
53        self
54    }
55
56    pub fn state(mut self, state: InteractionState) -> Self {
57        self.state = state;
58        self
59    }
60
61    pub fn on_click(
62        mut self,
63        handler: impl Fn(&mut S, &mut ViewContext<S>) + 'static + Send + Sync,
64    ) -> Self {
65        self.handlers.click = Some(Arc::new(handler));
66        self
67    }
68
69    fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
70        let theme = theme(cx);
71        let color = ThemeColor::new(cx);
72
73        let icon_color = match (self.state, self.color) {
74            (InteractionState::Disabled, _) => IconColor::Disabled,
75            _ => self.color,
76        };
77
78        let mut button = h_stack()
79            .justify_center()
80            .rounded_md()
81            .py(ui_size(cx, 0.25))
82            .px(ui_size(cx, 6. / 14.))
83            .when(self.variant == ButtonVariant::Filled, |this| {
84                this.bg(color.filled_element)
85            })
86            .hover(|style| style.bg(theme.highest.base.hovered.background))
87            .child(IconElement::new(self.icon).color(icon_color));
88
89        if let Some(click_handler) = self.handlers.click.clone() {
90            button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
91                click_handler(state, cx);
92            });
93        }
94
95        button
96    }
97}