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, 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 tooltip: ElementBox,
164 cx: &mut RenderContext<T>,
165 ) -> Tooltip
166 where
167 Self: 'static + Sized,
168 {
169 Tooltip::new(id, self.boxed(), tooltip, cx)
170 }
171}
172
173pub enum Lifecycle<T: Element> {
174 Empty,
175 Init {
176 element: T,
177 },
178 PostLayout {
179 element: T,
180 constraint: SizeConstraint,
181 size: Vector2F,
182 layout: T::LayoutState,
183 },
184 PostPaint {
185 element: T,
186 constraint: SizeConstraint,
187 bounds: RectF,
188 visible_bounds: RectF,
189 layout: T::LayoutState,
190 paint: T::PaintState,
191 },
192}
193pub struct ElementBox(ElementRc);
194
195#[derive(Clone)]
196pub struct ElementRc {
197 name: Option<Cow<'static, str>>,
198 element: Rc<RefCell<dyn AnyElement>>,
199}
200
201impl<T: Element> AnyElement for Lifecycle<T> {
202 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
203 let result;
204 *self = match mem::take(self) {
205 Lifecycle::Empty => unreachable!(),
206 Lifecycle::Init { mut element }
207 | Lifecycle::PostLayout { mut element, .. }
208 | Lifecycle::PostPaint { mut element, .. } => {
209 let (size, layout) = element.layout(constraint, cx);
210 debug_assert!(size.x().is_finite());
211 debug_assert!(size.y().is_finite());
212
213 result = size;
214 Lifecycle::PostLayout {
215 element,
216 constraint,
217 size,
218 layout,
219 }
220 }
221 };
222 result
223 }
224
225 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
226 *self = match mem::take(self) {
227 Lifecycle::PostLayout {
228 mut element,
229 constraint,
230 size,
231 mut layout,
232 } => {
233 let bounds = RectF::new(origin, size);
234 let visible_bounds = visible_bounds
235 .intersection(bounds)
236 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
237 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
238 Lifecycle::PostPaint {
239 element,
240 constraint,
241 bounds,
242 visible_bounds,
243 layout,
244 paint,
245 }
246 }
247 Lifecycle::PostPaint {
248 mut element,
249 constraint,
250 bounds,
251 mut layout,
252 ..
253 } => {
254 let bounds = RectF::new(origin, bounds.size());
255 let visible_bounds = visible_bounds
256 .intersection(bounds)
257 .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
258 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
259 Lifecycle::PostPaint {
260 element,
261 constraint,
262 bounds,
263 visible_bounds,
264 layout,
265 paint,
266 }
267 }
268 _ => panic!("invalid element lifecycle state"),
269 }
270 }
271
272 fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
273 if let Lifecycle::PostPaint {
274 element,
275 bounds,
276 visible_bounds,
277 layout,
278 paint,
279 ..
280 } = self
281 {
282 element.dispatch_event(event, *bounds, *visible_bounds, layout, paint, cx)
283 } else {
284 panic!("invalid element lifecycle state");
285 }
286 }
287
288 fn size(&self) -> Vector2F {
289 match self {
290 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
291 Lifecycle::PostLayout { size, .. } => *size,
292 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
293 }
294 }
295
296 fn metadata(&self) -> Option<&dyn Any> {
297 match self {
298 Lifecycle::Empty => unreachable!(),
299 Lifecycle::Init { element }
300 | Lifecycle::PostLayout { element, .. }
301 | Lifecycle::PostPaint { element, .. } => element.metadata(),
302 }
303 }
304
305 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
306 match self {
307 Lifecycle::PostPaint {
308 element,
309 constraint,
310 bounds,
311 visible_bounds,
312 layout,
313 paint,
314 } => {
315 let mut value = element.debug(*bounds, layout, paint, cx);
316 if let json::Value::Object(map) = &mut value {
317 let mut new_map: crate::json::Map<String, serde_json::Value> =
318 Default::default();
319 if let Some(typ) = map.remove("type") {
320 new_map.insert("type".into(), typ);
321 }
322 new_map.insert("constraint".into(), constraint.to_json());
323 new_map.insert("bounds".into(), bounds.to_json());
324 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
325 new_map.append(map);
326 json::Value::Object(new_map)
327 } else {
328 value
329 }
330 }
331 _ => panic!("invalid element lifecycle state"),
332 }
333 }
334}
335
336impl<T: Element> Default for Lifecycle<T> {
337 fn default() -> Self {
338 Self::Empty
339 }
340}
341
342impl ElementBox {
343 pub fn name(&self) -> Option<&str> {
344 self.0.name.as_deref()
345 }
346
347 pub fn metadata<T: 'static>(&self) -> Option<&T> {
348 let element = unsafe { &*self.0.element.as_ptr() };
349 element.metadata().and_then(|m| m.downcast_ref())
350 }
351}
352
353impl Into<ElementRc> for ElementBox {
354 fn into(self) -> ElementRc {
355 self.0
356 }
357}
358
359impl Deref for ElementBox {
360 type Target = ElementRc;
361
362 fn deref(&self) -> &Self::Target {
363 &self.0
364 }
365}
366
367impl DerefMut for ElementBox {
368 fn deref_mut(&mut self) -> &mut Self::Target {
369 &mut self.0
370 }
371}
372
373impl ElementRc {
374 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
375 self.element.borrow_mut().layout(constraint, cx)
376 }
377
378 pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
379 self.element.borrow_mut().paint(origin, visible_bounds, cx);
380 }
381
382 pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
383 self.element.borrow_mut().dispatch_event(event, cx)
384 }
385
386 pub fn size(&self) -> Vector2F {
387 self.element.borrow().size()
388 }
389
390 pub fn debug(&self, cx: &DebugContext) -> json::Value {
391 let mut value = self.element.borrow().debug(cx);
392
393 if let Some(name) = &self.name {
394 if let json::Value::Object(map) = &mut value {
395 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
396 new_map.insert("name".into(), json::Value::String(name.to_string()));
397 new_map.append(map);
398 return json::Value::Object(new_map);
399 }
400 }
401
402 value
403 }
404
405 pub fn with_metadata<T, F, R>(&self, f: F) -> R
406 where
407 T: 'static,
408 F: FnOnce(Option<&T>) -> R,
409 {
410 let element = self.element.borrow();
411 f(element.metadata().and_then(|m| m.downcast_ref()))
412 }
413}
414
415pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
416 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
417 self.extend(children);
418 }
419
420 fn add_child(&mut self, child: ElementBox) {
421 self.add_children(Some(child));
422 }
423
424 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
425 self.add_children(children);
426 self
427 }
428
429 fn with_child(self, child: ElementBox) -> Self {
430 self.with_children(Some(child))
431 }
432}
433
434impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
435
436fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
437 if max_size.x().is_infinite() && max_size.y().is_infinite() {
438 size
439 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
440 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
441 } else {
442 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
443 }
444}