1mod align;
2mod canvas;
3mod clipped;
4mod component;
5mod constrained_box;
6mod container;
7mod empty;
8mod expanded;
9mod flex;
10mod hook;
11mod image;
12mod keystroke_label;
13mod label;
14mod list;
15mod mouse_event_handler;
16mod overlay;
17mod resizable;
18mod stack;
19mod svg;
20mod text;
21mod tooltip;
22mod uniform_list;
23
24pub use self::{
25 align::*, canvas::*, component::*, constrained_box::*, container::*, empty::*, flex::*,
26 hook::*, image::*, keystroke_label::*, label::*, list::*, mouse_event_handler::*, overlay::*,
27 resizable::*, stack::*, svg::*, text::*, tooltip::*, uniform_list::*,
28};
29pub use crate::window::ChildView;
30
31use self::{clipped::Clipped, expanded::Expanded};
32use crate::{
33 geometry::{
34 rect::RectF,
35 vector::{vec2f, Vector2F},
36 },
37 json, Action, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext,
38 WeakViewHandle, WindowContext,
39};
40use anyhow::{anyhow, Result};
41use collections::HashMap;
42use core::panic;
43use json::ToJson;
44use smallvec::SmallVec;
45use std::{any::Any, borrow::Cow, mem, ops::Range};
46
47pub trait Element<V: View>: 'static {
48 type LayoutState;
49 type PaintState;
50
51 fn view_name(&self) -> &'static str {
52 V::ui_name()
53 }
54
55 fn layout(
56 &mut self,
57 constraint: SizeConstraint,
58 view: &mut V,
59 cx: &mut LayoutContext<V>,
60 ) -> (Vector2F, Self::LayoutState);
61
62 fn paint(
63 &mut self,
64 scene: &mut SceneBuilder,
65 bounds: RectF,
66 visible_bounds: RectF,
67 layout: &mut Self::LayoutState,
68 view: &mut V,
69 cx: &mut PaintContext<V>,
70 ) -> Self::PaintState;
71
72 fn rect_for_text_range(
73 &self,
74 range_utf16: Range<usize>,
75 bounds: RectF,
76 visible_bounds: RectF,
77 layout: &Self::LayoutState,
78 paint: &Self::PaintState,
79 view: &V,
80 cx: &ViewContext<V>,
81 ) -> Option<RectF>;
82
83 fn metadata(&self) -> Option<&dyn Any> {
84 None
85 }
86
87 fn debug(
88 &self,
89 bounds: RectF,
90 layout: &Self::LayoutState,
91 paint: &Self::PaintState,
92 view: &V,
93 cx: &ViewContext<V>,
94 ) -> serde_json::Value;
95
96 fn into_any(self) -> AnyElement<V>
97 where
98 Self: 'static + Sized,
99 {
100 AnyElement {
101 state: Box::new(ElementState::Init { element: self }),
102 name: None,
103 }
104 }
105
106 fn into_any_named(self, name: impl Into<Cow<'static, str>>) -> AnyElement<V>
107 where
108 Self: 'static + Sized,
109 {
110 AnyElement {
111 state: Box::new(ElementState::Init { element: self }),
112 name: Some(name.into()),
113 }
114 }
115
116 fn into_root_element(self, cx: &ViewContext<V>) -> RootElement<V>
117 where
118 Self: 'static + Sized,
119 {
120 RootElement {
121 element: self.into_any(),
122 view: cx.handle().downgrade(),
123 }
124 }
125
126 fn constrained(self) -> ConstrainedBox<V>
127 where
128 Self: 'static + Sized,
129 {
130 ConstrainedBox::new(self.into_any())
131 }
132
133 fn aligned(self) -> Align<V>
134 where
135 Self: 'static + Sized,
136 {
137 Align::new(self.into_any())
138 }
139
140 fn clipped(self) -> Clipped<V>
141 where
142 Self: 'static + Sized,
143 {
144 Clipped::new(self.into_any())
145 }
146
147 fn contained(self) -> Container<V>
148 where
149 Self: 'static + Sized,
150 {
151 Container::new(self.into_any())
152 }
153
154 fn expanded(self) -> Expanded<V>
155 where
156 Self: 'static + Sized,
157 {
158 Expanded::new(self.into_any())
159 }
160
161 fn flex(self, flex: f32, expanded: bool) -> FlexItem<V>
162 where
163 Self: 'static + Sized,
164 {
165 FlexItem::new(self.into_any()).flex(flex, expanded)
166 }
167
168 fn flex_float(self) -> FlexItem<V>
169 where
170 Self: 'static + Sized,
171 {
172 FlexItem::new(self.into_any()).float()
173 }
174
175 fn with_tooltip<Tag: 'static>(
176 self,
177 id: usize,
178 text: impl Into<Cow<'static, str>>,
179 action: Option<Box<dyn Action>>,
180 style: TooltipStyle,
181 cx: &mut ViewContext<V>,
182 ) -> Tooltip<V>
183 where
184 Self: 'static + Sized,
185 {
186 Tooltip::new::<Tag>(id, text, action, style, self.into_any(), cx)
187 }
188
189 /// Uses the the given element to calculate resizes for the given tag
190 fn provide_resize_bounds<Tag: 'static>(self) -> BoundsProvider<V, Tag>
191 where
192 Self: 'static + Sized,
193 {
194 BoundsProvider::<_, Tag>::new(self.into_any())
195 }
196
197 /// Calls the given closure with the new size of the element whenever the
198 /// handle is dragged. This will be calculated in relation to the bounds
199 /// provided by the given tag
200 fn resizable<Tag: 'static>(
201 self,
202 side: HandleSide,
203 size: f32,
204 on_resize: impl 'static + FnMut(&mut V, Option<f32>, &mut ViewContext<V>),
205 ) -> Resizable<V>
206 where
207 Self: 'static + Sized,
208 {
209 Resizable::new::<Tag>(self.into_any(), side, size, on_resize)
210 }
211
212 fn mouse<Tag: 'static>(self, region_id: usize) -> MouseEventHandler<V>
213 where
214 Self: Sized,
215 {
216 MouseEventHandler::for_child::<Tag>(self.into_any(), region_id)
217 }
218}
219
220pub trait RenderElement {
221 fn render<V: View>(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
222}
223
224trait AnyElementState<V: View> {
225 fn layout(
226 &mut self,
227 constraint: SizeConstraint,
228 view: &mut V,
229 cx: &mut LayoutContext<V>,
230 ) -> Vector2F;
231
232 fn paint(
233 &mut self,
234 scene: &mut SceneBuilder,
235 origin: Vector2F,
236 visible_bounds: RectF,
237 view: &mut V,
238 cx: &mut ViewContext<V>,
239 );
240
241 fn rect_for_text_range(
242 &self,
243 range_utf16: Range<usize>,
244 view: &V,
245 cx: &ViewContext<V>,
246 ) -> Option<RectF>;
247
248 fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value;
249
250 fn size(&self) -> Vector2F;
251
252 fn metadata(&self) -> Option<&dyn Any>;
253}
254
255enum ElementState<V: View, E: Element<V>> {
256 Empty,
257 Init {
258 element: E,
259 },
260 PostLayout {
261 element: E,
262 constraint: SizeConstraint,
263 size: Vector2F,
264 layout: E::LayoutState,
265 },
266 PostPaint {
267 element: E,
268 constraint: SizeConstraint,
269 bounds: RectF,
270 visible_bounds: RectF,
271 layout: E::LayoutState,
272 paint: E::PaintState,
273 },
274}
275
276impl<V: View, E: Element<V>> AnyElementState<V> for ElementState<V, E> {
277 fn layout(
278 &mut self,
279 constraint: SizeConstraint,
280 view: &mut V,
281 cx: &mut LayoutContext<V>,
282 ) -> Vector2F {
283 let result;
284 *self = match mem::take(self) {
285 ElementState::Empty => unreachable!(),
286 ElementState::Init { mut element }
287 | ElementState::PostLayout { mut element, .. }
288 | ElementState::PostPaint { mut element, .. } => {
289 let (size, layout) = element.layout(constraint, view, cx);
290 debug_assert!(
291 size.x().is_finite(),
292 "Element for {:?} had infinite x size after layout",
293 element.view_name()
294 );
295 debug_assert!(
296 size.y().is_finite(),
297 "Element for {:?} had infinite y size after layout",
298 element.view_name()
299 );
300
301 result = size;
302 ElementState::PostLayout {
303 element,
304 constraint,
305 size,
306 layout,
307 }
308 }
309 };
310 result
311 }
312
313 fn paint(
314 &mut self,
315 scene: &mut SceneBuilder,
316 origin: Vector2F,
317 visible_bounds: RectF,
318 view: &mut V,
319 cx: &mut ViewContext<V>,
320 ) {
321 *self = match mem::take(self) {
322 ElementState::PostLayout {
323 mut element,
324 constraint,
325 size,
326 mut layout,
327 } => {
328 let bounds = RectF::new(origin, size);
329 let paint = element.paint(
330 scene,
331 bounds,
332 visible_bounds,
333 &mut layout,
334 view,
335 &mut PaintContext::new(cx),
336 );
337 ElementState::PostPaint {
338 element,
339 constraint,
340 bounds,
341 visible_bounds,
342 layout,
343 paint,
344 }
345 }
346 ElementState::PostPaint {
347 mut element,
348 constraint,
349 bounds,
350 mut layout,
351 ..
352 } => {
353 let bounds = RectF::new(origin, bounds.size());
354 let paint = element.paint(
355 scene,
356 bounds,
357 visible_bounds,
358 &mut layout,
359 view,
360 &mut PaintContext::new(cx),
361 );
362 ElementState::PostPaint {
363 element,
364 constraint,
365 bounds,
366 visible_bounds,
367 layout,
368 paint,
369 }
370 }
371 ElementState::Empty => panic!("invalid element lifecycle state"),
372 ElementState::Init { .. } => {
373 panic!("invalid element lifecycle state, paint called before layout")
374 }
375 }
376 }
377
378 fn rect_for_text_range(
379 &self,
380 range_utf16: Range<usize>,
381 view: &V,
382 cx: &ViewContext<V>,
383 ) -> Option<RectF> {
384 if let ElementState::PostPaint {
385 element,
386 bounds,
387 visible_bounds,
388 layout,
389 paint,
390 ..
391 } = self
392 {
393 element.rect_for_text_range(
394 range_utf16,
395 *bounds,
396 *visible_bounds,
397 layout,
398 paint,
399 view,
400 cx,
401 )
402 } else {
403 None
404 }
405 }
406
407 fn size(&self) -> Vector2F {
408 match self {
409 ElementState::Empty | ElementState::Init { .. } => {
410 panic!("invalid element lifecycle state")
411 }
412 ElementState::PostLayout { size, .. } => *size,
413 ElementState::PostPaint { bounds, .. } => bounds.size(),
414 }
415 }
416
417 fn metadata(&self) -> Option<&dyn Any> {
418 match self {
419 ElementState::Empty => unreachable!(),
420 ElementState::Init { element }
421 | ElementState::PostLayout { element, .. }
422 | ElementState::PostPaint { element, .. } => element.metadata(),
423 }
424 }
425
426 fn debug(&self, view: &V, cx: &ViewContext<V>) -> serde_json::Value {
427 match self {
428 ElementState::PostPaint {
429 element,
430 constraint,
431 bounds,
432 visible_bounds,
433 layout,
434 paint,
435 } => {
436 let mut value = element.debug(*bounds, layout, paint, view, cx);
437 if let json::Value::Object(map) = &mut value {
438 let mut new_map: crate::json::Map<String, serde_json::Value> =
439 Default::default();
440 if let Some(typ) = map.remove("type") {
441 new_map.insert("type".into(), typ);
442 }
443 new_map.insert("constraint".into(), constraint.to_json());
444 new_map.insert("bounds".into(), bounds.to_json());
445 new_map.insert("visible_bounds".into(), visible_bounds.to_json());
446 new_map.append(map);
447 json::Value::Object(new_map)
448 } else {
449 value
450 }
451 }
452
453 _ => panic!("invalid element lifecycle state"),
454 }
455 }
456}
457
458impl<V: View, E: Element<V>> Default for ElementState<V, E> {
459 fn default() -> Self {
460 Self::Empty
461 }
462}
463
464pub struct AnyElement<V: View> {
465 state: Box<dyn AnyElementState<V>>,
466 name: Option<Cow<'static, str>>,
467}
468
469impl<V: View> AnyElement<V> {
470 pub fn name(&self) -> Option<&str> {
471 self.name.as_deref()
472 }
473
474 pub fn metadata<T: 'static>(&self) -> Option<&T> {
475 self.state
476 .metadata()
477 .and_then(|data| data.downcast_ref::<T>())
478 }
479
480 pub fn layout(
481 &mut self,
482 constraint: SizeConstraint,
483 view: &mut V,
484 cx: &mut LayoutContext<V>,
485 ) -> Vector2F {
486 self.state.layout(constraint, view, cx)
487 }
488
489 pub fn paint(
490 &mut self,
491 scene: &mut SceneBuilder,
492 origin: Vector2F,
493 visible_bounds: RectF,
494 view: &mut V,
495 cx: &mut ViewContext<V>,
496 ) {
497 self.state.paint(scene, origin, visible_bounds, view, cx);
498 }
499
500 pub fn rect_for_text_range(
501 &self,
502 range_utf16: Range<usize>,
503 view: &V,
504 cx: &ViewContext<V>,
505 ) -> Option<RectF> {
506 self.state.rect_for_text_range(range_utf16, view, cx)
507 }
508
509 pub fn size(&self) -> Vector2F {
510 self.state.size()
511 }
512
513 pub fn debug(&self, view: &V, cx: &ViewContext<V>) -> json::Value {
514 let mut value = self.state.debug(view, cx);
515
516 if let Some(name) = &self.name {
517 if let json::Value::Object(map) = &mut value {
518 let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
519 new_map.insert("name".into(), json::Value::String(name.to_string()));
520 new_map.append(map);
521 return json::Value::Object(new_map);
522 }
523 }
524
525 value
526 }
527
528 pub fn with_metadata<T, F, R>(&self, f: F) -> R
529 where
530 T: 'static,
531 F: FnOnce(Option<&T>) -> R,
532 {
533 f(self.state.metadata().and_then(|m| m.downcast_ref()))
534 }
535}
536
537impl<V: View> Element<V> for AnyElement<V> {
538 type LayoutState = ();
539 type PaintState = ();
540
541 fn layout(
542 &mut self,
543 constraint: SizeConstraint,
544 view: &mut V,
545 cx: &mut LayoutContext<V>,
546 ) -> (Vector2F, Self::LayoutState) {
547 let size = self.layout(constraint, view, cx);
548 (size, ())
549 }
550
551 fn paint(
552 &mut self,
553 scene: &mut SceneBuilder,
554 bounds: RectF,
555 visible_bounds: RectF,
556 _: &mut Self::LayoutState,
557 view: &mut V,
558 cx: &mut PaintContext<V>,
559 ) -> Self::PaintState {
560 self.paint(scene, bounds.origin(), visible_bounds, view, cx);
561 }
562
563 fn rect_for_text_range(
564 &self,
565 range_utf16: Range<usize>,
566 _: RectF,
567 _: RectF,
568 _: &Self::LayoutState,
569 _: &Self::PaintState,
570 view: &V,
571 cx: &ViewContext<V>,
572 ) -> Option<RectF> {
573 self.rect_for_text_range(range_utf16, view, cx)
574 }
575
576 fn debug(
577 &self,
578 _: RectF,
579 _: &Self::LayoutState,
580 _: &Self::PaintState,
581 view: &V,
582 cx: &ViewContext<V>,
583 ) -> serde_json::Value {
584 self.debug(view, cx)
585 }
586
587 fn into_any(self) -> AnyElement<V>
588 where
589 Self: Sized,
590 {
591 self
592 }
593}
594
595pub struct RootElement<V: View> {
596 element: AnyElement<V>,
597 view: WeakViewHandle<V>,
598}
599
600impl<V: View> RootElement<V> {
601 pub fn new(element: AnyElement<V>, view: WeakViewHandle<V>) -> Self {
602 Self { element, view }
603 }
604}
605
606pub trait AnyRootElement {
607 fn layout(
608 &mut self,
609 constraint: SizeConstraint,
610 new_parents: &mut HashMap<usize, usize>,
611 views_to_notify_if_ancestors_change: &mut HashMap<usize, SmallVec<[usize; 2]>>,
612 refreshing: bool,
613 cx: &mut WindowContext,
614 ) -> Result<Vector2F>;
615 fn paint(
616 &mut self,
617 scene: &mut SceneBuilder,
618 origin: Vector2F,
619 visible_bounds: RectF,
620 cx: &mut WindowContext,
621 ) -> Result<()>;
622 fn rect_for_text_range(
623 &self,
624 range_utf16: Range<usize>,
625 cx: &WindowContext,
626 ) -> Result<Option<RectF>>;
627 fn debug(&self, cx: &WindowContext) -> Result<serde_json::Value>;
628 fn name(&self) -> Option<&str>;
629}
630
631impl<V: View> AnyRootElement for RootElement<V> {
632 fn layout(
633 &mut self,
634 constraint: SizeConstraint,
635 new_parents: &mut HashMap<usize, usize>,
636 views_to_notify_if_ancestors_change: &mut HashMap<usize, SmallVec<[usize; 2]>>,
637 refreshing: bool,
638 cx: &mut WindowContext,
639 ) -> Result<Vector2F> {
640 let view = self
641 .view
642 .upgrade(cx)
643 .ok_or_else(|| anyhow!("layout called on a root element for a dropped view"))?;
644 view.update(cx, |view, cx| {
645 let mut cx = LayoutContext::new(
646 cx,
647 new_parents,
648 views_to_notify_if_ancestors_change,
649 refreshing,
650 );
651 Ok(self.element.layout(constraint, view, &mut cx))
652 })
653 }
654
655 fn paint(
656 &mut self,
657 scene: &mut SceneBuilder,
658 origin: Vector2F,
659 visible_bounds: RectF,
660 cx: &mut WindowContext,
661 ) -> Result<()> {
662 let view = self
663 .view
664 .upgrade(cx)
665 .ok_or_else(|| anyhow!("paint called on a root element for a dropped view"))?;
666
667 view.update(cx, |view, cx| {
668 self.element.paint(scene, origin, visible_bounds, view, cx);
669 Ok(())
670 })
671 }
672
673 fn rect_for_text_range(
674 &self,
675 range_utf16: Range<usize>,
676 cx: &WindowContext,
677 ) -> Result<Option<RectF>> {
678 let view = self.view.upgrade(cx).ok_or_else(|| {
679 anyhow!("rect_for_text_range called on a root element for a dropped view")
680 })?;
681 let view = view.read(cx);
682 let view_context = ViewContext::immutable(cx, self.view.id());
683 Ok(self
684 .element
685 .rect_for_text_range(range_utf16, view, &view_context))
686 }
687
688 fn debug(&self, cx: &WindowContext) -> Result<serde_json::Value> {
689 let view = self
690 .view
691 .upgrade(cx)
692 .ok_or_else(|| anyhow!("debug called on a root element for a dropped view"))?;
693 let view = view.read(cx);
694 let view_context = ViewContext::immutable(cx, self.view.id());
695 Ok(serde_json::json!({
696 "view_id": self.view.id(),
697 "view_name": V::ui_name(),
698 "view": view.debug_json(cx),
699 "element": self.element.debug(view, &view_context)
700 }))
701 }
702
703 fn name(&self) -> Option<&str> {
704 self.element.name()
705 }
706}
707
708pub trait ParentElement<'a, V: View>: Extend<AnyElement<V>> + Sized {
709 fn add_children<E: Element<V>>(&mut self, children: impl IntoIterator<Item = E>) {
710 self.extend(children.into_iter().map(|child| child.into_any()));
711 }
712
713 fn add_child<D: Element<V>>(&mut self, child: D) {
714 self.extend(Some(child.into_any()));
715 }
716
717 fn with_children<D: Element<V>>(mut self, children: impl IntoIterator<Item = D>) -> Self {
718 self.extend(children.into_iter().map(|child| child.into_any()));
719 self
720 }
721
722 fn with_child<D: Element<V>>(mut self, child: D) -> Self {
723 self.extend(Some(child.into_any()));
724 self
725 }
726}
727
728impl<'a, V: View, T> ParentElement<'a, V> for T where T: Extend<AnyElement<V>> {}
729
730pub fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
731 if max_size.x().is_infinite() && max_size.y().is_infinite() {
732 size
733 } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
734 vec2f(size.x() * max_size.y() / size.y(), max_size.y())
735 } else {
736 vec2f(max_size.x(), size.y() * max_size.x() / size.x())
737 }
738}