limn_layout/
grid_layout.rs1use cassowary::strength::*;
2use cassowary::WeightedRelation::*;
3
4use super::{LayoutVars, Layout, Constraint, LayoutContainer};
5use super::constraint::*;
6
7#[derive(Debug, Clone)]
8pub struct GridLayout {
9 num_columns: usize,
10 column: usize,
11 rows: Vec<LayoutVars>,
12 columns: Vec<LayoutVars>,
13 row_end: Option<Constraint>,
14}
15
16impl GridLayout {
17 pub fn new(parent: &mut Layout, num_columns: usize) -> Self {
18 assert!(num_columns > 0, "can't create grid layout with no columns");
19 let mut columns = Vec::new();
20 for col in 0..num_columns {
21 let column = LayoutVars::new();
22 let mut constraints = vec![
23 column.top | EQ(REQUIRED) | parent.vars.top,
24 column.bottom | EQ(REQUIRED) | parent.vars.bottom,
25 column.right - column.left | EQ(REQUIRED) | column.width,
26 column.bottom - column.top | EQ(REQUIRED) | column.height,
27 ];
28 if let Some(last_column) = columns.last() {
29 let last_column: &LayoutVars = last_column;
30 constraints.push(column.left | EQ(REQUIRED) | last_column.right);
31 constraints.push(column.width | EQ(REQUIRED) | last_column.width);
32 } else {
33 constraints.push(column.left | EQ(REQUIRED) | parent.vars.left);
34 }
35 if col == num_columns - 1 {
36 constraints.push(column.right | EQ(REQUIRED) | parent.vars.right);
37 }
38 parent.add(constraints);
39 parent.add_associated_vars(&column, &format!("column_{}", col));
40 columns.push(column);
41 }
42 GridLayout {
43 num_columns: num_columns,
44 column: 0,
45 rows: Vec::new(),
46 columns: columns,
47 row_end: None,
48 }
49 }
50}
51impl LayoutContainer for GridLayout {
52 fn add_child(&mut self, parent: &mut Layout, child: &mut Layout) {
53 if self.column == self.num_columns || self.rows.len() == 0 {
54 let row = LayoutVars::new();
55 let mut constraints = vec![
56 row.left | EQ(REQUIRED) | parent.vars.left,
57 row.right | EQ(REQUIRED) | parent.vars.right,
58 row.right - row.left | EQ(REQUIRED) | row.width,
59 row.bottom - row.top | EQ(REQUIRED) | row.height,
60 ];
61 if let Some(last_row) = self.rows.last() {
62 constraints.push(row.top | EQ(REQUIRED) | last_row.bottom);
63 constraints.push(row.height | EQ(REQUIRED) | last_row.height);
64 } else {
65 constraints.push(row.top | EQ(REQUIRED) | parent.vars.top);
66 }
67 if let Some(row_end) = self.row_end.take() {
68 parent.remove_constraint(row_end);
69 }
70 let row_end = row.bottom | EQ(REQUIRED) | parent.vars.bottom;
71 self.row_end = Some(row_end.clone());
72 constraints.push(row_end);
73 parent.add(constraints);
74 parent.add_associated_vars(&row, &format!("row_{}", self.rows.len()));
75 self.rows.push(row);
76 self.column = 0;
77 }
78 let (row, col) = (self.rows.last().unwrap(), self.columns.get(self.column).unwrap());
79 child.add(constraints![
80 bound_by(row),
81 bound_by(col),
82 match_layout(&parent).strength(STRONG),
83 ]);
84 self.column += 1;
85 }
86}