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