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