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 json::ToJson;
  8use replace_with::replace_with_or_abort;
  9use std::{any::Any, borrow::Cow};
 10
 11trait AnyElement {
 12    fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F;
 13    fn after_layout(&mut self, _: &mut AfterLayoutContext) {}
 14    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext);
 15    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool;
 16    fn debug(&self, ctx: &DebugContext) -> serde_json::Value;
 17
 18    fn size(&self) -> Vector2F;
 19    fn metadata(&self) -> Option<&dyn Any>;
 20}
 21
 22pub trait Element {
 23    type LayoutState;
 24    type PaintState;
 25
 26    fn layout(
 27        &mut self,
 28        constraint: SizeConstraint,
 29        ctx: &mut LayoutContext,
 30    ) -> (Vector2F, Self::LayoutState);
 31
 32    fn after_layout(
 33        &mut self,
 34        size: Vector2F,
 35        layout: &mut Self::LayoutState,
 36        ctx: &mut AfterLayoutContext,
 37    );
 38
 39    fn paint(
 40        &mut self,
 41        bounds: RectF,
 42        layout: &mut Self::LayoutState,
 43        ctx: &mut PaintContext,
 44    ) -> Self::PaintState;
 45
 46    fn dispatch_event(
 47        &mut self,
 48        event: &Event,
 49        bounds: RectF,
 50        layout: &mut Self::LayoutState,
 51        paint: &mut Self::PaintState,
 52        ctx: &mut EventContext,
 53    ) -> bool;
 54
 55    fn metadata(&self) -> Option<&dyn Any> {
 56        None
 57    }
 58
 59    fn debug(
 60        &self,
 61        bounds: RectF,
 62        layout: &Self::LayoutState,
 63        paint: &Self::PaintState,
 64        ctx: &DebugContext,
 65    ) -> serde_json::Value;
 66
 67    fn boxed(self) -> ElementBox
 68    where
 69        Self: 'static + Sized,
 70    {
 71        ElementBox {
 72            name: None,
 73            element: Box::new(Lifecycle::Init { element: self }),
 74        }
 75    }
 76
 77    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
 78    where
 79        Self: 'static + Sized,
 80    {
 81        ElementBox {
 82            name: Some(name.into()),
 83            element: Box::new(Lifecycle::Init { element: self }),
 84        }
 85    }
 86}
 87
 88pub enum Lifecycle<T: Element> {
 89    Init {
 90        element: T,
 91    },
 92    PostLayout {
 93        element: T,
 94        constraint: SizeConstraint,
 95        size: Vector2F,
 96        layout: T::LayoutState,
 97    },
 98    PostPaint {
 99        element: T,
100        constraint: SizeConstraint,
101        bounds: RectF,
102        layout: T::LayoutState,
103        paint: T::PaintState,
104    },
105}
106pub struct ElementBox {
107    name: Option<Cow<'static, str>>,
108    element: Box<dyn AnyElement>,
109}
110
111impl<T: Element> AnyElement for Lifecycle<T> {
112    fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
113        let mut result = None;
114        replace_with_or_abort(self, |me| match me {
115            Lifecycle::Init { mut element }
116            | Lifecycle::PostLayout { mut element, .. }
117            | Lifecycle::PostPaint { mut element, .. } => {
118                let (size, layout) = element.layout(constraint, ctx);
119                debug_assert!(size.x().is_finite());
120                debug_assert!(size.y().is_finite());
121
122                result = Some(size);
123                Lifecycle::PostLayout {
124                    element,
125                    constraint,
126                    size,
127                    layout,
128                }
129            }
130        });
131        result.unwrap()
132    }
133
134    fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
135        if let Lifecycle::PostLayout {
136            element,
137            size,
138            layout,
139            ..
140        } = self
141        {
142            element.after_layout(*size, layout, ctx);
143        } else {
144            panic!("invalid element lifecycle state");
145        }
146    }
147
148    fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
149        replace_with_or_abort(self, |me| {
150            if let Lifecycle::PostLayout {
151                mut element,
152                constraint,
153                size,
154                mut layout,
155            } = me
156            {
157                let bounds = RectF::new(origin, size);
158                let paint = element.paint(bounds, &mut layout, ctx);
159                Lifecycle::PostPaint {
160                    element,
161                    constraint,
162                    bounds,
163                    layout,
164                    paint,
165                }
166            } else {
167                panic!("invalid element lifecycle state");
168            }
169        });
170    }
171
172    fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
173        if let Lifecycle::PostPaint {
174            element,
175            bounds,
176            layout,
177            paint,
178            ..
179        } = self
180        {
181            element.dispatch_event(event, *bounds, layout, paint, ctx)
182        } else {
183            panic!("invalid element lifecycle state");
184        }
185    }
186
187    fn size(&self) -> Vector2F {
188        match self {
189            Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
190            Lifecycle::PostLayout { size, .. } => *size,
191            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
192        }
193    }
194
195    fn metadata(&self) -> Option<&dyn Any> {
196        match self {
197            Lifecycle::Init { element }
198            | Lifecycle::PostLayout { element, .. }
199            | Lifecycle::PostPaint { element, .. } => element.metadata(),
200        }
201    }
202
203    fn debug(&self, ctx: &DebugContext) -> serde_json::Value {
204        match self {
205            Lifecycle::PostPaint {
206                element,
207                constraint,
208                bounds,
209                layout,
210                paint,
211            } => {
212                let mut value = element.debug(*bounds, layout, paint, ctx);
213                if let json::Value::Object(map) = &mut value {
214                    let mut new_map: crate::json::Map<String, serde_json::Value> =
215                        Default::default();
216                    if let Some(typ) = map.remove("type") {
217                        new_map.insert("type".into(), typ);
218                    }
219                    new_map.insert("constraint".into(), constraint.to_json());
220                    new_map.append(map);
221                    json::Value::Object(new_map)
222                } else {
223                    value
224                }
225            }
226            _ => panic!("invalid element lifecycle state"),
227        }
228    }
229}
230
231impl ElementBox {
232    pub fn layout(&mut self, constraint: SizeConstraint, ctx: &mut LayoutContext) -> Vector2F {
233        self.element.layout(constraint, ctx)
234    }
235
236    pub fn after_layout(&mut self, ctx: &mut AfterLayoutContext) {
237        self.element.after_layout(ctx);
238    }
239
240    pub fn paint(&mut self, origin: Vector2F, ctx: &mut PaintContext) {
241        self.element.paint(origin, ctx);
242    }
243
244    pub fn dispatch_event(&mut self, event: &Event, ctx: &mut EventContext) -> bool {
245        self.element.dispatch_event(event, ctx)
246    }
247
248    pub fn size(&self) -> Vector2F {
249        self.element.size()
250    }
251
252    pub fn metadata(&self) -> Option<&dyn Any> {
253        self.element.metadata()
254    }
255
256    pub fn debug(&self, ctx: &DebugContext) -> json::Value {
257        let mut value = self.element.debug(ctx);
258
259        if let Some(name) = &self.name {
260            if let json::Value::Object(map) = &mut value {
261                let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
262                new_map.insert("name".into(), json::Value::String(name.to_string()));
263                new_map.append(map);
264                return json::Value::Object(new_map);
265            }
266        }
267
268        value
269    }
270}