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