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