icon_button.rs

 1use std::marker::PhantomData;
 2use std::sync::Arc;
 3
 4use gpui3::{Interactive, MouseButton};
 5
 6use crate::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
72        let icon_color = match (self.state, self.color) {
73            (InteractionState::Disabled, _) => IconColor::Disabled,
74            _ => self.color,
75        };
76
77        let mut div = div();
78        if self.variant == ButtonVariant::Filled {
79            div = div.bg(theme.highest.on.default.background);
80        }
81
82        if let Some(click_handler) = self.handlers.click.clone() {
83            div = div.on_mouse_down(MouseButton::Left, move |state, event, cx| {
84                click_handler(state, cx);
85            });
86        }
87
88        div.w_7()
89            .h_6()
90            .flex()
91            .items_center()
92            .justify_center()
93            .rounded_md()
94            .hover(|style| style.bg(theme.highest.base.hovered.background))
95            // .active()
96            // .fill(theme.highest.base.pressed.background)
97            .child(IconElement::new(self.icon).color(icon_color))
98    }
99}