components.rs

  1use crate::{
  2    element::{Element, ElementMetadata},
  3    frame,
  4    text::ArcCow,
  5    themes::rose_pine,
  6};
  7use gpui::{platform::MouseButton, ViewContext};
  8use playground_macros::Element;
  9use std::{marker::PhantomData, rc::Rc};
 10
 11struct ButtonHandlers<V, D> {
 12    click: Option<Rc<dyn Fn(&mut V, &D, &mut ViewContext<V>)>>,
 13}
 14
 15impl<V, D> Default for ButtonHandlers<V, D> {
 16    fn default() -> Self {
 17        Self { click: None }
 18    }
 19}
 20
 21#[derive(Element)]
 22#[element_crate = "crate"]
 23pub struct Button<V: 'static, D: 'static> {
 24    metadata: ElementMetadata<V>,
 25    handlers: ButtonHandlers<V, D>,
 26    label: Option<ArcCow<'static, str>>,
 27    icon: Option<ArcCow<'static, str>>,
 28    data: Rc<D>,
 29    view_type: PhantomData<V>,
 30}
 31
 32// Impl block for buttons without data.
 33// See below for an impl block for any button.
 34impl<V: 'static> Button<V, ()> {
 35    fn new() -> Self {
 36        Self {
 37            metadata: Default::default(),
 38            handlers: ButtonHandlers::default(),
 39            label: None,
 40            icon: None,
 41            data: Rc::new(()),
 42            view_type: PhantomData,
 43        }
 44    }
 45
 46    pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
 47        Button {
 48            metadata: Default::default(),
 49            handlers: ButtonHandlers::default(),
 50            label: self.label,
 51            icon: self.icon,
 52            data: Rc::new(data),
 53            view_type: PhantomData,
 54        }
 55    }
 56}
 57
 58// Impl block for *any* button.
 59impl<V: 'static, D: 'static> Button<V, D> {
 60    pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
 61        self.label = Some(label.into());
 62        self
 63    }
 64
 65    pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
 66        self.icon = Some(icon.into());
 67        self
 68    }
 69
 70    pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
 71        let data = self.data.clone();
 72        Element::click(self, MouseButton::Left, move |view, _, cx| {
 73            handler(view, data.as_ref(), cx);
 74        })
 75    }
 76}
 77
 78pub fn button<V>() -> Button<V, ()> {
 79    Button::new()
 80}
 81
 82impl<V: 'static, D: 'static> Button<V, D> {
 83    fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
 84        // TODO: Drive theme from the context
 85        let button = frame()
 86            .fill(rose_pine::dawn().error(0.5))
 87            .h_4()
 88            .children(self.label.clone());
 89
 90        if let Some(handler) = self.handlers.click.clone() {
 91            let data = self.data.clone();
 92            button.mouse_down(MouseButton::Left, move |view, event, cx| {
 93                handler(view, data.as_ref(), cx)
 94            })
 95        } else {
 96            button
 97        }
 98    }
 99}
100
101// impl<V: 'static, D> Element<V> for Button<V, D> {
102//     type Layout = AnyElement<V>;
103
104//     fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
105//         &mut self.metadata.style
106//     }
107
108//     fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
109//         &mut self.metadata.handlers
110//     }
111
112//     fn layout(
113//         &mut self,
114//         view: &mut V,
115//         cx: &mut crate::element::LayoutContext<V>,
116//     ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
117//         let mut element = self.render(view, cx).into_any();
118//         let node_id = element.layout(view, cx)?;
119//         Ok((node_id, element))
120//     }
121
122//     fn paint<'a>(
123//         &mut self,
124//         layout: crate::element::Layout<'a, Self::Layout>,
125//         view: &mut V,
126//         cx: &mut crate::element::PaintContext<V>,
127//     ) -> anyhow::Result<()> {
128//         layout.from_element.paint(view, cx)?;
129//         Ok(())
130//     }
131// }