container.rs

  1use pathfinder_geometry::rect::RectF;
  2
  3use crate::{
  4    color::ColorU,
  5    geometry::vector::{vec2f, Vector2F},
  6    scene::{Border, Quad},
  7    AfterLayoutContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
  8    SizeConstraint,
  9};
 10
 11pub struct Container {
 12    margin: Margin,
 13    padding: Padding,
 14    overdraw: Overdraw,
 15    background_color: Option<ColorU>,
 16    border: Border,
 17    corner_radius: f32,
 18    shadow: Option<Shadow>,
 19    child: ElementBox,
 20}
 21
 22impl Container {
 23    pub fn new(child: ElementBox) -> Self {
 24        Self {
 25            margin: Margin::default(),
 26            padding: Padding::default(),
 27            overdraw: Overdraw::default(),
 28            background_color: None,
 29            border: Border::default(),
 30            corner_radius: 0.0,
 31            shadow: None,
 32            child,
 33        }
 34    }
 35
 36    pub fn with_margin_top(mut self, margin: f32) -> Self {
 37        self.margin.top = margin;
 38        self
 39    }
 40
 41    pub fn with_uniform_padding(mut self, padding: f32) -> Self {
 42        self.padding = Padding {
 43            top: padding,
 44            left: padding,
 45            bottom: padding,
 46            right: padding,
 47        };
 48        self
 49    }
 50
 51    pub fn with_padding_right(mut self, padding: f32) -> Self {
 52        self.padding.right = padding;
 53        self
 54    }
 55
 56    pub fn with_background_color(mut self, color: impl Into<ColorU>) -> Self {
 57        self.background_color = Some(color.into());
 58        self
 59    }
 60
 61    pub fn with_border(mut self, border: Border) -> Self {
 62        self.border = border;
 63        self
 64    }
 65
 66    pub fn with_overdraw_bottom(mut self, overdraw: f32) -> Self {
 67        self.overdraw.bottom = overdraw;
 68        self
 69    }
 70
 71    pub fn with_corner_radius(mut self, radius: f32) -> Self {
 72        self.corner_radius = radius;
 73        self
 74    }
 75
 76    pub fn with_shadow(mut self, offset: Vector2F, blur: f32, color: impl Into<ColorU>) -> Self {
 77        self.shadow = Some(Shadow {
 78            offset,
 79            blur,
 80            color: color.into(),
 81        });
 82        self
 83    }
 84
 85    fn margin_size(&self) -> Vector2F {
 86        vec2f(
 87            self.margin.left + self.margin.right,
 88            self.margin.top + self.margin.bottom,
 89        )
 90    }
 91
 92    fn padding_size(&self) -> Vector2F {
 93        vec2f(
 94            self.padding.left + self.padding.right,
 95            self.padding.top + self.padding.bottom,
 96        )
 97    }
 98
 99    fn border_size(&self) -> Vector2F {
100        let mut x = 0.0;
101        if self.border.left {
102            x += self.border.width;
103        }
104        if self.border.right {
105            x += self.border.width;
106        }
107
108        let mut y = 0.0;
109        if self.border.top {
110            y += self.border.width;
111        }
112        if self.border.bottom {
113            y += self.border.width;
114        }
115
116        vec2f(x, y)
117    }
118}
119
120impl Element for Container {
121    type LayoutState = ();
122    type PaintState = ();
123
124    fn layout(
125        &mut self,
126        constraint: SizeConstraint,
127        ctx: &mut LayoutContext,
128    ) -> (Vector2F, Self::LayoutState) {
129        let size_buffer = self.margin_size() + self.padding_size() + self.border_size();
130        let child_constraint = SizeConstraint {
131            min: (constraint.min - size_buffer).max(Vector2F::zero()),
132            max: (constraint.max - size_buffer).max(Vector2F::zero()),
133        };
134        let child_size = self.child.layout(child_constraint, ctx);
135        (child_size + size_buffer, ())
136    }
137
138    fn after_layout(
139        &mut self,
140        _: Vector2F,
141        _: &mut Self::LayoutState,
142        ctx: &mut AfterLayoutContext,
143    ) {
144        self.child.after_layout(ctx);
145    }
146
147    fn paint(
148        &mut self,
149        bounds: RectF,
150        _: &mut Self::LayoutState,
151        ctx: &mut PaintContext,
152    ) -> Self::PaintState {
153        ctx.scene.push_quad(Quad {
154            bounds,
155            background: self.background_color,
156            border: self.border,
157            corner_radius: self.corner_radius,
158        });
159        self.child.paint(bounds.origin(), ctx);
160    }
161
162    fn dispatch_event(
163        &mut self,
164        event: &Event,
165        _: RectF,
166        _: &mut Self::LayoutState,
167        _: &mut Self::PaintState,
168        ctx: &mut EventContext,
169    ) -> bool {
170        self.child.dispatch_event(event, ctx)
171    }
172}
173
174#[derive(Default)]
175pub struct Margin {
176    top: f32,
177    left: f32,
178    bottom: f32,
179    right: f32,
180}
181
182#[derive(Default)]
183pub struct Padding {
184    top: f32,
185    left: f32,
186    bottom: f32,
187    right: f32,
188}
189
190#[derive(Default)]
191pub struct Overdraw {
192    top: f32,
193    left: f32,
194    bottom: f32,
195    right: f32,
196}
197
198#[derive(Default)]
199pub struct Shadow {
200    offset: Vector2F,
201    blur: f32,
202    color: ColorU,
203}