new.rs

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