components.rs

 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}