1pub use crate::layout_context::LayoutContext;
2pub use crate::paint_context::PaintContext;
3use anyhow::Result;
4pub use gpui::{Layout, LayoutId};
5use smallvec::SmallVec;
6
7pub trait Element<V: 'static>: 'static {
8 type PaintState;
9
10 fn layout(
11 &mut self,
12 view: &mut V,
13 cx: &mut LayoutContext<V>,
14 ) -> Result<(LayoutId, Self::PaintState)>
15 where
16 Self: Sized;
17
18 fn paint(
19 &mut self,
20 view: &mut V,
21 layout: &Layout,
22 state: &mut Self::PaintState,
23 cx: &mut PaintContext<V>,
24 ) where
25 Self: Sized;
26
27 fn into_any(self) -> AnyElement<V>
28 where
29 Self: 'static + Sized,
30 {
31 AnyElement(Box::new(StatefulElement {
32 element: self,
33 phase: ElementPhase::Init,
34 }))
35 }
36}
37
38/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
39trait AnyStatefulElement<V> {
40 fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
41 fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
42}
43
44/// A wrapper around an element that stores its layout state.
45struct StatefulElement<V: 'static, E: Element<V>> {
46 element: E,
47 phase: ElementPhase<V, E>,
48}
49
50enum ElementPhase<V: 'static, E: Element<V>> {
51 Init,
52 PostLayout {
53 layout_id: LayoutId,
54 paint_state: E::PaintState,
55 },
56 PostPaint {
57 layout: Layout,
58 paint_state: E::PaintState,
59 },
60 Error(String),
61}
62
63impl<V: 'static, E: Element<V>> Default for ElementPhase<V, E> {
64 fn default() -> Self {
65 Self::Init
66 }
67}
68
69/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
70impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
71 fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
72 let result;
73 self.phase = match std::mem::take(&mut self.phase) {
74 ElementPhase::Init => match self.element.layout(view, cx) {
75 Ok((layout_id, paint_state)) => {
76 result = Ok(layout_id);
77 ElementPhase::PostLayout {
78 layout_id,
79 paint_state,
80 }
81 }
82 Err(error) => {
83 let message = error.to_string();
84 result = Err(error);
85 ElementPhase::Error(message)
86 }
87 },
88 _ => panic!("invalid element phase to call layout"),
89 };
90
91 result
92 }
93
94 fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
95 self.phase = match std::mem::take(&mut self.phase) {
96 ElementPhase::PostLayout {
97 layout_id,
98 mut paint_state,
99 } => match cx.computed_layout(layout_id) {
100 Ok(layout) => {
101 self.element.paint(view, &layout, &mut paint_state, cx);
102 ElementPhase::PostPaint {
103 layout,
104 paint_state,
105 }
106 }
107 Err(error) => ElementPhase::Error(error.to_string()),
108 },
109 phase @ ElementPhase::Error(_) => phase,
110 _ => panic!("invalid element phase to call paint"),
111 };
112 }
113}
114
115/// A dynamic element.
116pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
117
118impl<V> AnyElement<V> {
119 pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
120 self.0.layout(view, cx)
121 }
122
123 pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
124 self.0.paint(view, cx)
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}