elements.rs

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