components.rs

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