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