1use anyhow::Result;
2use derive_more::{Deref, DerefMut};
3use gpui::{geometry::rect::RectF, EngineLayout};
4use smallvec::SmallVec;
5use std::marker::PhantomData;
6use util::ResultExt;
7
8pub use crate::layout_context::LayoutContext;
9pub use crate::paint_context::PaintContext;
10
11type LayoutId = gpui::LayoutId;
12
13pub trait Element<V: 'static>: 'static {
14 type Layout;
15
16 fn layout(
17 &mut self,
18 view: &mut V,
19 cx: &mut LayoutContext<V>,
20 ) -> Result<Layout<V, Self::Layout>>
21 where
22 Self: Sized;
23
24 fn paint(
25 &mut self,
26 view: &mut V,
27 layout: &mut Layout<V, Self::Layout>,
28 cx: &mut PaintContext<V>,
29 ) where
30 Self: Sized;
31
32 fn into_any(self) -> AnyElement<V>
33 where
34 Self: 'static + Sized,
35 {
36 AnyElement(Box::new(ElementState {
37 element: self,
38 layout: None,
39 }))
40 }
41}
42
43/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
44trait ElementStateObject<V> {
45 fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
46 fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
47}
48
49/// A wrapper around an element that stores its layout state.
50struct ElementState<V: 'static, E: Element<V>> {
51 element: E,
52 layout: Option<Layout<V, E::Layout>>,
53}
54
55/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
56impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
57 fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
58 let layout = self.element.layout(view, cx)?;
59 let layout_id = layout.id;
60 self.layout = Some(layout);
61 Ok(layout_id)
62 }
63
64 fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
65 let layout = self.layout.as_mut().expect("paint called before layout");
66 if layout.engine_layout.is_none() {
67 layout.engine_layout = cx.computed_layout(layout.id).log_err()
68 }
69 self.element.paint(view, layout, cx)
70 }
71}
72
73/// A dynamic element.
74pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>);
75
76impl<V> AnyElement<V> {
77 pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
78 self.0.layout(view, cx)
79 }
80
81 pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
82 self.0.paint(view, cx)
83 }
84}
85
86#[derive(Deref, DerefMut)]
87pub struct Layout<V, D> {
88 id: LayoutId,
89 engine_layout: Option<EngineLayout>,
90 #[deref]
91 #[deref_mut]
92 element_data: D,
93 view_type: PhantomData<V>,
94}
95
96impl<V: 'static, D> Layout<V, D> {
97 pub fn new(id: LayoutId, element_data: D) -> Self {
98 Self {
99 id,
100 engine_layout: None,
101 element_data: element_data,
102 view_type: PhantomData,
103 }
104 }
105
106 pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF {
107 self.engine_layout(cx).bounds
108 }
109
110 pub fn order(&mut self, cx: &mut PaintContext<V>) -> u32 {
111 self.engine_layout(cx).order
112 }
113
114 fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {
115 self.engine_layout
116 .get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default())
117 }
118}
119
120impl<V: 'static> Layout<V, Option<AnyElement<V>>> {
121 pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
122 let mut element = self.element_data.take().unwrap();
123 element.paint(view, cx);
124 self.element_data = Some(element);
125 }
126}
127
128pub trait ParentElement<V: 'static> {
129 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
130
131 fn child(mut self, child: impl IntoElement<V>) -> Self
132 where
133 Self: Sized,
134 {
135 self.children_mut().push(child.into_element().into_any());
136 self
137 }
138
139 fn children<I, E>(mut self, children: I) -> Self
140 where
141 I: IntoIterator<Item = E>,
142 E: IntoElement<V>,
143 Self: Sized,
144 {
145 self.children_mut().extend(
146 children
147 .into_iter()
148 .map(|child| child.into_element().into_any()),
149 );
150 self
151 }
152}
153
154pub trait IntoElement<V: 'static> {
155 type Element: Element<V>;
156
157 fn into_element(self) -> Self::Element;
158}