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