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