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(
61 mut self,
62 handler: impl 'static + Fn(&mut V, &mut ViewContext<V>) + Send + Sync,
63 ) -> Self {
64 self.handlers.click = Some(Arc::new(handler));
65 self
66 }
67
68 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
69 let theme = theme(cx);
70
71 let icon_color = match (self.state, self.color) {
72 (InteractionState::Disabled, _) => IconColor::Disabled,
73 _ => self.color,
74 };
75
76 let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
77 ButtonVariant::Filled => (
78 theme.filled_element,
79 theme.filled_element_hover,
80 theme.filled_element_active,
81 ),
82 ButtonVariant::Ghost => (
83 theme.ghost_element,
84 theme.ghost_element_hover,
85 theme.ghost_element_active,
86 ),
87 };
88
89 let mut button = h_stack()
90 .id(self.id.clone())
91 .justify_center()
92 .rounded_md()
93 .py(ui_size(cx, 0.25))
94 .px(ui_size(cx, 6. / 14.))
95 .bg(bg_color)
96 .hover(|style| style.bg(bg_hover_color))
97 .active(|style| style.bg(bg_active_color))
98 .child(IconElement::new(self.icon).color(icon_color));
99
100 if let Some(click_handler) = self.handlers.click.clone() {
101 button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
102 click_handler(state, cx);
103 });
104 }
105
106 button
107 }
108}