elements.rs

  1mod align;
  2mod canvas;
  3mod constrained_box;
  4mod container;
  5mod empty;
  6mod event_handler;
  7mod flex;
  8mod label;
  9mod line_box;
 10mod list;
 11mod mouse_event_handler;
 12mod stack;
 13mod svg;
 14mod uniform_list;
 15
 16pub use crate::presenter::ChildView;
 17pub use align::*;
 18pub use canvas::*;
 19pub use constrained_box::*;
 20pub use container::*;
 21pub use empty::*;
 22pub use event_handler::*;
 23pub use flex::*;
 24pub use label::*;
 25pub use line_box::*;
 26pub use list::*;
 27pub use mouse_event_handler::*;
 28pub use stack::*;
 29pub use svg::*;
 30pub use uniform_list::*;
 31
 32use crate::{
 33    geometry::{rect::RectF, vector::Vector2F},
 34    json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
 35};
 36use core::panic;
 37use json::ToJson;
 38use std::{any::Any, borrow::Cow, mem};
 39
 40trait AnyElement {
 41    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
 42    fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext);
 43    fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
 44    fn debug(&self, cx: &DebugContext) -> serde_json::Value;
 45
 46    fn size(&self) -> Vector2F;
 47    fn metadata(&self) -> Option<&dyn Any>;
 48}
 49
 50pub trait Element {
 51    type LayoutState;
 52    type PaintState;
 53
 54    fn layout(
 55        &mut self,
 56        constraint: SizeConstraint,
 57        cx: &mut LayoutContext,
 58    ) -> (Vector2F, Self::LayoutState);
 59
 60    fn paint(
 61        &mut self,
 62        bounds: RectF,
 63        layout: &mut Self::LayoutState,
 64        cx: &mut PaintContext,
 65    ) -> Self::PaintState;
 66
 67    fn dispatch_event(
 68        &mut self,
 69        event: &Event,
 70        bounds: RectF,
 71        layout: &mut Self::LayoutState,
 72        paint: &mut Self::PaintState,
 73        cx: &mut EventContext,
 74    ) -> bool;
 75
 76    fn metadata(&self) -> Option<&dyn Any> {
 77        None
 78    }
 79
 80    fn debug(
 81        &self,
 82        bounds: RectF,
 83        layout: &Self::LayoutState,
 84        paint: &Self::PaintState,
 85        cx: &DebugContext,
 86    ) -> serde_json::Value;
 87
 88    fn boxed(self) -> ElementBox
 89    where
 90        Self: 'static + Sized,
 91    {
 92        ElementBox {
 93            name: None,
 94            element: Box::new(Lifecycle::Init { element: self }),
 95        }
 96    }
 97
 98    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
 99    where
100        Self: 'static + Sized,
101    {
102        ElementBox {
103            name: Some(name.into()),
104            element: Box::new(Lifecycle::Init { element: self }),
105        }
106    }
107}
108
109pub enum Lifecycle<T: Element> {
110    Empty,
111    Init {
112        element: T,
113    },
114    PostLayout {
115        element: T,
116        constraint: SizeConstraint,
117        size: Vector2F,
118        layout: T::LayoutState,
119    },
120    PostPaint {
121        element: T,
122        constraint: SizeConstraint,
123        bounds: RectF,
124        layout: T::LayoutState,
125        paint: T::PaintState,
126    },
127}
128pub struct ElementBox {
129    name: Option<Cow<'static, str>>,
130    element: Box<dyn AnyElement>,
131}
132
133impl<T: Element> AnyElement for Lifecycle<T> {
134    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
135        let result;
136        *self = match mem::take(self) {
137            Lifecycle::Empty => unreachable!(),
138            Lifecycle::Init { mut element }
139            | Lifecycle::PostLayout { mut element, .. }
140            | Lifecycle::PostPaint { mut element, .. } => {
141                let (size, layout) = element.layout(constraint, cx);
142                debug_assert!(size.x().is_finite());
143                debug_assert!(size.y().is_finite());
144
145                result = size;
146                Lifecycle::PostLayout {
147                    element,
148                    constraint,
149                    size,
150                    layout,
151                }
152            }
153        };
154        result
155    }
156
157    fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
158        *self = match mem::take(self) {
159            Lifecycle::PostLayout {
160                mut element,
161                constraint,
162                size,
163                mut layout,
164            } => {
165                let bounds = RectF::new(origin, size);
166                let paint = element.paint(bounds, &mut layout, cx);
167                Lifecycle::PostPaint {
168                    element,
169                    constraint,
170                    bounds,
171                    layout,
172                    paint,
173                }
174            }
175            Lifecycle::PostPaint {
176                mut element,
177                constraint,
178                bounds,
179                mut layout,
180                ..
181            } => {
182                let bounds = RectF::new(origin, bounds.size());
183                let paint = element.paint(bounds, &mut layout, cx);
184                Lifecycle::PostPaint {
185                    element,
186                    constraint,
187                    bounds,
188                    layout,
189                    paint,
190                }
191            }
192            _ => panic!("invalid element lifecycle state"),
193        }
194    }
195
196    fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
197        if let Lifecycle::PostPaint {
198            element,
199            bounds,
200            layout,
201            paint,
202            ..
203        } = self
204        {
205            element.dispatch_event(event, *bounds, layout, paint, cx)
206        } else {
207            panic!("invalid element lifecycle state");
208        }
209    }
210
211    fn size(&self) -> Vector2F {
212        match self {
213            Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
214            Lifecycle::PostLayout { size, .. } => *size,
215            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
216        }
217    }
218
219    fn metadata(&self) -> Option<&dyn Any> {
220        match self {
221            Lifecycle::Empty => unreachable!(),
222            Lifecycle::Init { element }
223            | Lifecycle::PostLayout { element, .. }
224            | Lifecycle::PostPaint { element, .. } => element.metadata(),
225        }
226    }
227
228    fn debug(&self, cx: &DebugContext) -> serde_json::Value {
229        match self {
230            Lifecycle::PostPaint {
231                element,
232                constraint,
233                bounds,
234                layout,
235                paint,
236            } => {
237                let mut value = element.debug(*bounds, layout, paint, cx);
238                if let json::Value::Object(map) = &mut value {
239                    let mut new_map: crate::json::Map<String, serde_json::Value> =
240                        Default::default();
241                    if let Some(typ) = map.remove("type") {
242                        new_map.insert("type".into(), typ);
243                    }
244                    new_map.insert("constraint".into(), constraint.to_json());
245                    new_map.append(map);
246                    json::Value::Object(new_map)
247                } else {
248                    value
249                }
250            }
251            _ => panic!("invalid element lifecycle state"),
252        }
253    }
254}
255
256impl<T: Element> Default for Lifecycle<T> {
257    fn default() -> Self {
258        Self::Empty
259    }
260}
261
262impl ElementBox {
263    pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
264        self.element.layout(constraint, cx)
265    }
266
267    pub fn paint(&mut self, origin: Vector2F, cx: &mut PaintContext) {
268        self.element.paint(origin, cx);
269    }
270
271    pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
272        self.element.dispatch_event(event, cx)
273    }
274
275    pub fn size(&self) -> Vector2F {
276        self.element.size()
277    }
278
279    pub fn metadata(&self) -> Option<&dyn Any> {
280        self.element.metadata()
281    }
282
283    pub fn debug(&self, cx: &DebugContext) -> json::Value {
284        let mut value = self.element.debug(cx);
285
286        if let Some(name) = &self.name {
287            if let json::Value::Object(map) = &mut value {
288                let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
289                new_map.insert("name".into(), json::Value::String(name.to_string()));
290                new_map.append(map);
291                return json::Value::Object(new_map);
292            }
293        }
294
295        value
296    }
297}
298
299pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
300    fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
301        self.extend(children);
302    }
303
304    fn add_child(&mut self, child: ElementBox) {
305        self.add_children(Some(child));
306    }
307
308    fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
309        self.add_children(children);
310        self
311    }
312
313    fn with_child(self, child: ElementBox) -> Self {
314        self.with_children(Some(child))
315    }
316}
317
318impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}