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