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