1use std::borrow::Borrow;
2
3use fltk::group::Group;
4use fltk::prelude::*;
5
6use crate::{Padding, WrapperFactory};
7
8use super::{Cell, CellAlign, Grid, GridProperties, StripeCell};
9
10use self::group::StripeGroupBuilder;
11
12mod cell;
13mod group;
14mod stripe;
15
16pub use cell::CellBuilder;
17pub use stripe::StripeBuilder;
18
19pub struct GridBuilder<G: GroupExt + Clone = Group, F: Borrow<WrapperFactory> = WrapperFactory> {
20 props: GridProperties<G>,
21 factory: F,
22 default_cell_padding: Padding,
23 default_row_align: Vec<CellAlign>,
24 default_col_align: Vec<CellAlign>,
25 next_row: usize,
26 next_col: usize,
27}
28
29#[derive(Clone, Copy)]
30pub struct StripeGroupRef {
31 kind: StripeKind,
32 idx: usize,
33}
34
35#[derive(Clone, Copy)]
36enum StripeKind {
37 Row,
38 Column,
39}
40
41impl<G: GroupExt + Clone> GridBuilder<G> {
42 pub fn new(group: G) -> Self {
43 Self::with_factory(group, WrapperFactory::new())
44 }
45}
46
47impl<G: GroupExt + Clone, F: Borrow<WrapperFactory>> GridBuilder<G, F> {
48 pub fn with_factory(group: G, factory: F) -> Self {
49 Self {
50 props: GridProperties {
51 group,
52 padding: Default::default(),
53 row_spacing: 0,
54 col_spacing: 0,
55 cells: Vec::new(),
56 spans: Vec::new(),
57 groups: Vec::new(),
58 rows: Vec::new(),
59 cols: Vec::new(),
60 },
61 factory,
62 default_cell_padding: Default::default(),
63 default_row_align: Vec::new(),
64 default_col_align: Vec::new(),
65 next_row: 0,
66 next_col: 0,
67 }
68 }
69
70 pub fn with_row_spacing(mut self, spacing: i32) -> Self {
71 self.props.row_spacing = std::cmp::max(0, spacing);
72 self
73 }
74
75 pub fn with_col_spacing(mut self, spacing: i32) -> Self {
76 self.props.col_spacing = std::cmp::max(0, spacing);
77 self
78 }
79
80 pub fn with_left_padding(mut self, padding: i32) -> Self {
81 self.props.padding.left = padding;
82 self
83 }
84
85 pub fn with_top_padding(mut self, padding: i32) -> Self {
86 self.props.padding.top = padding;
87 self
88 }
89
90 pub fn with_right_padding(mut self, padding: i32) -> Self {
91 self.props.padding.right = padding;
92 self
93 }
94
95 pub fn with_bottom_padding(mut self, padding: i32) -> Self {
96 self.props.padding.bottom = padding;
97 self
98 }
99
100 pub fn with_padding(mut self, left: i32, top: i32, right: i32, bottom: i32) -> Self {
101 self.props.padding = Padding {
102 left,
103 top,
104 right,
105 bottom,
106 };
107 self
108 }
109
110 pub fn with_default_cell_padding(
111 mut self,
112 left: i32,
113 top: i32,
114 right: i32,
115 bottom: i32,
116 ) -> Self {
117 self.default_cell_padding = Padding {
118 left,
119 top,
120 right,
121 bottom,
122 };
123 self
124 }
125
126 pub fn num_rows(&self) -> usize {
127 self.props.rows.len()
128 }
129
130 pub fn num_cols(&self) -> usize {
131 self.props.cols.len()
132 }
133
134 pub fn row(&mut self) -> StripeBuilder<G, F> {
135 StripeBuilder::new(self, StripeKind::Row, None)
136 }
137
138 pub fn col(&mut self) -> StripeBuilder<G, F> {
139 StripeBuilder::new(self, StripeKind::Column, None)
140 }
141
142 pub fn row_group(&mut self) -> StripeGroupBuilder<G, F> {
143 StripeGroupBuilder::new(self, StripeKind::Row)
144 }
145
146 pub fn col_group(&mut self) -> StripeGroupBuilder<G, F> {
147 StripeGroupBuilder::new(self, StripeKind::Column)
148 }
149
150 pub fn extend_group(&mut self, group: StripeGroupRef) -> StripeBuilder<G, F> {
151 StripeBuilder::new(self, group.kind, Some(group.idx))
152 }
153
154 pub fn cell(&mut self) -> Option<CellBuilder<G, F>> {
155 let (row, col) = self.next_free_cell()?;
156 Some(CellBuilder::new(self, row, col, 1, 1))
157 }
158
159 pub fn cell_at(&mut self, row: usize, col: usize) -> Option<CellBuilder<G, F>> {
160 if (row >= self.props.rows.len()) && (col >= self.props.cols.len()) {
161 return None;
162 }
163 match self.props.rows[row].cells[col] {
164 StripeCell::Free | StripeCell::Skipped => Some(CellBuilder::new(self, row, col, 1, 1)),
165 _ => None,
166 }
167 }
168
169 pub fn span(&mut self, row_span: usize, col_span: usize) -> Option<CellBuilder<G, F>> {
170 if (row_span == 0) || (col_span == 0) {
171 return None;
172 }
173
174 let (row, col) = self.next_free_cell()?;
175 if self.is_span_available(row, col, row_span, col_span, false) {
176 Some(CellBuilder::new(self, row, col, row_span, col_span))
177 } else {
178 None
179 }
180 }
181
182 pub fn span_at(
183 &mut self,
184 row: usize,
185 col: usize,
186 row_span: usize,
187 col_span: usize,
188 ) -> Option<CellBuilder<G, F>> {
189 if (row_span == 0) || (col_span == 0) {
190 return None;
191 }
192
193 if (row >= self.props.rows.len()) && (col >= self.props.cols.len()) {
194 return None;
195 }
196 if self.is_span_available(row, col, row_span, col_span, true) {
197 Some(CellBuilder::new(self, row, col, row_span, col_span))
198 } else {
199 None
200 }
201 }
202
203 pub fn end(self) -> Grid<G> {
204 self.props.group.end();
205 Grid::new(self.props)
206 }
207
208 fn next_free_cell(&mut self) -> Option<(usize, usize)> {
209 let mut row = self.next_row;
210 let mut col = self.next_col;
211
212 loop {
213 if col >= self.props.cols.len() {
214 col = 0;
215 row += 1;
216 }
217 if row >= self.props.rows.len() {
218 return None;
219 }
220 if let StripeCell::Free = self.props.rows[row].cells[col] {
221 break;
222 }
223 col += 1;
224 }
225
226 self.next_row = row;
227 self.next_col = col;
228
229 Some((row, col))
230 }
231
232 fn is_span_available(
233 &self,
234 row: usize,
235 col: usize,
236 row_span: usize,
237 col_span: usize,
238 allow_skipped: bool,
239 ) -> bool {
240 let top = row;
241 let bottom = top + row_span;
242 let left = col;
243 let right = left + col_span;
244
245 if (bottom > self.props.rows.len()) || (right > self.props.cols.len()) {
246 return false;
247 }
248
249 for cell_row in top..bottom {
250 for cell_col in left..right {
251 let cell_available = match self.props.rows[cell_row].cells[cell_col] {
252 StripeCell::Free => true,
253 StripeCell::Skipped if allow_skipped => true,
254 _ => false,
255 };
256 if !cell_available {
257 return false;
258 }
259 }
260 }
261
262 true
263 }
264
265 fn add_cell(&mut self, cell: Cell) {
266 if (cell.props.row_span > 1) || (cell.props.col_span > 1) {
267 return self.add_span(cell);
268 }
269
270 let row = cell.props.row;
271 let col = cell.props.col;
272
273 let cell_idx = self.props.cells.len();
274 self.props.cells.push(cell);
275
276 self.props.rows[row].cells[col] = StripeCell::Cell(cell_idx);
277 self.props.cols[col].cells[row] = StripeCell::Cell(cell_idx);
278 }
279
280 fn add_span(&mut self, span: Cell) {
281 let top = span.props.row;
282 let bottom = top + span.props.row_span;
283 let left = span.props.col;
284 let right = left + span.props.col_span;
285
286 self.props.spans.push(span);
287
288 for row in top..bottom {
289 for col in left..right {
290 self.props.rows[row].cells[col] = StripeCell::Span;
291 self.props.cols[col].cells[row] = StripeCell::Span;
292 }
293 }
294 }
295}