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 result = Some(size);
91 Lifecycle::PostLayout {
92 element,
93 size,
94 layout,
95 }
96 }
97 });
98 result.unwrap()
99 }
100
101 fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
102 if let Lifecycle::PostLayout {
103 element,
104 size,
105 layout,
106 } = self
107 {
108 element.after_layout(*size, layout, ctx);
109 } else {
110 panic!("invalid element lifecycle state");
111 }
112 }
113
114 fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
115 replace_with_or_abort(self, |me| {
116 if let Lifecycle::PostLayout {
117 mut element,
118 size,
119 mut layout,
120 } = me
121 {
122 let bounds = RectF::new(origin, size);
123 let paint = element.paint(bounds, &mut layout, ctx);
124 Lifecycle::PostPaint {
125 element,
126 bounds,
127 layout,
128 paint,
129 }
130 } else {
131 panic!("invalid element lifecycle state");
132 }
133 });
134 }
135
136 fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
137 if let Lifecycle::PostPaint {
138 element,
139 bounds,
140 layout,
141 paint,
142 } = self
143 {
144 element.dispatch_event(event, *bounds, layout, paint, ctx)
145 } else {
146 panic!("invalid element lifecycle state");
147 }
148 }
149
150 fn size(&self) -> Vector2F {
151 match self {
152 Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
153 Lifecycle::PostLayout { size, .. } => *size,
154 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
155 }
156 }
157
158 fn metadata(&self) -> Option<&dyn Any> {
159 match self {
160 Lifecycle::Init { element }
161 | Lifecycle::PostLayout { element, .. }
162 | Lifecycle::PostPaint { element, .. } => element.metadata(),
163 }
164 }
165}
166
167impl ElementBox {
168 pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
169 self.0.layout(constraint, ctx)
170 }
171
172 pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
173 self.0.after_layout(ctx);
174 }
175
176 pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
177 self.0.paint(origin, ctx);
178 }
179
180 pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
181 self.0.dispatch_event(event, ctx)
182 }
183
184 pub fn size(&self) -> Vector2F {
185 self.0.size()
186 }
187
188 pub fn metadata(&self) -> Option<&dyn Any> {
189 self.0.metadata()
190 }
191}