elements.rs

  1mod align;
  2mod canvas;
  3mod constrained_box;
  4mod container;
  5mod empty;
  6mod event_handler;
  7mod flex;
  8mod hook;
  9mod image;
 10mod label;
 11mod line_box;
 12mod list;
 13mod mouse_event_handler;
 14mod overlay;
 15mod stack;
 16mod svg;
 17mod text;
 18mod uniform_list;
 19
 20pub use self::{
 21    align::*, canvas::*, constrained_box::*, container::*, empty::*, event_handler::*, flex::*,
 22    hook::*, image::*, label::*, line_box::*, list::*, mouse_event_handler::*, overlay::*,
 23    stack::*, svg::*, text::*, uniform_list::*,
 24};
 25pub use crate::presenter::ChildView;
 26use crate::{
 27    geometry::{
 28        rect::RectF,
 29        vector::{vec2f, Vector2F},
 30    },
 31    json, DebugContext, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
 32};
 33use core::panic;
 34use json::ToJson;
 35use std::{
 36    any::Any,
 37    borrow::Cow,
 38    cell::RefCell,
 39    mem,
 40    ops::{Deref, DerefMut},
 41    rc::Rc,
 42};
 43
 44trait AnyElement {
 45    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
 46    fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
 47    fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
 48    fn debug(&self, cx: &DebugContext) -> serde_json::Value;
 49
 50    fn size(&self) -> Vector2F;
 51    fn metadata(&self) -> Option<&dyn Any>;
 52}
 53
 54pub trait Element {
 55    type LayoutState;
 56    type PaintState;
 57
 58    fn layout(
 59        &mut self,
 60        constraint: SizeConstraint,
 61        cx: &mut LayoutContext,
 62    ) -> (Vector2F, Self::LayoutState);
 63
 64    fn paint(
 65        &mut self,
 66        bounds: RectF,
 67        visible_bounds: RectF,
 68        layout: &mut Self::LayoutState,
 69        cx: &mut PaintContext,
 70    ) -> Self::PaintState;
 71
 72    fn dispatch_event(
 73        &mut self,
 74        event: &Event,
 75        bounds: RectF,
 76        layout: &mut Self::LayoutState,
 77        paint: &mut Self::PaintState,
 78        cx: &mut EventContext,
 79    ) -> bool;
 80
 81    fn metadata(&self) -> Option<&dyn Any> {
 82        None
 83    }
 84
 85    fn debug(
 86        &self,
 87        bounds: RectF,
 88        layout: &Self::LayoutState,
 89        paint: &Self::PaintState,
 90        cx: &DebugContext,
 91    ) -> serde_json::Value;
 92
 93    fn boxed(self) -> ElementBox
 94    where
 95        Self: 'static + Sized,
 96    {
 97        ElementBox(ElementRc {
 98            name: None,
 99            element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
100        })
101    }
102
103    fn named(self, name: impl Into<Cow<'static, str>>) -> ElementBox
104    where
105        Self: 'static + Sized,
106    {
107        ElementBox(ElementRc {
108            name: Some(name.into()),
109            element: Rc::new(RefCell::new(Lifecycle::Init { element: self })),
110        })
111    }
112}
113
114pub enum Lifecycle<T: Element> {
115    Empty,
116    Init {
117        element: T,
118    },
119    PostLayout {
120        element: T,
121        constraint: SizeConstraint,
122        size: Vector2F,
123        layout: T::LayoutState,
124    },
125    PostPaint {
126        element: T,
127        constraint: SizeConstraint,
128        bounds: RectF,
129        layout: T::LayoutState,
130        paint: T::PaintState,
131    },
132}
133pub struct ElementBox(ElementRc);
134
135#[derive(Clone)]
136pub struct ElementRc {
137    name: Option<Cow<'static, str>>,
138    element: Rc<RefCell<dyn AnyElement>>,
139}
140
141impl<T: Element> AnyElement for Lifecycle<T> {
142    fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
143        let result;
144        *self = match mem::take(self) {
145            Lifecycle::Empty => unreachable!(),
146            Lifecycle::Init { mut element }
147            | Lifecycle::PostLayout { mut element, .. }
148            | Lifecycle::PostPaint { mut element, .. } => {
149                let (size, layout) = element.layout(constraint, cx);
150                debug_assert!(size.x().is_finite());
151                debug_assert!(size.y().is_finite());
152
153                result = size;
154                Lifecycle::PostLayout {
155                    element,
156                    constraint,
157                    size,
158                    layout,
159                }
160            }
161        };
162        result
163    }
164
165    fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
166        *self = match mem::take(self) {
167            Lifecycle::PostLayout {
168                mut element,
169                constraint,
170                size,
171                mut layout,
172            } => {
173                let bounds = RectF::new(origin, size);
174                let visible_bounds = visible_bounds
175                    .intersection(bounds)
176                    .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
177                let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
178                Lifecycle::PostPaint {
179                    element,
180                    constraint,
181                    bounds,
182                    layout,
183                    paint,
184                }
185            }
186            Lifecycle::PostPaint {
187                mut element,
188                constraint,
189                bounds,
190                mut layout,
191                ..
192            } => {
193                let bounds = RectF::new(origin, bounds.size());
194                let visible_bounds = visible_bounds
195                    .intersection(bounds)
196                    .unwrap_or_else(|| RectF::new(bounds.origin(), Vector2F::default()));
197                let paint = element.paint(bounds, visible_bounds, &mut layout, cx);
198                Lifecycle::PostPaint {
199                    element,
200                    constraint,
201                    bounds,
202                    layout,
203                    paint,
204                }
205            }
206            _ => panic!("invalid element lifecycle state"),
207        }
208    }
209
210    fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
211        if let Lifecycle::PostPaint {
212            element,
213            bounds,
214            layout,
215            paint,
216            ..
217        } = self
218        {
219            element.dispatch_event(event, *bounds, layout, paint, cx)
220        } else {
221            panic!("invalid element lifecycle state");
222        }
223    }
224
225    fn size(&self) -> Vector2F {
226        match self {
227            Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
228            Lifecycle::PostLayout { size, .. } => *size,
229            Lifecycle::PostPaint { bounds, .. } => bounds.size(),
230        }
231    }
232
233    fn metadata(&self) -> Option<&dyn Any> {
234        match self {
235            Lifecycle::Empty => unreachable!(),
236            Lifecycle::Init { element }
237            | Lifecycle::PostLayout { element, .. }
238            | Lifecycle::PostPaint { element, .. } => element.metadata(),
239        }
240    }
241
242    fn debug(&self, cx: &DebugContext) -> serde_json::Value {
243        match self {
244            Lifecycle::PostPaint {
245                element,
246                constraint,
247                bounds,
248                layout,
249                paint,
250            } => {
251                let mut value = element.debug(*bounds, layout, paint, cx);
252                if let json::Value::Object(map) = &mut value {
253                    let mut new_map: crate::json::Map<String, serde_json::Value> =
254                        Default::default();
255                    if let Some(typ) = map.remove("type") {
256                        new_map.insert("type".into(), typ);
257                    }
258                    new_map.insert("constraint".into(), constraint.to_json());
259                    new_map.append(map);
260                    json::Value::Object(new_map)
261                } else {
262                    value
263                }
264            }
265            _ => panic!("invalid element lifecycle state"),
266        }
267    }
268}
269
270impl<T: Element> Default for Lifecycle<T> {
271    fn default() -> Self {
272        Self::Empty
273    }
274}
275
276impl ElementBox {
277    pub fn metadata<T: 'static>(&self) -> Option<&T> {
278        let element = unsafe { &*self.0.element.as_ptr() };
279        element.metadata().and_then(|m| m.downcast_ref())
280    }
281}
282
283impl Into<ElementRc> for ElementBox {
284    fn into(self) -> ElementRc {
285        self.0
286    }
287}
288
289impl Deref for ElementBox {
290    type Target = ElementRc;
291
292    fn deref(&self) -> &Self::Target {
293        &self.0
294    }
295}
296
297impl DerefMut for ElementBox {
298    fn deref_mut(&mut self) -> &mut Self::Target {
299        &mut self.0
300    }
301}
302
303impl ElementRc {
304    pub fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F {
305        self.element.borrow_mut().layout(constraint, cx)
306    }
307
308    pub fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext) {
309        self.element.borrow_mut().paint(origin, visible_bounds, cx);
310    }
311
312    pub fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool {
313        self.element.borrow_mut().dispatch_event(event, cx)
314    }
315
316    pub fn size(&self) -> Vector2F {
317        self.element.borrow().size()
318    }
319
320    pub fn debug(&self, cx: &DebugContext) -> json::Value {
321        let mut value = self.element.borrow().debug(cx);
322
323        if let Some(name) = &self.name {
324            if let json::Value::Object(map) = &mut value {
325                let mut new_map: crate::json::Map<String, serde_json::Value> = Default::default();
326                new_map.insert("name".into(), json::Value::String(name.to_string()));
327                new_map.append(map);
328                return json::Value::Object(new_map);
329            }
330        }
331
332        value
333    }
334
335    pub fn with_metadata<T, F, R>(&self, f: F) -> R
336    where
337        T: 'static,
338        F: FnOnce(Option<&T>) -> R,
339    {
340        let element = self.element.borrow();
341        f(element.metadata().and_then(|m| m.downcast_ref()))
342    }
343}
344
345pub trait ParentElement<'a>: Extend<ElementBox> + Sized {
346    fn add_children(&mut self, children: impl IntoIterator<Item = ElementBox>) {
347        self.extend(children);
348    }
349
350    fn add_child(&mut self, child: ElementBox) {
351        self.add_children(Some(child));
352    }
353
354    fn with_children(mut self, children: impl IntoIterator<Item = ElementBox>) -> Self {
355        self.add_children(children);
356        self
357    }
358
359    fn with_child(self, child: ElementBox) -> Self {
360        self.with_children(Some(child))
361    }
362}
363
364impl<'a, T> ParentElement<'a> for T where T: Extend<ElementBox> {}
365
366fn constrain_size_preserving_aspect_ratio(max_size: Vector2F, size: Vector2F) -> Vector2F {
367    if max_size.x().is_infinite() && max_size.y().is_infinite() {
368        size
369    } else if max_size.x().is_infinite() || max_size.x() / max_size.y() > size.x() / size.y() {
370        vec2f(size.x() * max_size.y() / size.y(), max_size.y())
371    } else {
372        vec2f(max_size.x(), size.y() * max_size.x() / size.x())
373    }
374}