new.rs

  1use crate::{
  2    geometry::{rect::RectF, vector::Vector2F},
  3    json, AfterLayoutContext, DebugContext, Event, EventContext, LayoutContext, PaintContext,
  4    SizeConstraint,
  5};
  6use core::panic;
  7use replace_with::replace_with_or_abort;
  8use std::any::Any;
  9
 10trait AnyElement {
 11    fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F;
 12    fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
 13    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext);
 14    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool;
 15    fn debug(&self, ctx: &DebugContext) -> serde_json::Value;
 16
 17    fn size(&self) -> Vector2F;
 18    fn metadata(&self) -> Option<&dyn Any>;
 19}
 20
 21pub trait Element {
 22    type LayoutState;
 23    type PaintState;
 24
 25    fn layout(
 26        &mut self,
 27        constraint: SizeConstraint,
 28        ctx: &mut LayoutContext,
 29    ) -> (Vector2F, Self::LayoutState);
 30
 31    fn after_layout(
 32        &mut self,
 33        size: Vector2F,
 34        layout: &mut Self::LayoutState,
 35        ctx: &mut AfterLayoutContext,
 36    );
 37
 38    fn paint(
 39        &mut self,
 40        bounds: RectF,
 41        layout: &mut Self::LayoutState,
 42        ctx: &mut PaintContext,
 43    ) -> Self::PaintState;
 44
 45    fn dispatch_event(
 46        &mut self,
 47        event: &Event,
 48        bounds: RectF,
 49        layout: &mut Self::LayoutState,
 50        paint: &mut Self::PaintState,
 51        ctx: &mut EventContext,
 52    ) -> bool;
 53
 54    fn metadata(&self) -> Option<&dyn Any> {
 55        None
 56    }
 57
 58    fn debug(
 59        &self,
 60        bounds: RectF,
 61        layout: &Self::LayoutState,
 62        paint: &Self::PaintState,
 63        ctx: &DebugContext,
 64    ) -> serde_json::Value;
 65
 66    fn boxed(self) -> ElementBox
 67    where
 68        Self: 'static + Sized,
 69    {
 70        ElementBox(Box::new(Lifecycle::Init { element: self }))
 71    }
 72}
 73
 74pub enum Lifecycle<T: Element> {
 75    Init {
 76        element: T,
 77    },
 78    PostLayout {
 79        element: T,
 80        size: Vector2F,
 81        layout: T::LayoutState,
 82    },
 83    PostPaint {
 84        element: T,
 85        bounds: RectF,
 86        layout: T::LayoutState,
 87        paint: T::PaintState,
 88    },
 89}
 90pub struct ElementBox(Box<dyn AnyElement>);
 91
 92impl<T: Element> AnyElement for Lifecycle<T> {
 93    fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
 94        let mut result = None;
 95        replace_with_or_abort(self, |me| match me {
 96            Lifecycle::Init { mut element }
 97            | Lifecycle::PostLayout { mut element, .. }
 98            | Lifecycle::PostPaint { mut element, .. } => {
 99                let (size, layout) = element.layout(constraint, ctx);
100                debug_assert!(size.x().is_finite());
101                debug_assert!(size.y().is_finite());
102
103                result = Some(size);
104                Lifecycle::PostLayout {
105                    element,
106                    size,
107                    layout,
108                }
109            }
110        });
111        result.unwrap()
112    }
113
114    fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
115        if let Lifecycle::PostLayout {
116            element,
117            size,
118            layout,
119        } = self
120        {
121            element.after_layout(*size, layout, ctx);
122        } else {
123            panic!("invalid element lifecycle state");
124        }
125    }
126
127    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
128        replace_with_or_abort(self, |me| {
129            if let Lifecycle::PostLayout {
130                mut element,
131                size,
132                mut layout,
133            } = me
134            {
135                let bounds = RectF::new(origin, size);
136                let paint = element.paint(bounds, &mut layout, ctx);
137                Lifecycle::PostPaint {
138                    element,
139                    bounds,
140                    layout,
141                    paint,
142                }
143            } else {
144                panic!("invalid element lifecycle state");
145            }
146        });
147    }
148
149    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
150        if let Lifecycle::PostPaint {
151            element,
152            bounds,
153            layout,
154            paint,
155        } = self
156        {
157            element.dispatch_event(event, *bounds, layout, paint, ctx)
158        } else {
159            panic!("invalid element lifecycle state");
160        }
161    }
162
163    fn size(&self) -> Vector2F {
164        match self {
165            Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
166            Lifecycle::PostLayout { size, .. } => *size,
167            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
168        }
169    }
170
171    fn metadata(&self) -> Option<&dyn Any> {
172        match self {
173            Lifecycle::Init { element }
174            | Lifecycle::PostLayout { element, .. }
175            | Lifecycle::PostPaint { element, .. } => element.metadata(),
176        }
177    }
178
179    fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
180        match self {
181            Lifecycle::PostPaint {
182                element,
183                bounds,
184                layout,
185                paint,
186            } => element.debug(*bounds, layout, paint, ctx),
187            _ => panic!("invalid element lifecycle state"),
188        }
189    }
190}
191
192impl ElementBox {
193    pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
194        self.0.layout(constraint, ctx)
195    }
196
197    pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
198        self.0.after_layout(ctx);
199    }
200
201    pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
202        self.0.paint(origin, ctx);
203    }
204
205    pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
206        self.0.dispatch_event(event, ctx)
207    }
208
209    pub fn size(&self) -> Vector2F {
210        self.0.size()
211    }
212
213    pub fn metadata(&self) -> Option<&dyn Any> {
214        self.0.metadata()
215    }
216
217    pub fn debug(&self, ctx: &DebugContext) -> json::Value {
218        self.0.debug(ctx)
219    }
220}