elements.rs

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