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