components.rs

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