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