1 | //! The module contains a [`CompactGridDimension`] for [`CompactGrid`] height/width estimation. |
2 | //! |
3 | //! [`CompactGrid`]: crate::grid::compact::CompactGrid |
4 | |
5 | use core::cmp::max; |
6 | |
7 | use crate::{ |
8 | dimension::{Dimension, Estimate}, |
9 | records::Records, |
10 | util::string::{count_lines, string_width_multiline}, |
11 | }; |
12 | |
13 | use 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)] |
19 | pub struct CompactGridDimension { |
20 | height: usize, |
21 | width: Vec<usize>, |
22 | } |
23 | |
24 | impl 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 | |
41 | impl 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 | |
51 | impl<R> Estimate<R, CompactConfig> for CompactGridDimension |
52 | where |
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 | |
62 | fn 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 | |
81 | fn 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 | |
97 | fn 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 | |
109 | fn 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 | |
116 | fn 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 | |