align.rs

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