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                result = Some(size);
 91                Lifecycle::PostLayout {
 92                    element,
 93                    size,
 94                    layout,
 95                }
 96            }
 97        });
 98        result.unwrap()
 99    }
100
101    fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
102        if let Lifecycle::PostLayout {
103            element,
104            size,
105            layout,
106        } = self
107        {
108            element.after_layout(*size, layout, ctx);
109        } else {
110            panic!("invalid element lifecycle state");
111        }
112    }
113
114    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
115        replace_with_or_abort(self, |me| {
116            if let Lifecycle::PostLayout {
117                mut element,
118                size,
119                mut layout,
120            } = me
121            {
122                let bounds = RectF::new(origin, size);
123                let paint = element.paint(bounds, &mut layout, ctx);
124                Lifecycle::PostPaint {
125                    element,
126                    bounds,
127                    layout,
128                    paint,
129                }
130            } else {
131                panic!("invalid element lifecycle state");
132            }
133        });
134    }
135
136    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
137        if let Lifecycle::PostPaint {
138            element,
139            bounds,
140            layout,
141            paint,
142        } = self
143        {
144            element.dispatch_event(event, *bounds, layout, paint, ctx)
145        } else {
146            panic!("invalid element lifecycle state");
147        }
148    }
149
150    fn size(&self) -> Vector2F {
151        match self {
152            Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
153            Lifecycle::PostLayout { size, .. } => *size,
154            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
155        }
156    }
157
158    fn metadata(&self) -> Option<&dyn Any> {
159        match self {
160            Lifecycle::Init { element }
161            | Lifecycle::PostLayout { element, .. }
162            | Lifecycle::PostPaint { element, .. } => element.metadata(),
163        }
164    }
165}
166
167impl ElementBox {
168    pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
169        self.0.layout(constraint, ctx)
170    }
171
172    pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
173        self.0.after_layout(ctx);
174    }
175
176    pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
177        self.0.paint(origin, ctx);
178    }
179
180    pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
181        self.0.dispatch_event(event, ctx)
182    }
183
184    pub fn size(&self) -> Vector2F {
185        self.0.size()
186    }
187
188    pub fn metadata(&self) -> Option<&dyn Any> {
189        self.0.metadata()
190    }
191}