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