components.rs

  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}