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