1use gpui2::{
2 div, ArcCow, Element, EventContext, Interactive, IntoElement, MouseButton, ParentElement,
3 StyleHelpers, ViewContext,
4};
5use std::{marker::PhantomData, rc::Rc};
6
7struct ButtonHandlers<V, D> {
8 click: Option<Rc<dyn Fn(&mut V, &D, &mut EventContext<V>)>>,
9}
10
11impl<V, D> Default for ButtonHandlers<V, D> {
12 fn default() -> Self {
13 Self { click: None }
14 }
15}
16
17#[derive(Component)]
18pub struct Button<V: 'static, D: 'static> {
19 handlers: ButtonHandlers<V, D>,
20 label: Option<ArcCow<'static, str>>,
21 icon: Option<ArcCow<'static, str>>,
22 data: Rc<D>,
23 view_type: PhantomData<V>,
24}
25
26// Impl block for buttons without data.
27// See below for an impl block for any button.
28impl<V: 'static> Button<V, ()> {
29 fn new() -> Self {
30 Self {
31 handlers: ButtonHandlers::default(),
32 label: None,
33 icon: None,
34 data: Rc::new(()),
35 view_type: PhantomData,
36 }
37 }
38
39 pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
40 Button {
41 handlers: ButtonHandlers::default(),
42 label: self.label,
43 icon: self.icon,
44 data: Rc::new(data),
45 view_type: PhantomData,
46 }
47 }
48}
49
50// Impl block for button regardless of its data type.
51impl<V: 'static, D: 'static> Button<V, D> {
52 pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
53 self.label = Some(label.into());
54 self
55 }
56
57 pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
58 self.icon = Some(icon.into());
59 self
60 }
61
62 pub fn on_click(
63 mut self,
64 handler: impl Fn(&mut V, &D, &mut EventContext<V>) + 'static,
65 ) -> Self {
66 self.handlers.click = Some(Rc::new(handler));
67 self
68 }
69}
70
71pub fn button<V>() -> Button<V, ()> {
72 Button::new()
73}
74
75impl<V: 'static, D: 'static> Button<V, D> {
76 fn render(
77 &mut self,
78 view: &mut V,
79 cx: &mut ViewContext<V>,
80 ) -> impl IntoElement<V> + Interactive<V> {
81 // let colors = &cx.theme::<Theme>().colors;
82
83 let button = div()
84 // .fill(colors.error(0.5))
85 .h_4()
86 .children(self.label.clone());
87
88 if let Some(handler) = self.handlers.click.clone() {
89 let data = self.data.clone();
90 button.on_mouse_down(MouseButton::Left, move |view, event, cx| {
91 handler(view, data.as_ref(), cx)
92 })
93 } else {
94 button
95 }
96 }
97}