components.rs

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