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