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