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