fop_layout/layout/table/
grid.rs1use crate::area::{Area, AreaId, AreaTree, AreaType};
4use fop_types::{Length, Point, Rect, Result, Size};
5
6use super::types::{BorderCollapse, GridCell, TableLayout};
7
8impl TableLayout {
9 pub fn create_grid(&self, rows: usize, cols: usize) -> Vec<Vec<Option<GridCell>>> {
11 vec![vec![None; cols]; rows]
12 }
13
14 pub fn place_cell(&self, grid: &mut [Vec<Option<GridCell>>], cell: GridCell) -> Result<()> {
16 let rows = grid.len();
17 let cols = if rows > 0 { grid[0].len() } else { 0 };
18
19 if cell.row >= rows || cell.col >= cols {
21 return Err(fop_types::FopError::Generic(
22 "Cell position out of bounds".to_string(),
23 ));
24 }
25
26 #[allow(clippy::needless_range_loop)]
28 for r in cell.row..(cell.row + cell.rowspan).min(rows) {
29 for c in cell.col..(cell.col + cell.colspan).min(cols) {
30 if r == cell.row && c == cell.col {
31 grid[r][c] = Some(cell.clone());
32 } else {
33 grid[r][c] = Some(GridCell {
35 row: cell.row,
36 col: cell.col,
37 rowspan: 0, colspan: 0,
39 content_id: None,
40 });
41 }
42 }
43 }
44
45 Ok(())
46 }
47
48 pub fn layout_table(
50 &self,
51 area_tree: &mut AreaTree,
52 column_widths: &[Length],
53 grid: &[Vec<Option<GridCell>>],
54 y_offset: Length,
55 ) -> Result<AreaId> {
56 let rows = grid.len();
57 let cols = if rows > 0 { grid[0].len() } else { 0 };
58
59 let table_width: Length = column_widths
61 .iter()
62 .copied()
63 .fold(Length::ZERO, |acc, len| acc + len);
64
65 let total_spacing = match self.border_collapse {
67 BorderCollapse::Separate => self.border_spacing * (cols + 1) as i32,
68 BorderCollapse::Collapse => Length::ZERO,
69 };
70 let total_width = table_width + total_spacing;
71
72 let table_rect = Rect::from_point_size(
74 Point::new(Length::ZERO, y_offset),
75 Size::new(total_width, Length::from_pt(100.0)), );
77 let table_area = Area::new(AreaType::Block, table_rect);
78 let table_id = area_tree.add_area(table_area);
79
80 let (initial_x, initial_y, cell_spacing_x, cell_spacing_y) = match self.border_collapse {
82 BorderCollapse::Separate => (
83 self.border_spacing,
84 self.border_spacing,
85 self.border_spacing,
86 self.border_spacing,
87 ),
88 BorderCollapse::Collapse => (Length::ZERO, Length::ZERO, Length::ZERO, Length::ZERO),
89 };
90
91 let mut current_y = initial_y;
92 for row in grid {
93 let mut current_x = initial_x;
94 let row_height = Length::from_pt(20.0); for (col_idx, cell_opt) in row.iter().enumerate() {
97 if let Some(cell) = cell_opt {
98 if cell.rowspan > 0 && cell.colspan > 0 {
100 let cell_width = column_widths[col_idx];
101 let cell_rect = Rect::from_point_size(
102 Point::new(current_x, current_y),
103 Size::new(cell_width, row_height),
104 );
105 let cell_area = Area::new(AreaType::Block, cell_rect);
106 area_tree.add_area(cell_area);
107 }
108 }
109
110 if col_idx < column_widths.len() {
111 current_x += column_widths[col_idx] + cell_spacing_x;
112 }
113 }
114
115 current_y += row_height + cell_spacing_y;
116 }
117
118 Ok(table_id)
119 }
120}