components.rs

  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}