elements.rs

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