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::{IntoRecords, 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: R, cfg: &CompactConfig) -> Vec<usize>
27 where
28 R: Records,
29 <R::Iter as IntoRecords>::Cell: AsRef<str>,
30 {
31 build_height(records, cfg)
32 }
33
34 /// Calculates width of columns.
35 pub fn width<R>(records: R, cfg: &CompactConfig) -> Vec<usize>
36 where
37 R: Records,
38 <R::Iter as IntoRecords>::Cell: AsRef<str>,
39 {
40 build_width(records, cfg)
41 }
42
43 /// Calculates dimensions of columns.
44 pub fn dimension<R>(records: R, cfg: &CompactConfig) -> (Vec<usize>, Vec<usize>)
45 where
46 R: Records,
47 <R::Iter as IntoRecords>::Cell: AsRef<str>,
48 {
49 build_dims(records, cfg)
50 }
51}
52
53impl Dimension for CompactGridDimension {
54 fn get_width(&self, column: usize) -> usize {
55 self.width[column]
56 }
57
58 fn get_height(&self, _: usize) -> usize {
59 self.height
60 }
61}
62
63impl<R> Estimate<R, CompactConfig> for CompactGridDimension
64where
65 R: Records,
66 <R::Iter as IntoRecords>::Cell: AsRef<str>,
67{
68 fn estimate(&mut self, records: R, cfg: &CompactConfig) {
69 self.width = build_width(records, cfg);
70 let pad: &Sides = cfg.get_padding();
71 self.height = 1 + pad.top.size + pad.bottom.size;
72 }
73}
74
75fn build_dims<R>(records: R, cfg: &CompactConfig) -> (Vec<usize>, Vec<usize>)
76where
77 R: Records,
78 <R::Iter as IntoRecords>::Cell: AsRef<str>,
79{
80 let mut heights: Vec = vec![];
81 let mut widths: Vec = vec![0; records.count_columns()];
82
83 for columns in records.iter_rows() {
84 let mut row_height: usize = 0;
85 for (col, cell) in columns.into_iter().enumerate() {
86 let height: usize = get_cell_height(cell.as_ref(), cfg);
87 let width: usize = get_cell_width(text:cell.as_ref(), cfg);
88 row_height = max(v1:row_height, v2:height);
89 widths[col] = max(v1:widths[col], v2:width)
90 }
91
92 heights.push(row_height);
93 }
94
95 (widths, heights)
96}
97
98fn build_height<R>(records: R, cfg: &CompactConfig) -> Vec<usize>
99where
100 R: Records,
101 <R::Iter as IntoRecords>::Cell: AsRef<str>,
102{
103 let mut heights: Vec = vec![];
104
105 for columns in records.iter_rows() {
106 let mut row_height: usize = 0;
107 for cell in columns.into_iter() {
108 let height: usize = get_cell_height(cell.as_ref(), cfg);
109 row_height = max(v1:row_height, v2:height);
110 }
111
112 heights.push(row_height);
113 }
114
115 heights
116}
117
118fn build_width<R>(records: R, cfg: &CompactConfig) -> Vec<usize>
119where
120 R: Records,
121 <R::Iter as IntoRecords>::Cell: AsRef<str>,
122{
123 let mut widths: Vec = vec![0; records.count_columns()];
124 for columns in records.iter_rows() {
125 for (col, cell) in columns.into_iter().enumerate() {
126 let width: usize = get_cell_width(text:cell.as_ref(), cfg);
127 widths[col] = max(v1:widths[col], v2:width);
128 }
129 }
130
131 widths
132}
133
134fn get_cell_height(cell: &str, cfg: &CompactConfig) -> usize {
135 let count_lines: usize = max(v1:1, v2:count_lines(cell));
136 let pad: &Sides = cfg.get_padding();
137
138 count_lines + pad.top.size + pad.bottom.size
139}
140
141fn get_cell_width(text: &str, cfg: &CompactConfig) -> usize {
142 let width: usize = string_width_multiline(text);
143 let pad: &Sides = cfg.get_padding();
144
145 width + pad.left.size + pad.right.size
146}
147