1use crate::{
2 grid::{
3 config::{ColoredConfig, Entity, Position, SpannedConfig},
4 records::{ExactRecords, Records},
5 },
6 settings::CellOption,
7};
8
9/// Columns (Vertical) span.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
11pub struct ColumnSpan {
12 size: usize,
13}
14
15impl ColumnSpan {
16 /// Creates a new column (vertical) span.
17 pub fn new(size: usize) -> Self {
18 Self { size }
19 }
20
21 /// Creates a new column (vertical) span with a maximux value possible.
22 pub fn max() -> Self {
23 Self::new(size:usize::MAX)
24 }
25}
26
27impl<R> CellOption<R, ColoredConfig> for ColumnSpan
28where
29 R: Records + ExactRecords,
30{
31 fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
32 let count_rows: usize = records.count_rows();
33 let count_cols: usize = records.count_columns();
34
35 set_col_spans(cfg, self.size, entity, (count_rows, count_cols));
36 remove_false_spans(cfg);
37 }
38}
39
40fn set_col_spans(cfg: &mut SpannedConfig, span: usize, entity: Entity, shape: (usize, usize)) {
41 for pos: (usize, usize) in entity.iter(count_rows:shape.0, count_cols:shape.1) {
42 if !is_valid_pos(pos, shape) {
43 continue;
44 }
45
46 let mut span: usize = span;
47 if !is_column_span_valid(col:pos.1, span, count_cols:shape.1) {
48 span = shape.1 - pos.1;
49 }
50
51 if span_has_intersections(cfg, pos, span) {
52 continue;
53 }
54
55 set_span_column(cfg, pos, span);
56 }
57}
58
59fn set_span_column(cfg: &mut SpannedConfig, pos: (usize, usize), span: usize) {
60 if span == 0 {
61 let (row: usize, col: usize) = pos;
62 if col == 0 {
63 return;
64 }
65
66 if let Some(closecol: usize) = closest_visible(cfg, (row, col - 1)) {
67 let span: usize = col + 1 - closecol;
68 cfg.set_column_span((row, closecol), span);
69 }
70 }
71
72 cfg.set_column_span(pos, span);
73}
74
75fn closest_visible(cfg: &SpannedConfig, mut pos: Position) -> Option<usize> {
76 loop {
77 if cfg.is_cell_visible(pos) {
78 return Some(pos.1);
79 }
80
81 if pos.1 == 0 {
82 return None;
83 }
84
85 pos.1 -= 1;
86 }
87}
88
89fn is_column_span_valid(col: usize, span: usize, count_cols: usize) -> bool {
90 span + col <= count_cols
91}
92
93fn is_valid_pos((row: usize, col: usize): Position, (count_rows: usize, count_cols: usize): (usize, usize)) -> bool {
94 row < count_rows && col < count_cols
95}
96
97fn span_has_intersections(cfg: &SpannedConfig, (row: usize, col: usize): Position, span: usize) -> bool {
98 for col: usize in col..col + span {
99 if !cfg.is_cell_visible((row, col)) {
100 return true;
101 }
102 }
103
104 false
105}
106
107fn remove_false_spans(cfg: &mut SpannedConfig) {
108 for (pos: (usize, usize), _) in cfg.get_column_spans() {
109 if cfg.is_cell_visible(pos) {
110 continue;
111 }
112
113 cfg.set_row_span(pos, span:1);
114 cfg.set_column_span(pos, span:1);
115 }
116
117 for (pos: (usize, usize), _) in cfg.get_row_spans() {
118 if cfg.is_cell_visible(pos) {
119 continue;
120 }
121
122 cfg.set_row_span(pos, span:1);
123 cfg.set_column_span(pos, span:1);
124 }
125}
126