components.rs

  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}