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