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}