align.rs

  1use crate::{
  2    geometry::{rect::RectF, vector::Vector2F},
  3    json, AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint,
  4    ViewContext,
  5};
  6use json::ToJson;
  7
  8use serde_json::json;
  9
 10pub struct Align<V> {
 11    child: AnyElement<V>,
 12    alignment: Vector2F,
 13}
 14
 15impl<V> Align<V> {
 16    pub fn new(child: AnyElement<V>) -> Self {
 17        Self {
 18            child,
 19            alignment: Vector2F::zero(),
 20        }
 21    }
 22
 23    pub fn top(mut self) -> Self {
 24        self.alignment.set_y(-1.0);
 25        self
 26    }
 27
 28    pub fn bottom(mut self) -> Self {
 29        self.alignment.set_y(1.0);
 30        self
 31    }
 32
 33    pub fn left(mut self) -> Self {
 34        self.alignment.set_x(-1.0);
 35        self
 36    }
 37
 38    pub fn right(mut self) -> Self {
 39        self.alignment.set_x(1.0);
 40        self
 41    }
 42}
 43
 44impl<V: 'static> Element<V> for Align<V> {
 45    type LayoutState = ();
 46    type PaintState = ();
 47
 48    fn layout(
 49        &mut self,
 50        mut constraint: SizeConstraint,
 51        view: &mut V,
 52        cx: &mut LayoutContext<V>,
 53    ) -> (Vector2F, Self::LayoutState) {
 54        let mut size = constraint.max;
 55        constraint.min = Vector2F::zero();
 56        let child_size = self.child.layout(constraint, view, cx);
 57        if size.x().is_infinite() {
 58            size.set_x(child_size.x());
 59        }
 60        if size.y().is_infinite() {
 61            size.set_y(child_size.y());
 62        }
 63        (size, ())
 64    }
 65
 66    fn paint(
 67        &mut self,
 68        scene: &mut SceneBuilder,
 69        bounds: RectF,
 70        visible_bounds: RectF,
 71        _: &mut Self::LayoutState,
 72        view: &mut V,
 73        cx: &mut PaintContext<V>,
 74    ) -> Self::PaintState {
 75        let my_center = bounds.size() / 2.;
 76        let my_target = my_center + my_center * self.alignment;
 77
 78        let child_center = self.child.size() / 2.;
 79        let child_target = child_center + child_center * self.alignment;
 80
 81        self.child.paint(
 82            scene,
 83            bounds.origin() - (child_target - my_target),
 84            visible_bounds,
 85            view,
 86            cx,
 87        );
 88    }
 89
 90    fn rect_for_text_range(
 91        &self,
 92        range_utf16: std::ops::Range<usize>,
 93        _: RectF,
 94        _: RectF,
 95        _: &Self::LayoutState,
 96        _: &Self::PaintState,
 97        view: &V,
 98        cx: &ViewContext<V>,
 99    ) -> Option<RectF> {
100        self.child.rect_for_text_range(range_utf16, view, cx)
101    }
102
103    fn debug(
104        &self,
105        bounds: pathfinder_geometry::rect::RectF,
106        _: &Self::LayoutState,
107        _: &Self::PaintState,
108        view: &V,
109        cx: &ViewContext<V>,
110    ) -> json::Value {
111        json!({
112            "type": "Align",
113            "bounds": bounds.to_json(),
114            "alignment": self.alignment.to_json(),
115            "child": self.child.debug(view, cx),
116        })
117    }
118}