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