1//! The module contains a [`CompactGridDimension`] for [`CompactGrid`] height/width estimation.
2//!
3//! [`CompactGrid`]: crate::grid::compact::CompactGrid
4
5use core::cmp::max;
6
7use crate::{
8 dimension::{Dimension, Estimate},
9 records::Records,
10 util::string::{count_lines, string_width_multiline},
11};
12
13use crate::config::compact::CompactConfig;
14
15/// A [`Dimension`] implementation which calculates exact column/row width/height.
16///
17/// [`Grid`]: crate::grid::iterable::Grid
18#[derive(Debug, Default, Clone, PartialEq, Eq)]
19pub struct CompactGridDimension {
20 height: usize,
21 width: Vec<usize>,
22}
23
24impl CompactGridDimension {
25 /// Calculates height of rows.
26 pub fn height<R: Records>(records: R, cfg: &CompactConfig) -> Vec<usize> {
27 build_height(records, cfg)
28 }
29
30 /// Calculates width of columns.
31 pub fn width<R: Records>(records: R, cfg: &CompactConfig) -> Vec<usize> {
32 build_width(records, cfg)
33 }
34
35 /// Calculates dimensions of columns.
36 pub fn dimension<R: Records>(records: R, cfg: &CompactConfig) -> (Vec<usize>, Vec<usize>) {
37 build_dims(records, cfg)
38 }
39}
40
41impl Dimension for CompactGridDimension {
42 fn get_width(&self, column: usize) -> usize {
43 self.width[column]
44 }
45
46 fn get_height(&self, _: usize) -> usize {
47 self.height
48 }
49}
50
51impl<R> Estimate<R, CompactConfig> for CompactGridDimension
52where
53 R: Records,
54{
55 fn estimate(&mut self, records: R, cfg: &CompactConfig) {
56 self.width = build_width(records, cfg);
57 let pad: &Sides = cfg.get_padding();
58 self.height = 1 + pad.top.size + pad.bottom.size;
59 }
60}
61
62fn build_dims<R: Records>(records: R, cfg: &CompactConfig) -> (Vec<usize>, Vec<usize>) {
63 let mut heights: Vec = vec![];
64 let mut widths: Vec = vec![0; records.count_columns()];
65
66 for columns in records.iter_rows() {
67 let mut row_height: usize = 0;
68 for (col, cell) in columns.into_iter().enumerate() {
69 let height: usize = get_cell_height(cell.as_ref(), cfg);
70 let width: usize = get_cell_width(text:cell.as_ref(), cfg);
71 row_height = max(v1:row_height, v2:height);
72 widths[col] = max(v1:widths[col], v2:width)
73 }
74
75 heights.push(row_height);
76 }
77
78 (widths, heights)
79}
80
81fn build_height<R: Records>(records: R, cfg: &CompactConfig) -> Vec<usize> {
82 let mut heights: Vec = vec![];
83
84 for columns in records.iter_rows() {
85 let mut row_height: usize = 0;
86 for cell in columns.into_iter() {
87 let height: usize = get_cell_height(cell.as_ref(), cfg);
88 row_height = max(v1:row_height, v2:height);
89 }
90
91 heights.push(row_height);
92 }
93
94 heights
95}
96
97fn build_width<R: Records>(records: R, cfg: &CompactConfig) -> Vec<usize> {
98 let mut widths: Vec = vec![0; records.count_columns()];
99 for columns in records.iter_rows() {
100 for (col, cell) in columns.into_iter().enumerate() {
101 let width: usize = get_cell_width(text:cell.as_ref(), cfg);
102 widths[col] = max(v1:widths[col], v2:width);
103 }
104 }
105
106 widths
107}
108
109fn get_cell_height(cell: &str, cfg: &CompactConfig) -> usize {
110 let count_lines: usize = max(v1:1, v2:count_lines(cell));
111 let pad: &Sides = cfg.get_padding();
112
113 count_lines + pad.top.size + pad.bottom.size
114}
115
116fn get_cell_width(text: &str, cfg: &CompactConfig) -> usize {
117 let width: usize = string_width_multiline(text);
118 let pad: &Sides = cfg.get_padding();
119
120 width + pad.left.size + pad.right.size
121}
122