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, borrow::Cow};
  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 {
 71            name: None,
 72            element: Box::new(Lifecycle::Init { element: self }),
 73        }
 74    }
 75
 76    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
 77    where
 78        Self: 'static + Sized,
 79    {
 80        ElementBox {
 81            name: Some(name.into()),
 82            element: Box::new(Lifecycle::Init { element: self }),
 83        }
 84    }
 85}
 86
 87pub enum Lifecycle<T: Element> {
 88    Init {
 89        element: T,
 90    },
 91    PostLayout {
 92        element: T,
 93        size: Vector2F,
 94        layout: T::LayoutState,
 95    },
 96    PostPaint {
 97        element: T,
 98        bounds: RectF,
 99        layout: T::LayoutState,
100        paint: T::PaintState,
101    },
102}
103pub struct ElementBox {
104    name: Option<Cow<'static, str>>,
105    element: Box<dyn AnyElement>,
106}
107
108impl<T: Element> AnyElement for Lifecycle<T> {
109    fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
110        let mut result = None;
111        replace_with_or_abort(self, |me| match me {
112            Lifecycle::Init { mut element }
113            | Lifecycle::PostLayout { mut element, .. }
114            | Lifecycle::PostPaint { mut element, .. } => {
115                let (size, layout) = element.layout(constraint, ctx);
116                debug_assert!(size.x().is_finite());
117                debug_assert!(size.y().is_finite());
118
119                result = Some(size);
120                Lifecycle::PostLayout {
121                    element,
122                    size,
123                    layout,
124                }
125            }
126        });
127        result.unwrap()
128    }
129
130    fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
131        if let Lifecycle::PostLayout {
132            element,
133            size,
134            layout,
135        } = self
136        {
137            element.after_layout(*size, layout, ctx);
138        } else {
139            panic!("invalid element lifecycle state");
140        }
141    }
142
143    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
144        replace_with_or_abort(self, |me| {
145            if let Lifecycle::PostLayout {
146                mut element,
147                size,
148                mut layout,
149            } = me
150            {
151                let bounds = RectF::new(origin, size);
152                let paint = element.paint(bounds, &mut layout, ctx);
153                Lifecycle::PostPaint {
154                    element,
155                    bounds,
156                    layout,
157                    paint,
158                }
159            } else {
160                panic!("invalid element lifecycle state");
161            }
162        });
163    }
164
165    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
166        if let Lifecycle::PostPaint {
167            element,
168            bounds,
169            layout,
170            paint,
171        } = self
172        {
173            element.dispatch_event(event, *bounds, layout, paint, ctx)
174        } else {
175            panic!("invalid element lifecycle state");
176        }
177    }
178
179    fn size(&self) -> Vector2F {
180        match self {
181            Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
182            Lifecycle::PostLayout { size, .. } => *size,
183            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
184        }
185    }
186
187    fn metadata(&self) -> Option<&dyn Any> {
188        match self {
189            Lifecycle::Init { element }
190            | Lifecycle::PostLayout { element, .. }
191            | Lifecycle::PostPaint { element, .. } => element.metadata(),
192        }
193    }
194
195    fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
196        match self {
197            Lifecycle::PostPaint {
198                element,
199                bounds,
200                layout,
201                paint,
202            } => element.debug(*bounds, layout, paint, ctx),
203            _ => panic!("invalid element lifecycle state"),
204        }
205    }
206}
207
208impl ElementBox {
209    pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
210        self.element.layout(constraint, ctx)
211    }
212
213    pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
214        self.element.after_layout(ctx);
215    }
216
217    pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
218        self.element.paint(origin, ctx);
219    }
220
221    pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
222        self.element.dispatch_event(event, ctx)
223    }
224
225    pub fn size(&self) -> Vector2F {
226        self.element.size()
227    }
228
229    pub fn metadata(&self) -> Option<&dyn Any> {
230        self.element.metadata()
231    }
232
233    pub fn debug(&self, ctx: &DebugContext) -> json::Value {
234        let mut value = self.element.debug(ctx);
235
236        if let Some(name) = &self.name {
237            if let json::Value::Object(map) = &mut value {
238                let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
239                new_map.insert("name".into(), json::Value::String(name.to_string()));
240                new_map.append(map);
241                return json::Value::Object(new_map);
242            }
243        }
244
245        value
246    }
247}