1use cassowary::{Variable, Constraint, Term, Expression};
2use cassowary::WeightedRelation::*;
3use cassowary::strength::*;
4
5use euclid::{TypedPoint2D, TypedSize2D};
6
7use super::{LAYOUT, LayoutRef, LayoutVars, Size, Point};
8
9pub fn width(width: f32) -> WidgetConstraintBuilder {
10 WidgetConstraint::Width(width).builder(REQUIRED)
11}
12pub fn height(height: f32) -> WidgetConstraintBuilder {
13 WidgetConstraint::Height(height).builder(REQUIRED)
14}
15pub fn min_width(width: f32) -> WidgetConstraintBuilder {
16 WidgetConstraint::MinWidth(width).builder(REQUIRED)
17}
18pub fn min_height(height: f32) -> WidgetConstraintBuilder {
19 WidgetConstraint::MinHeight(height).builder(REQUIRED)
20}
21pub fn size<T>(size: TypedSize2D<f32, T>) -> WidgetConstraintBuilder {
22 WidgetConstraint::Size(size.to_untyped()).builder(REQUIRED)
23}
24pub fn min_size<T>(size: TypedSize2D<f32, T>) -> WidgetConstraintBuilder {
25 WidgetConstraint::MinSize(size.to_untyped()).builder(REQUIRED)
26}
27pub fn aspect_ratio(aspect_ratio: f32) -> WidgetConstraintBuilder {
28 WidgetConstraint::AspectRatio(aspect_ratio).builder(REQUIRED)
29}
30pub fn shrink() -> WidgetConstraintBuilder {
31 WidgetConstraint::Shrink.builder(WEAK)
32}
33pub fn shrink_horizontal() -> WidgetConstraintBuilder {
34 WidgetConstraint::ShrinkHorizontal.builder(WEAK)
35}
36pub fn shrink_vertical() -> WidgetConstraintBuilder {
37 WidgetConstraint::ShrinkVertical.builder(WEAK)
38}
39pub fn top_left<T>(point: TypedPoint2D<f32, T>) -> WidgetConstraintBuilder {
40 WidgetConstraint::TopLeft(point.to_untyped()).builder(REQUIRED)
41}
42pub fn center<T: LayoutRef>(widget: &T) -> WidgetConstraintBuilder {
43 WidgetConstraint::Center(widget.layout_ref().clone()).builder(REQUIRED)
44}
45pub fn center_horizontal<T: LayoutRef>(widget: &T) -> WidgetConstraintBuilder {
46 let widget = widget.layout_ref();
47 WidgetConstraint::CenterHorizontal(widget.left, widget.right).builder(REQUIRED)
48}
49pub fn center_vertical<T: LayoutRef>(widget: &T) -> WidgetConstraintBuilder {
50 let widget = widget.layout_ref();
51 WidgetConstraint::CenterVertical(widget.top, widget.bottom).builder(REQUIRED)
52}
53
54pub fn align_top<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
55 let widget = widget.layout_ref();
56 PaddableConstraint::AlignTop(widget.top).builder(REQUIRED)
57}
58pub fn align_bottom<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
59 let widget = widget.layout_ref();
60 PaddableConstraint::AlignBottom(widget.bottom).builder(REQUIRED)
61}
62pub fn align_left<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
63 let widget = widget.layout_ref();
64 PaddableConstraint::AlignLeft(widget.left).builder(REQUIRED)
65}
66pub fn align_right<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
67 let widget = widget.layout_ref();
68 PaddableConstraint::AlignRight(widget.right).builder(REQUIRED)
69}
70
71pub fn align_above<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
72 let widget = widget.layout_ref();
73 PaddableConstraint::AlignAbove(widget.top).builder(REQUIRED)
74}
75pub fn align_below<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
76 let widget = widget.layout_ref();
77 PaddableConstraint::AlignBelow(widget.bottom).builder(REQUIRED)
78}
79pub fn align_to_left_of<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
80 let widget = widget.layout_ref();
81 PaddableConstraint::AlignToLeftOf(widget.left).builder(REQUIRED)
82}
83pub fn align_to_right_of<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
84 let widget = widget.layout_ref();
85 PaddableConstraint::AlignToRightOf(widget.right).builder(REQUIRED)
86}
87
88pub fn above<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
89 let widget = widget.layout_ref();
90 PaddableConstraint::Above(widget.top).builder(REQUIRED)
91}
92pub fn below<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
93 let widget = widget.layout_ref();
94 PaddableConstraint::Below(widget.bottom).builder(REQUIRED)
95}
96pub fn to_left_of<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
97 let widget = widget.layout_ref();
98 PaddableConstraint::ToLeftOf(widget.left).builder(REQUIRED)
99}
100pub fn to_right_of<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
101 let widget = widget.layout_ref();
102 PaddableConstraint::ToRightOf(widget.right).builder(REQUIRED)
103}
104
105pub fn bound_left<T: LayoutRef>(outer: &T) -> PaddableConstraintBuilder {
106 let outer = outer.layout_ref();
107 PaddableConstraint::BoundLeft(outer.left).builder(REQUIRED)
108}
109pub fn bound_top<T: LayoutRef>(outer: &T) -> PaddableConstraintBuilder {
110 let outer = outer.layout_ref();
111 PaddableConstraint::BoundTop(outer.top).builder(REQUIRED)
112}
113pub fn bound_right<T: LayoutRef>(outer: &T) -> PaddableConstraintBuilder {
114 let outer = outer.layout_ref();
115 PaddableConstraint::BoundRight(outer.right).builder(REQUIRED)
116}
117pub fn bound_bottom<T: LayoutRef>(outer: &T) -> PaddableConstraintBuilder {
118 let outer = outer.layout_ref();
119 PaddableConstraint::BoundBottom(outer.bottom).builder(REQUIRED)
120}
121
122pub fn bound_by<T: LayoutRef>(outer: &T) -> PaddableConstraintBuilder {
123 let outer = outer.layout_ref();
124 PaddableConstraint::BoundBy(outer.clone()).builder(REQUIRED)
125}
126
127pub fn match_layout<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
128 let widget = widget.layout_ref();
129 PaddableConstraint::MatchLayout(widget.clone()).builder(REQUIRED)
130}
131pub fn match_width<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
132 let widget = widget.layout_ref();
133 PaddableConstraint::MatchWidth(widget.width).builder(REQUIRED)
134}
135pub fn match_height<T: LayoutRef>(widget: &T) -> PaddableConstraintBuilder {
136 let widget = widget.layout_ref();
137 PaddableConstraint::MatchHeight(widget.height).builder(REQUIRED)
138}
139
140#[derive(Debug, Copy, Clone)]
141pub enum WidgetConstraint {
142 Width(f32),
143 Height(f32),
144 MinWidth(f32),
145 MinHeight(f32),
146 Size(Size),
147 MinSize(Size),
148 AspectRatio(f32),
149 Shrink,
150 ShrinkHorizontal,
151 ShrinkVertical,
152 TopLeft(Point),
153 Center(LayoutVars),
154 CenterHorizontal(Variable, Variable),
155 CenterVertical(Variable, Variable),
156}
157
158#[derive(Debug, Copy, Clone)]
159pub enum PaddableConstraint {
160 AlignTop(Variable),
161 AlignBottom(Variable),
162 AlignLeft(Variable),
163 AlignRight(Variable),
164 AlignAbove(Variable),
165 AlignBelow(Variable),
166 AlignToLeftOf(Variable),
167 AlignToRightOf(Variable),
168 Above(Variable),
169 Below(Variable),
170 ToLeftOf(Variable),
171 ToRightOf(Variable),
172 BoundLeft(Variable),
173 BoundTop(Variable),
174 BoundRight(Variable),
175 BoundBottom(Variable),
176 BoundBy(LayoutVars),
177 MatchLayout(LayoutVars),
178 MatchWidth(Variable),
179 MatchHeight(Variable),
180}
181
182impl WidgetConstraint {
183 pub fn builder(self, default_strength: f64) -> WidgetConstraintBuilder {
184 WidgetConstraintBuilder {
185 constraint: self,
186 strength: default_strength,
187 }
188 }
189}
190
191impl PaddableConstraint {
192 pub fn builder(self, default_strength: f64) -> PaddableConstraintBuilder {
193 PaddableConstraintBuilder {
194 constraint: self,
195 strength: default_strength,
196 padding: 0.0,
197 }
198 }
199}
200
201#[derive(Debug, Copy, Clone)]
202pub struct WidgetConstraintBuilder {
203 constraint: WidgetConstraint,
204 strength: f64,
205}
206
207impl WidgetConstraintBuilder {
208 pub fn strength(mut self, strength: f64) -> Self {
209 self.strength = strength;
210 self
211 }
212}
213
214#[derive(Debug, Copy, Clone)]
215pub struct PaddableConstraintBuilder {
216 constraint: PaddableConstraint,
217 strength: f64,
218 padding: f32,
219}
220
221impl PaddableConstraintBuilder {
222 pub fn strength(mut self, strength: f64) -> Self {
223 self.strength = strength;
224 self
225 }
226 pub fn padding(mut self, padding: f32) -> Self {
227 self.padding = padding;
228 self
229 }
230}
231
232pub trait ConstraintBuilder {
233 fn build(&self, widget: &LayoutVars) -> Vec<Constraint>;
234}
235
236impl ConstraintBuilder for Constraint {
237 fn build(&self, widget: &LayoutVars) -> Vec<Constraint> {
238 let ref terms = self.expr().terms;
239 let mut vars_replaced = false;
240 let mut new_terms = Vec::new();
241 for term in terms {
242 let var = if term.variable == LAYOUT.left {
243 widget.left
244 } else if term.variable == LAYOUT.top {
245 widget.top
246 } else if term.variable == LAYOUT.right {
247 widget.right
248 } else if term.variable == LAYOUT.bottom {
249 widget.bottom
250 } else if term.variable == LAYOUT.width {
251 widget.width
252 } else if term.variable == LAYOUT.height {
253 widget.height
254 } else {
255 term.variable
256 };
257 if var != term.variable {
258 vars_replaced = true;
259 }
260 new_terms.push(Term {
261 variable: var,
262 coefficient: term.coefficient,
263 });
264 }
265 if vars_replaced {
266 let expr = Expression::new(new_terms, self.expr().constant);
267 let cons = Constraint::new(expr, self.op(), self.strength());
268 vec![ cons ]
269 } else {
270 vec![ self.clone() ]
272 }
273 }
274}
275
276impl ConstraintBuilder for WidgetConstraintBuilder {
277 fn build(&self, widget: &LayoutVars) -> Vec<Constraint> {
278 let strength = self.strength;
279 match self.constraint.clone() {
280 WidgetConstraint::Width(width) => {
281 vec![ widget.width | EQ(strength) | width ]
282 }
283 WidgetConstraint::Height(height) => {
284 vec![ widget.height | EQ(strength) | height ]
285 }
286 WidgetConstraint::MinWidth(width) => {
287 vec![ widget.width | GE(strength) | width ]
288 }
289 WidgetConstraint::MinHeight(height) => {
290 vec![ widget.height | GE(strength) | height ]
291 }
292 WidgetConstraint::Size(size) => {
293 vec![
294 widget.width | EQ(strength) | size.width,
295 widget.height | EQ(strength) | size.height,
296 ]
297 }
298 WidgetConstraint::MinSize(size) => {
299 vec![
300 widget.width | GE(strength) | size.width,
301 widget.height | GE(strength) | size.height,
302 ]
303 }
304 WidgetConstraint::AspectRatio(aspect_ratio) => {
305 vec![ aspect_ratio * widget.width | EQ(strength) | widget.height ]
306 }
307 WidgetConstraint::Shrink => {
308 vec![
309 widget.width | EQ(strength) | 0.0,
310 widget.height | EQ(strength) | 0.0,
311 ]
312 }
313 WidgetConstraint::ShrinkHorizontal => {
314 vec![ widget.width | EQ(strength) | 0.0 ]
315 }
316 WidgetConstraint::ShrinkVertical => {
317 vec![ widget.height | EQ(strength) | 0.0 ]
318 }
319 WidgetConstraint::TopLeft(point) => {
320 vec![
321 widget.left | EQ(strength) | point.x,
322 widget.top | EQ(strength) | point.y,
323 ]
324 }
325 WidgetConstraint::Center(other) => {
326 vec![
327 widget.left - other.left | EQ(REQUIRED) | other.right - widget.right,
328 widget.top - other.top | EQ(REQUIRED) | other.bottom - widget.bottom,
329 ]
330 }
331 WidgetConstraint::CenterHorizontal(left, right) => {
332 vec![ widget.left - left | EQ(REQUIRED) | right - widget.right ]
333 }
334 WidgetConstraint::CenterVertical(top, bottom) => {
335 vec![ widget.top - top | EQ(REQUIRED) | bottom - widget.bottom ]
336 }
337 }
338 }
339}
340
341impl ConstraintBuilder for PaddableConstraintBuilder {
342 fn build(&self, widget: &LayoutVars) -> Vec<Constraint> {
343 let strength = self.strength;
344 let padding = self.padding;
345 match self.constraint.clone() {
346 PaddableConstraint::AlignTop(top) => {
347 vec![ widget.top - top | EQ(strength) | padding ]
348 }
349 PaddableConstraint::AlignBottom(bottom) => {
350 vec![ bottom - widget.bottom | EQ(strength) | padding ]
351 }
352 PaddableConstraint::AlignLeft(left) => {
353 vec![ widget.left - left | EQ(strength) | padding ]
354 }
355 PaddableConstraint::AlignRight(right) => {
356 vec![ right - widget.right | EQ(strength) | padding ]
357 }
358 PaddableConstraint::AlignAbove(top) => {
359 vec![ top - widget.bottom | EQ(strength) | padding ]
360 }
361 PaddableConstraint::AlignBelow(bottom) => {
362 vec![ widget.top - bottom | EQ(strength) | padding ]
363 }
364 PaddableConstraint::AlignToLeftOf(left) => {
365 vec![ left - widget.right | EQ(strength) | padding ]
366 }
367 PaddableConstraint::AlignToRightOf(right) => {
368 vec![ widget.left - right | EQ(strength) | padding ]
369 }
370 PaddableConstraint::Above(top) => {
371 vec![ top - widget.bottom | GE(strength) | padding ]
372 }
373 PaddableConstraint::Below(bottom) => {
374 vec![ widget.top - bottom | GE(strength) | padding ]
375 }
376 PaddableConstraint::ToLeftOf(left) => {
377 vec![ left - widget.right | GE(strength) | padding ]
378 }
379 PaddableConstraint::ToRightOf(right) => {
380 vec![ widget.left - right | GE(strength) | padding ]
381 }
382 PaddableConstraint::BoundLeft(left) => {
383 vec![ widget.left - left | GE(strength) | padding ]
384 }
385 PaddableConstraint::BoundTop(top) => {
386 vec![ widget.top - top | GE(strength) | padding ]
387 }
388 PaddableConstraint::BoundRight(right) => {
389 vec![ right - widget.right | GE(strength) | padding ]
390 }
391 PaddableConstraint::BoundBottom(bottom) => {
392 vec![ bottom - widget.bottom | GE(strength) | padding ]
393 }
394 PaddableConstraint::BoundBy(other) => {
395 vec![
396 widget.left - other.left | GE(strength) | padding,
397 widget.top - other.top | GE(strength) | padding,
398 other.right - widget.right | GE(strength) | padding,
399 other.bottom - widget.bottom | GE(strength) | padding,
400 ]
401 }
402 PaddableConstraint::MatchLayout(other) => {
403 vec![
404 widget.left - other.left | EQ(strength) | padding,
405 widget.top - other.top | EQ(strength) | padding,
406 other.right - widget.right | EQ(strength) | padding,
407 other.bottom - widget.bottom | EQ(strength) | padding,
408 ]
409 }
410 PaddableConstraint::MatchWidth(width) => {
411 vec![ width - widget.width | EQ(strength) | padding ]
412 }
413 PaddableConstraint::MatchHeight(height) => {
414 vec![ height - widget.height | EQ(strength) | padding ]
415 }
416 }
417 }
418}
419
420impl <C: ConstraintBuilder> ConstraintBuilder for Vec<C> {
421 fn build(&self, widget: &LayoutVars) -> Vec<Constraint> {
422 let mut constraints = Vec::new();
423 for builder in self {
424 constraints.extend(builder.build(widget));
425 }
426 constraints
427 }
428}
429
430impl ConstraintBuilder for Box<ConstraintBuilder> {
431 fn build(&self, widget: &LayoutVars) -> Vec<Constraint> {
432 self.as_ref().build(widget)
433 }
434}