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