1mod align;
2mod canvas;
3mod constrained_box;
4mod container;
5mod empty;
6mod event_handler;
7mod expanded;
8mod flex;
9mod hook;
10mod image;
11mod keystroke_label;
12mod label;
13mod list;
14mod mouse_event_handler;
15mod overlay;
16mod stack;
17mod svg;
18mod text;
19mod uniform_list;
20
21use self::expanded::Expanded;
22pub use self::{
23 align::*, canvas::*, constrained_box::*, container::*, empty::*, event_handler::*, flex::*,
24 hook::*, image::*, keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*,
25 stack::*, svg::*, text::*, uniform_list::*,
26};
27pub use crate::presenter::ChildView;
28use crate::{
29 geometry::{
30 rect::RectF,
31 vector::{vec2f, Vector2F},
32 },
33 json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
34};
35use core::panic;
36use json::ToJson;
37use std::{
38 any::Any,
39 borrow::Cow,
40 cell::RefCell,
41 mem,
42 ops::{Deref, DerefMut},
43 rc::Rc,
44};
45
46trait AnyElement {
47 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
48 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
49 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
50 fn debug(&self, cx: &DebugContext) -> serde_json::Value;
51
52 fn size(&self) -> Vector2F;
53 fn metadata(&self) -> Option<&dyn Any>;
54}
55
56pub trait Element {
57 type LayoutState;
58 type PaintState;
59
60 fn layout(
61 &mut self,
62 constraint: SizeConstraint,
63 cx: &mut LayoutContext,
64 ) -> (Vector2F, Self::LayoutState);
65
66 fn paint(
67 &mut self,
68 bounds: RectF,
69 visible_bounds: RectF,
70 layout: &mut Self::LayoutState,
71 cx: &mut PaintContext,
72 ) -> Self::PaintState;
73
74 fn dispatch_event(
75 &mut self,
76 event: &Event,
77 bounds: RectF,
78 visible_bounds: RectF,
79 layout: &mut Self::LayoutState,
80 paint: &mut Self::PaintState,
81 cx: &mut EventContext,
82 ) -> bool;
83
84 fn metadata(&self) -> Option<&dyn Any> {
85 None
86 }
87
88 fn debug(
89 &self,
90 bounds: RectF,
91 layout: &Self::LayoutState,
92 paint: &Self::PaintState,
93 cx: &DebugContext,
94 ) -> serde_json::Value;
95
96 fn boxed(self) -> ElementBox
97 where
98 Self: 'static + Sized,
99 {
100 ElementBox(ElementRc {
101 name: None,
102 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
103 })
104 }
105
106 fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
107 where
108 Self: 'static + Sized,
109 {
110 ElementBox(ElementRc {
111 name: Some(name.into()),
112 element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
113 })
114 }
115
116 fn constrained(self) -> ConstrainedBox
117 where
118 Self: 'static + Sized,
119 {
120 ConstrainedBox::new(self.boxed())
121 }
122
123 fn aligned(self) -> Align
124 where
125 Self: 'static + Sized,
126 {
127 Align::new(self.boxed())
128 }
129
130 fn contained(self) -> Container
131 where
132 Self: 'static + Sized,
133 {
134 Container::new(self.boxed())
135 }
136
137 fn expanded(self) -> Expanded
138 where
139 Self: 'static + Sized,
140 {
141 Expanded::new(self.boxed())
142 }
143
144 fn flex(self, flex: f32, expanded: bool) -> FlexItem
145 where
146 Self: 'static + Sized,
147 {
148 FlexItem::new(self.boxed()).flex(flex, expanded)
149 }
150
151 fn flex_float(self) -> FlexItem
152 where
153 Self: 'static + Sized,
154 {
155 FlexItem::new(self.boxed()).float()
156 }
157}
158
159pub enum Lifecycle<T: Element> {
160 Empty,
161 Init {
162 element: T,
163 },
164 PostLayout {
165 element: T,
166 constraint: SizeConstraint,
167 size: Vector2F,
168 layout: T::LayoutState,
169 },
170 PostPaint {
171 element: T,
172 constraint: SizeConstraint,
173 bounds: RectF,
174 visible_bounds: RectF,
175 layout: T::LayoutState,
176 paint: T::PaintState,
177 },
178}
179pub struct ElementBox(ElementRc);
180
181#[derive(Clone)]
182pub struct ElementRc {
183 name: Option<Cow<'static, str>>,
184 element: Rc<RefCell<dyn AnyElement>>,
185}
186
187impl<T: Element> AnyElement for Lifecycle<T> {
188 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
189 let result;
190 *self = match mem::take(self) {
191 Lifecycle::Empty => unreachable!(),
192 Lifecycle::Init { mut element }
193 | Lifecycle::PostLayout { mut element, .. }
194 | Lifecycle::PostPaint { mut element, .. } => {
195 let (size, layout) = element.layout(constraint, cx);
196 debug_assert!(size.x().is_finite());
197 debug_assert!(size.y().is_finite());
198
199 result = size;
200 Lifecycle::PostLayout {
201 element,
202 constraint,
203 size,
204 layout,
205 }
206 }
207 };
208 result
209 }
210
211 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
212 *self = match mem::take(self) {
213 Lifecycle::PostLayout {
214 mut element,
215 constraint,
216 size,
217 mut layout,
218 } => {
219 let bounds = RectF::new(origin, size);
220 let visible_bounds = visible_bounds
221 .intersection(bounds)
222 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
223 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
224 Lifecycle::PostPaint {
225 element,
226 constraint,
227 bounds,
228 visible_bounds,
229 layout,
230 paint,
231 }
232 }
233 Lifecycle::PostPaint {
234 mut element,
235 constraint,
236 bounds,
237 mut layout,
238 ..
239 } => {
240 let bounds = RectF::new(origin, bounds.size());
241 let visible_bounds = visible_bounds
242 .intersection(bounds)
243 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
244 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
245 Lifecycle::PostPaint {
246 element,
247 constraint,
248 bounds,
249 visible_bounds,
250 layout,
251 paint,
252 }
253 }
254 _ => panic!("invalid element lifecycle state"),
255 }
256 }
257
258 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
259 if let Lifecycle::PostPaint {
260 element,
261 bounds,
262 visible_bounds,
263 layout,
264 paint,
265 ..
266 } = self
267 {
268 element.dispatch_event(event, *bounds, *visible_bounds, layout, paint, cx)
269 } else {
270 panic!("invalid element lifecycle state");
271 }
272 }
273
274 fn size(&self) -> Vector2F {
275 match self {
276 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
277 Lifecycle::PostLayout { size, .. } => *size,
278 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
279 }
280 }
281
282 fn metadata(&self) -> Option<&dyn Any> {
283 match self {
284 Lifecycle::Empty => unreachable!(),
285 Lifecycle::Init { element }
286 | Lifecycle::PostLayout { element, .. }
287 | Lifecycle::PostPaint { element, .. } => element.metadata(),
288 }
289 }
290
291 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
292 match self {
293 Lifecycle::PostPaint {
294 element,
295 constraint,
296 bounds,
297 visible_bounds,
298 layout,
299 paint,
300 } => {
301 let mut value = element.debug(*bounds, layout, paint, cx);
302 if let json::Value::Object(map) = &mut value {
303 let mut new_map: crate::json::Map<String, serde_json::Value> =
304 Default::default();
305 if let Some(typ) = map.remove("type") {
306 new_map.insert("type".into(), typ);
307 }
308 new_map.insert("constraint".into(), constraint.to_json());
309 new_map.insert("bounds".into(), bounds.to_json());
310 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
311 new_map.append(map);
312 json::Value::Object(new_map)
313 } else {
314 value
315 }
316 }
317 _ => panic!("invalid element lifecycle state"),
318 }
319 }
320}
321
322impl<T: Element> Default for Lifecycle<T> {
323 fn default() -> Self {
324 Self::Empty
325 }
326}
327
328impl ElementBox {
329 pub fn name(&self) -> Option<&str> {
330 self.0.name.as_deref()
331 }
332
333 pub fn metadata<T: 'static>(&self) -> Option<&T> {
334 let element = unsafe { &*self.0.element.as_ptr() };
335 element.metadata().and_then(|m| m.downcast_ref())
336 }
337}
338
339impl Into<ElementRc> for ElementBox {
340 fn into(self) -> ElementRc {
341 self.0
342 }
343}
344
345impl Deref for ElementBox {
346 type Target = ElementRc;
347
348 fn deref(&self) -> &Self::Target {
349 &self.0
350 }
351}
352
353impl DerefMut for ElementBox {
354 fn deref_mut(&mut self) -> &mut Self::Target {
355 &mut self.0
356 }
357}
358
359impl ElementRc {
360 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
361 self.element.borrow_mut().layout(constraint, cx)
362 }
363
364 pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
365 self.element.borrow_mut().paint(origin, visible_bounds, cx);
366 }
367
368 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
369 self.element.borrow_mut().dispatch_event(event, cx)
370 }
371
372 pub fn size(&self) -> Vector2F {
373 self.element.borrow().size()
374 }
375
376 pub fn debug(&self, cx: &DebugContext) -> json::Value {
377 let mut value = self.element.borrow().debug(cx);
378
379 if let Some(name) = &self.name {
380 if let json::Value::Object(map) = &mut value {
381 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
382 new_map.insert("name".into(), json::Value::String(name.to_string()));
383 new_map.append(map);
384 return json::Value::Object(new_map);
385 }
386 }
387
388 value
389 }
390
391 pub fn with_metadata<T, F, R>(&self, f: F) -> R
392 where
393 T: 'static,
394 F: FnOnce(Option<&T>) -> R,
395 {
396 let element = self.element.borrow();
397 f(element.metadata().and_then(|m| m.downcast_ref()))
398 }
399}
400
401pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
402 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
403 self.extend(children);
404 }
405
406 fn add_child(&mut self, child: ElementBox) {
407 self.add_children(Some(child));
408 }
409
410 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
411 self.add_children(children);
412 self
413 }
414
415 fn with_child(self, child: ElementBox) -> Self {
416 self.with_children(Some(child))
417 }
418}
419
420impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
421
422fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
423 if max_size.x().is_infinite() && max_size.y().is_infinite() {
424 size
425 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
426 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
427 } else {
428 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
429 }
430}