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