1pub use crate::paint_context::PaintContext;
2pub use crate::ViewContext;
3use anyhow::Result;
4use gpui::geometry::vector::Vector2F;
5pub use gpui::{Layout, LayoutId};
6use smallvec::SmallVec;
7
8pub trait Element<V: 'static>: 'static + IntoElement<V> {
9 type PaintState;
10
11 fn layout(
12 &mut self,
13 view: &mut V,
14 cx: &mut ViewContext<V>,
15 ) -> Result<(LayoutId, Self::PaintState)>
16 where
17 Self: Sized;
18
19 fn paint(
20 &mut self,
21 view: &mut V,
22 parent_origin: Vector2F,
23 layout: &Layout,
24 state: &mut Self::PaintState,
25 cx: &mut PaintContext<V>,
26 ) where
27 Self: Sized;
28
29 fn into_any(self) -> AnyElement<V>
30 where
31 Self: 'static + Sized,
32 {
33 AnyElement(Box::new(StatefulElement {
34 element: self,
35 phase: ElementPhase::Init,
36 }))
37 }
38}
39
40/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
41trait AnyStatefulElement<V> {
42 fn layout(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> Result<LayoutId>;
43 fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>);
44}
45
46/// A wrapper around an element that stores its layout state.
47struct StatefulElement<V: 'static, E: Element<V>> {
48 element: E,
49 phase: ElementPhase<V, E>,
50}
51
52enum ElementPhase<V: 'static, E: Element<V>> {
53 Init,
54 PostLayout {
55 layout_id: LayoutId,
56 paint_state: E::PaintState,
57 },
58 #[allow(dead_code)]
59 PostPaint {
60 layout: Layout,
61 paint_state: E::PaintState,
62 },
63 Error(String),
64}
65
66impl<V: 'static, E: Element<V>> std::fmt::Debug for ElementPhase<V, E> {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 match self {
69 ElementPhase::Init => write!(f, "Init"),
70 ElementPhase::PostLayout { layout_id, .. } => {
71 write!(f, "PostLayout with layout id: {:?}", layout_id)
72 }
73 ElementPhase::PostPaint { layout, .. } => {
74 write!(f, "PostPaint with layout: {:?}", layout)
75 }
76 ElementPhase::Error(err) => write!(f, "Error: {}", err),
77 }
78 }
79}
80
81impl<V: 'static, E: Element<V>> Default for ElementPhase<V, E> {
82 fn default() -> Self {
83 Self::Init
84 }
85}
86
87/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
88impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
89 fn layout(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> Result<LayoutId> {
90 let result;
91 self.phase = match self.element.layout(view, cx) {
92 Ok((layout_id, paint_state)) => {
93 result = Ok(layout_id);
94 ElementPhase::PostLayout {
95 layout_id,
96 paint_state,
97 }
98 }
99 Err(error) => {
100 let message = error.to_string();
101 result = Err(error);
102 ElementPhase::Error(message)
103 }
104 };
105 result
106 }
107
108 fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
109 self.phase = match std::mem::take(&mut self.phase) {
110 ElementPhase::PostLayout {
111 layout_id,
112 mut paint_state,
113 } => match cx.computed_layout(layout_id) {
114 Ok(layout) => {
115 self.element
116 .paint(view, parent_origin, &layout, &mut paint_state, cx);
117 ElementPhase::PostPaint {
118 layout,
119 paint_state,
120 }
121 }
122 Err(error) => ElementPhase::Error(error.to_string()),
123 },
124 ElementPhase::PostPaint {
125 layout,
126 mut paint_state,
127 } => {
128 self.element
129 .paint(view, parent_origin, &layout, &mut paint_state, cx);
130 ElementPhase::PostPaint {
131 layout,
132 paint_state,
133 }
134 }
135 phase @ ElementPhase::Error(_) => phase,
136
137 phase @ _ => {
138 panic!("invalid element phase to call paint: {:?}", phase);
139 }
140 };
141 }
142}
143
144/// A dynamic element.
145pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
146
147impl<V> AnyElement<V> {
148 pub fn layout(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> Result<LayoutId> {
149 self.0.layout(view, cx)
150 }
151
152 pub fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut PaintContext<V>) {
153 self.0.paint(view, parent_origin, cx)
154 }
155}
156
157pub trait ParentElement<V: 'static> {
158 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
159
160 fn child(mut self, child: impl IntoElement<V>) -> Self
161 where
162 Self: Sized,
163 {
164 self.children_mut().push(child.into_element().into_any());
165 self
166 }
167
168 fn children<I, E>(mut self, children: I) -> Self
169 where
170 I: IntoIterator<Item = E>,
171 E: IntoElement<V>,
172 Self: Sized,
173 {
174 self.children_mut().extend(
175 children
176 .into_iter()
177 .map(|child| child.into_element().into_any()),
178 );
179 self
180 }
181}
182
183pub trait IntoElement<V: 'static> {
184 type Element: Element<V>;
185
186 fn into_element(self) -> Self::Element;
187}