1use std::sync::Arc;
2
3use gpui::{rems, 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 icon_color = match (self.state, self.color) {
70 (InteractionState::Disabled, _) => IconColor::Disabled,
71 _ => self.color,
72 };
73
74 let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
75 ButtonVariant::Filled => (
76 cx.theme().colors().element_background,
77 cx.theme().colors().element_hover,
78 cx.theme().colors().element_active,
79 ),
80 ButtonVariant::Ghost => (
81 cx.theme().colors().ghost_element_background,
82 cx.theme().colors().ghost_element_hover,
83 cx.theme().colors().ghost_element_active,
84 ),
85 };
86
87 let mut button = h_stack()
88 .id(self.id.clone())
89 .justify_center()
90 .rounded_md()
91 .py(rems(0.21875))
92 .px(rems(0.375))
93 .bg(bg_color)
94 .hover(|style| style.bg(bg_hover_color))
95 .active(|style| style.bg(bg_active_color))
96 .child(IconElement::new(self.icon).color(icon_color));
97
98 if let Some(click_handler) = self.handlers.click.clone() {
99 button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| {
100 click_handler(state, cx);
101 });
102 }
103
104 button
105 }
106}