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}
230
231pub struct ElementBox(ElementRc);
232
233#[derive(Clone)]
234pub struct ElementRc {
235 name: Option<Cow<'static, str>>,
236 element: Rc<RefCell<dyn AnyElement>>,
237}
238
239impl<T: Element> AnyElement for Lifecycle<T> {
240 fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
241 let result;
242 *self = match mem::take(self) {
243 Lifecycle::Empty => unreachable!(),
244 Lifecycle::Init { mut element }
245 | Lifecycle::PostLayout { mut element, .. }
246 | Lifecycle::PostPaint { mut element, .. } => {
247 let (size, layout) = element.layout(constraint, cx);
248 debug_assert!(size.x().is_finite());
249 debug_assert!(size.y().is_finite());
250
251 result = size;
252 Lifecycle::PostLayout {
253 element,
254 constraint,
255 size,
256 layout,
257 }
258 }
259 };
260 result
261 }
262
263 fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
264 *self = match mem::take(self) {
265 Lifecycle::PostLayout {
266 mut element,
267 constraint,
268 size,
269 mut layout,
270 } => {
271 let bounds = RectF::new(origin, size);
272 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
273 Lifecycle::PostPaint {
274 element,
275 constraint,
276 bounds,
277 visible_bounds,
278 layout,
279 paint,
280 }
281 }
282 Lifecycle::PostPaint {
283 mut element,
284 constraint,
285 bounds,
286 mut layout,
287 ..
288 } => {
289 let bounds = RectF::new(origin, bounds.size());
290 let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
291 Lifecycle::PostPaint {
292 element,
293 constraint,
294 bounds,
295 visible_bounds,
296 layout,
297 paint,
298 }
299 }
300 Lifecycle::Empty => panic!("invalid element lifecycle state"),
301 Lifecycle::Init { .. } => {
302 panic!("invalid element lifecycle state, paint called before layout")
303 }
304 }
305 }
306
307 fn rect_for_text_range(
308 &self,
309 range_utf16: Range<usize>,
310 cx: &MeasurementContext,
311 ) -> Option<RectF> {
312 if let Lifecycle::PostPaint {
313 element,
314 bounds,
315 visible_bounds,
316 layout,
317 paint,
318 ..
319 } = self
320 {
321 element.rect_for_text_range(range_utf16, *bounds, *visible_bounds, layout, paint, cx)
322 } else {
323 None
324 }
325 }
326
327 fn size(&self) -> Vector2F {
328 match self {
329 Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
330 Lifecycle::PostLayout { size, .. } => *size,
331 Lifecycle::PostPaint { bounds, .. } => bounds.size(),
332 }
333 }
334
335 fn metadata(&self) -> Option<&dyn Any> {
336 match self {
337 Lifecycle::Empty => unreachable!(),
338 Lifecycle::Init { element }
339 | Lifecycle::PostLayout { element, .. }
340 | Lifecycle::PostPaint { element, .. } => element.metadata(),
341 }
342 }
343
344 fn debug(&self, cx: &DebugContext) -> serde_json::Value {
345 match self {
346 Lifecycle::PostPaint {
347 element,
348 constraint,
349 bounds,
350 visible_bounds,
351 layout,
352 paint,
353 } => {
354 let mut value = element.debug(*bounds, layout, paint, cx);
355 if let json::Value::Object(map) = &mut value {
356 let mut new_map: crate::json::Map<String, serde_json::Value> =
357 Default::default();
358 if let Some(typ) = map.remove("type") {
359 new_map.insert("type".into(), typ);
360 }
361 new_map.insert("constraint".into(), constraint.to_json());
362 new_map.insert("bounds".into(), bounds.to_json());
363 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
364 new_map.append(map);
365 json::Value::Object(new_map)
366 } else {
367 value
368 }
369 }
370
371 _ => panic!("invalid element lifecycle state"),
372 }
373 }
374}
375
376impl<T: Element> Default for Lifecycle<T> {
377 fn default() -> Self {
378 Self::Empty
379 }
380}
381
382impl ElementBox {
383 pub fn name(&self) -> Option<&str> {
384 self.0.name.as_deref()
385 }
386
387 pub fn metadata<T: 'static>(&self) -> Option<&T> {
388 let element = unsafe { &*self.0.element.as_ptr() };
389 element.metadata().and_then(|m| m.downcast_ref())
390 }
391}
392
393impl Clone for ElementBox {
394 fn clone(&self) -> Self {
395 ElementBox(self.0.clone())
396 }
397}
398
399impl From<ElementBox> for ElementRc {
400 fn from(val: ElementBox) -> Self {
401 val.0
402 }
403}
404
405impl Deref for ElementBox {
406 type Target = ElementRc;
407
408 fn deref(&self) -> &Self::Target {
409 &self.0
410 }
411}
412
413impl DerefMut for ElementBox {
414 fn deref_mut(&mut self) -> &mut Self::Target {
415 &mut self.0
416 }
417}
418
419impl ElementRc {
420 pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
421 self.element.borrow_mut().layout(constraint, cx)
422 }
423
424 pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
425 self.element.borrow_mut().paint(origin, visible_bounds, cx);
426 }
427
428 pub fn rect_for_text_range(
429 &self,
430 range_utf16: Range<usize>,
431 cx: &MeasurementContext,
432 ) -> Option<RectF> {
433 self.element.borrow().rect_for_text_range(range_utf16, cx)
434 }
435
436 pub fn size(&self) -> Vector2F {
437 self.element.borrow().size()
438 }
439
440 pub fn debug(&self, cx: &DebugContext) -> json::Value {
441 let mut value = self.element.borrow().debug(cx);
442
443 if let Some(name) = &self.name {
444 if let json::Value::Object(map) = &mut value {
445 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
446 new_map.insert("name".into(), json::Value::String(name.to_string()));
447 new_map.append(map);
448 return json::Value::Object(new_map);
449 }
450 }
451
452 value
453 }
454
455 pub fn with_metadata<T, F, R>(&self, f: F) -> R
456 where
457 T: 'static,
458 F: FnOnce(Option<&T>) -> R,
459 {
460 let element = self.element.borrow();
461 f(element.metadata().and_then(|m| m.downcast_ref()))
462 }
463}
464
465pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
466 fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
467 self.extend(children);
468 }
469
470 fn add_child(&mut self, child: ElementBox) {
471 self.add_children(Some(child));
472 }
473
474 fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
475 self.add_children(children);
476 self
477 }
478
479 fn with_child(self, child: ElementBox) -> Self {
480 self.with_children(Some(child))
481 }
482}
483
484impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
485
486pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
487 if max_size.x().is_infinite() && max_size.y().is_infinite() {
488 size
489 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
490 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
491 } else {
492 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
493 }
494}