elements.rs

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