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// }