tabled/features/style/
span_border_correction.rs1use papergrid::{records::Records, Position};
7
8use crate::{Table, TableOption};
9
10#[derive(Debug)]
18pub struct StyleCorrectSpan;
19
20impl<R> TableOption<R> for StyleCorrectSpan
21where
22 R: Records,
23{
24 fn change(&mut self, table: &mut Table<R>) {
25 correct_span_styles(table);
26 }
27}
28
29fn correct_span_styles<R>(table: &mut Table<R>)
30where
31 R: Records,
32{
33 let spans = table
34 .get_config()
35 .iter_column_spans(table.shape())
36 .collect::<Vec<_>>();
37 for &((row, c), span) in &spans {
38 for col in c..c + span {
39 if col == 0 {
40 continue;
41 }
42
43 let is_first = col == c;
44 let has_up = row > 0 && has_left(table, (row - 1, col));
45 let has_down = row + 1 < table.shape().0 && has_left(table, (row + 1, col));
46
47 let mut border = table.get_config().get_border((row, col), table.shape());
48 let borders = table.get_config().get_borders();
49
50 let has_top_border = border.left_top_corner.is_some() && border.top.is_some();
51 if has_top_border {
52 if has_up && is_first {
53 border.left_top_corner = borders.intersection;
54 } else if has_up {
55 border.left_top_corner = borders.bottom_intersection;
56 } else if is_first {
57 border.left_top_corner = borders.top_intersection;
58 } else {
59 border.left_top_corner = border.top;
60 }
61 }
62
63 let has_bottom_border = border.left_bottom_corner.is_some() && border.bottom.is_some();
64 if has_bottom_border {
65 if has_down && is_first {
66 border.left_bottom_corner = borders.intersection;
67 } else if has_down {
68 border.left_bottom_corner = borders.top_intersection;
69 } else if is_first {
70 border.left_bottom_corner = borders.bottom_intersection;
71 } else {
72 border.left_bottom_corner = border.bottom;
73 }
74 }
75
76 table.get_config_mut().set_border((row, col), border);
77 }
78 }
79
80 let spans = table
81 .get_config()
82 .iter_row_spans(table.shape())
83 .collect::<Vec<_>>();
84 for &((r, col), span) in &spans {
85 for row in r + 1..r + span {
86 let mut border = table.get_config().get_border((row, col), table.shape());
87 let borders = table.get_config().get_borders();
88
89 let has_left_border = border.left_top_corner.is_some();
90 if has_left_border {
91 let has_left = col > 0 && has_top(table, (row, col - 1));
92 if has_left {
93 border.left_top_corner = borders.horizontal_right;
94 } else {
95 border.left_top_corner = borders.vertical;
96 }
97 }
98
99 let has_right_border = border.right_top_corner.is_some();
100 if has_right_border {
101 let has_right = col + 1 < table.shape().1 && has_top(table, (row, col + 1));
102 if has_right {
103 border.right_top_corner = borders.horizontal_left;
104 } else {
105 border.right_top_corner = borders.vertical;
106 }
107 }
108
109 table.get_config_mut().set_border((row, col), border);
110 }
111 }
112
113 let cells = iter_totaly_spanned_cells(table).collect::<Vec<_>>();
114 for (row, col) in cells {
115 if row == 0 {
116 continue;
117 }
118
119 let mut border = table.get_config().get_border((row, col), table.shape());
120 let borders = table.get_config().get_borders();
121
122 let has_right = col + 1 < table.shape().1 && has_top(table, (row, col + 1));
123 let has_up = has_left(table, (row - 1, col));
124 if has_up && !has_right {
125 border.right_top_corner = borders.horizontal_right;
126 }
127
128 let has_down = row + 1 < table.shape().0 && has_left(table, (row + 1, col));
129 if has_down {
130 border.left_bottom_corner = borders.top_intersection;
131 }
132
133 table.get_config_mut().set_border((row, col), border);
134 }
135}
136
137fn has_left<R>(table: &Table<R>, pos: Position) -> bool
138where
139 R: Records,
140{
141 let cfg = table.get_config();
142 if cfg.is_cell_covered_by_both_spans(pos, table.shape())
143 || cfg.is_cell_covered_by_column_span(pos, table.shape())
144 {
145 return false;
146 }
147
148 let border = cfg.get_border(pos, table.shape());
149 border.left.is_some() || border.left_top_corner.is_some() || border.left_bottom_corner.is_some()
150}
151
152fn has_top<R>(table: &Table<R>, pos: Position) -> bool
153where
154 R: Records,
155{
156 let cfg = table.get_config();
157 if cfg.is_cell_covered_by_both_spans(pos, table.shape())
158 || cfg.is_cell_covered_by_row_span(pos, table.shape())
159 {
160 return false;
161 }
162
163 let border = cfg.get_border(pos, table.shape());
164 border.top.is_some() || border.left_top_corner.is_some() || border.right_top_corner.is_some()
165}
166
167fn iter_totaly_spanned_cells<R>(table: &Table<R>) -> impl Iterator<Item = Position> + '_
168where
169 R: Records,
170{
171 let (count_rows, count_cols) = table.shape();
173 (0..count_rows).flat_map(move |row| {
174 (0..count_cols)
175 .map(move |col| (row, col))
176 .filter(move |&p| {
177 table
178 .get_config()
179 .is_cell_covered_by_both_spans(p, (count_rows, count_cols))
180 })
181 })
182}