elements.rs

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