limn_layout/
grid_layout.rs

1use 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}