1pub use crate::ViewContext;
2use anyhow::Result;
3use gpui::geometry::vector::Vector2F;
4pub use gpui::{Layout, LayoutId};
5use smallvec::SmallVec;
6
7pub trait Element<V: 'static>: 'static + IntoElement<V> {
8 type PaintState;
9
10 fn layout(
11 &mut self,
12 view: &mut V,
13 cx: &mut ViewContext<V>,
14 ) -> Result<(LayoutId, Self::PaintState)>
15 where
16 Self: Sized;
17
18 fn paint(
19 &mut self,
20 view: &mut V,
21 parent_origin: Vector2F,
22 layout: &Layout,
23 state: &mut Self::PaintState,
24 cx: &mut ViewContext<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 ViewContext<V>) -> Result<LayoutId>;
42 fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut ViewContext<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 ViewContext<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 ViewContext<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(layout) => {
114 self.element
115 .paint(view, parent_origin, &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
128 .paint(view, parent_origin, &layout, &mut paint_state, cx);
129 ElementPhase::PostPaint {
130 layout,
131 paint_state,
132 }
133 }
134 phase @ ElementPhase::Error(_) => phase,
135
136 phase @ _ => {
137 panic!("invalid element phase to call paint: {:?}", phase);
138 }
139 };
140 }
141}
142
143/// A dynamic element.
144pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
145
146impl<V> AnyElement<V> {
147 pub fn layout(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> Result<LayoutId> {
148 self.0.layout(view, cx)
149 }
150
151 pub fn paint(&mut self, view: &mut V, parent_origin: Vector2F, cx: &mut ViewContext<V>) {
152 self.0.paint(view, parent_origin, cx)
153 }
154}
155
156pub trait ParentElement<V: 'static> {
157 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
158
159 fn child(mut self, child: impl IntoElement<V>) -> Self
160 where
161 Self: Sized,
162 {
163 self.children_mut().push(child.into_element().into_any());
164 self
165 }
166
167 fn children<I, E>(mut self, children: I) -> Self
168 where
169 I: IntoIterator<Item = E>,
170 E: IntoElement<V>,
171 Self: Sized,
172 {
173 self.children_mut().extend(
174 children
175 .into_iter()
176 .map(|child| child.into_element().into_any()),
177 );
178 self
179 }
180}
181
182pub trait IntoElement<V: 'static> {
183 type Element: Element<V>;
184
185 fn into_element(self) -> Self::Element;
186}