1use crate::{h_stack, prelude::*};
2use crate::{ClickHandler, Icon, IconColor, IconElement};
3use gpui::{prelude::*, rems, MouseButton};
4use std::sync::Arc;
5
6struct IconButtonHandlers<V: 'static> {
7 click: Option<ClickHandler<V>>,
8}
9
10impl<V: 'static> Default for IconButtonHandlers<V> {
11 fn default() -> Self {
12 Self { click: None }
13 }
14}
15
16#[derive(Component)]
17pub struct IconButton<V: 'static> {
18 id: ElementId,
19 icon: Icon,
20 color: IconColor,
21 variant: ButtonVariant,
22 state: InteractionState,
23 handlers: IconButtonHandlers<V>,
24}
25
26impl<V: 'static> IconButton<V> {
27 pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
28 Self {
29 id: id.into(),
30 icon,
31 color: IconColor::default(),
32 variant: ButtonVariant::default(),
33 state: InteractionState::default(),
34 handlers: IconButtonHandlers::default(),
35 }
36 }
37
38 pub fn icon(mut self, icon: Icon) -> Self {
39 self.icon = icon;
40 self
41 }
42
43 pub fn color(mut self, color: IconColor) -> Self {
44 self.color = color;
45 self
46 }
47
48 pub fn variant(mut self, variant: ButtonVariant) -> Self {
49 self.variant = variant;
50 self
51 }
52
53 pub fn state(mut self, state: InteractionState) -> Self {
54 self.state = state;
55 self
56 }
57
58 pub fn on_click(
59 mut self,
60 handler: impl 'static + Fn(&mut V, &mut ViewContext<V>) + Send + Sync,
61 ) -> Self {
62 self.handlers.click = Some(Arc::new(handler));
63 self
64 }
65
66 fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
67 let icon_color = match (self.state, self.color) {
68 (InteractionState::Disabled, _) => IconColor::Disabled,
69 _ => self.color,
70 };
71
72 let (bg_color, bg_hover_color, bg_active_color) = match self.variant {
73 ButtonVariant::Filled => (
74 cx.theme().colors().element_background,
75 cx.theme().colors().element_hover,
76 cx.theme().colors().element_active,
77 ),
78 ButtonVariant::Ghost => (
79 cx.theme().colors().ghost_element_background,
80 cx.theme().colors().ghost_element_hover,
81 cx.theme().colors().ghost_element_active,
82 ),
83 };
84
85 let mut button = h_stack()
86 .id(self.id.clone())
87 .justify_center()
88 .rounded_md()
89 // todo!("Where do these numbers come from?")
90 .py(rems(0.21875))
91 .px(rems(0.375))
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 cx.stop_propagation();
100 click_handler(state, cx);
101 });
102 }
103
104 button
105 }
106}