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