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}