elements.rs

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