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