1mod align;
2mod canvas;
3mod constrained_box;
4mod container;
5mod empty;
6mod event_handler;
7mod flex;
8mod label;
9mod line_box;
10mod list;
11mod mouse_event_handler;
12mod stack;
13mod svg;
14mod uniform_list;
15
16pub use crate::presenter::ChildView;
17pub use align::*;
18pub use canvas::*;
19pub use constrained_box::*;
20pub use container::*;
21pub use empty::*;
22pub use event_handler::*;
23pub use flex::*;
24pub use label::*;
25pub use line_box::*;
26pub use list::*;
27pub use mouse_event_handler::*;
28pub use stack::*;
29pub use svg::*;
30pub use uniform_list::*;
31
32use crate::{
33 geometry::{rect::RectF, vector::Vector2F},
34 json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
35};
36use core::panic;
37use json::ToJson;
38use std::{any::Any, borrow::Cow, mem};
39
40trait AnyElement {
41 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
42 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
43 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
44 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
45
46 fn size(&self) -> Vector2F;
47 fn metadata(&self) -> Option<&dyn Any>;
48}
49
50pub trait Element {
51 type LayoutState;
52 type PaintState;
53
54 fn layout(
55 &mut self,
56 constraint: SizeConstraint,
57 cx: &mut LayoutContext,
58 ) -> (Vector2F, Self::LayoutState);
59
60 fn paint(
61 &mut self,
62 bounds: RectF,
63 layout: &mut Self::LayoutState,
64 cx: &mut PaintContext,
65 ) -> Self::PaintState;
66
67 fn dispatch_event(
68 &mut self,
69 event: &Event,
70 bounds: RectF,
71 layout: &mut Self::LayoutState,
72 paint: &mut Self::PaintState,
73 cx: &mut EventContext,
74 ) -> bool;
75
76 fn metadata(&self) -> Option<&dyn Any> {
77 None
78 }
79
80 fn debug(
81 &self,
82 bounds: RectF,
83 layout: &Self::LayoutState,
84 paint: &Self::PaintState,
85 cx: &DebugContext,
86 ) -> serde_json::Value;
87
88 fn boxed(self) -> ElementBox
89 where
90 Self: 'static + Sized,
91 {
92 ElementBox {
93 name: None,
94 element: Box::new(Lifecycle::Init { element: self }),
95 }
96 }
97
98 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
99 where
100 Self: 'static + Sized,
101 {
102 ElementBox {
103 name: Some(name.into()),
104 element: Box::new(Lifecycle::Init { element: self }),
105 }
106 }
107}
108
109pub enum Lifecycle<T: Element> {
110 Empty,
111 Init {
112 element: T,
113 },
114 PostLayout {
115 element: T,
116 constraint: SizeConstraint,
117 size: Vector2F,
118 layout: T::LayoutState,
119 },
120 PostPaint {
121 element: T,
122 constraint: SizeConstraint,
123 bounds: RectF,
124 layout: T::LayoutState,
125 paint: T::PaintState,
126 },
127}
128pub struct ElementBox {
129 name: Option<Cow<'static, str>>,
130 element: Box<dyn AnyElement>,
131}
132
133impl<T: Element> AnyElement for Lifecycle<T> {
134 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
135 let result;
136 *self = match mem::take(self) {
137 Lifecycle::Empty => unreachable!(),
138 Lifecycle::Init { mut element }
139 | Lifecycle::PostLayout { mut element, .. }
140 | Lifecycle::PostPaint { mut element, .. } => {
141 let (size, layout) = element.layout(constraint, cx);
142 debug_assert!(size.x().is_finite());
143 debug_assert!(size.y().is_finite());
144
145 result = size;
146 Lifecycle::PostLayout {
147 element,
148 constraint,
149 size,
150 layout,
151 }
152 }
153 };
154 result
155 }
156
157 fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
158 *self = match mem::take(self) {
159 Lifecycle::PostLayout {
160 mut element,
161 constraint,
162 size,
163 mut layout,
164 } => {
165 let bounds = RectF::new(origin, size);
166 let paint = element.paint(bounds, &mut layout, cx);
167 Lifecycle::PostPaint {
168 element,
169 constraint,
170 bounds,
171 layout,
172 paint,
173 }
174 }
175 Lifecycle::PostPaint {
176 mut element,
177 constraint,
178 bounds,
179 mut layout,
180 ..
181 } => {
182 let bounds = RectF::new(origin, bounds.size());
183 let paint = element.paint(bounds, &mut layout, cx);
184 Lifecycle::PostPaint {
185 element,
186 constraint,
187 bounds,
188 layout,
189 paint,
190 }
191 }
192 _ => panic!("invalid element lifecycle state"),
193 }
194 }
195
196 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
197 if let Lifecycle::PostPaint {
198 element,
199 bounds,
200 layout,
201 paint,
202 ..
203 } = self
204 {
205 element.dispatch_event(event, *bounds, layout, paint, cx)
206 } else {
207 panic!("invalid element lifecycle state");
208 }
209 }
210
211 fn size(&self) -> Vector2F {
212 match self {
213 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
214 Lifecycle::PostLayout { size, .. } => *size,
215 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
216 }
217 }
218
219 fn metadata(&self) -> Option<&dyn Any> {
220 match self {
221 Lifecycle::Empty => unreachable!(),
222 Lifecycle::Init { element }
223 | Lifecycle::PostLayout { element, .. }
224 | Lifecycle::PostPaint { element, .. } => element.metadata(),
225 }
226 }
227
228 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
229 match self {
230 Lifecycle::PostPaint {
231 element,
232 constraint,
233 bounds,
234 layout,
235 paint,
236 } => {
237 let mut value = element.debug(*bounds, layout, paint, cx);
238 if let json::Value::Object(map) = &mut value {
239 let mut new_map: crate::json::Map<String, serde_json::Value> =
240 Default::default();
241 if let Some(typ) = map.remove("type") {
242 new_map.insert("type".into(), typ);
243 }
244 new_map.insert("constraint".into(), constraint.to_json());
245 new_map.append(map);
246 json::Value::Object(new_map)
247 } else {
248 value
249 }
250 }
251 _ => panic!("invalid element lifecycle state"),
252 }
253 }
254}
255
256impl<T: Element> Default for Lifecycle<T> {
257 fn default() -> Self {
258 Self::Empty
259 }
260}
261
262impl ElementBox {
263 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
264 self.element.layout(constraint, cx)
265 }
266
267 pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
268 self.element.paint(origin, cx);
269 }
270
271 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
272 self.element.dispatch_event(event, cx)
273 }
274
275 pub fn size(&self) -> Vector2F {
276 self.element.size()
277 }
278
279 pub fn metadata(&self) -> Option<&dyn Any> {
280 self.element.metadata()
281 }
282
283 pub fn debug(&self, cx: &DebugContext) -> json::Value {
284 let mut value = self.element.debug(cx);
285
286 if let Some(name) = &self.name {
287 if let json::Value::Object(map) = &mut value {
288 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
289 new_map.insert("name".into(), json::Value::String(name.to_string()));
290 new_map.append(map);
291 return json::Value::Object(new_map);
292 }
293 }
294
295 value
296 }
297}
298
299pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
300 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
301 self.extend(children);
302 }
303
304 fn add_child(&mut self, child: ElementBox) {
305 self.add_children(Some(child));
306 }
307
308 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
309 self.add_children(children);
310 self
311 }
312
313 fn with_child(self, child: ElementBox) -> Self {
314 self.with_children(Some(child))
315 }
316}
317
318impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}