align.rs

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