1use crate::console::{ConsoleOptions, DynRenderable, RenderResult, Renderable};
4use crate::segment::Segment;
5
6#[derive(Clone)]
8pub struct Columns {
9 pub renderables: Vec<DynRenderable>,
10 pub equal: bool,
11 pub expand: bool,
12 pub padding: usize,
13 pub width: Option<usize>,
14}
15
16impl std::fmt::Debug for Columns {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.debug_struct("Columns")
19 .field("count", &self.renderables.len())
20 .field("equal", &self.equal)
21 .finish()
22 }
23}
24
25impl Columns {
26 pub fn new() -> Self {
38 Self {
39 renderables: Vec::new(),
40 equal: false,
41 expand: false,
42 padding: 1,
43 width: None,
44 }
45 }
46
47 pub fn add(&mut self, renderable: impl Renderable + Send + Sync + 'static) {
49 self.renderables.push(DynRenderable::new(renderable));
50 }
51
52 pub fn padding(mut self, padding: usize) -> Self {
54 self.padding = padding;
55 self
56 }
57 pub fn equal(mut self) -> Self {
59 self.equal = true;
60 self
61 }
62 pub fn expand(mut self) -> Self {
64 self.expand = true;
65 self
66 }
67}
68
69impl Renderable for Columns {
70 fn render(&self, options: &ConsoleOptions) -> RenderResult {
71 let count = self.renderables.len();
72 if count == 0 {
73 return RenderResult::new();
74 }
75
76 let available = self.width.unwrap_or(options.max_width);
77 let total_padding = (count.saturating_sub(1)) * self.padding;
78 let col_width = available.saturating_sub(total_padding) / count;
79
80 let rendered: Vec<RenderResult> = self
82 .renderables
83 .iter()
84 .map(|r| r.render(&options.update_width(col_width.max(1))))
85 .collect();
86
87 let max_lines = rendered.iter().map(|r| r.lines.len()).max().unwrap_or(0);
89
90 let mut lines: Vec<Vec<Segment>> = Vec::new();
91
92 for line_idx in 0..max_lines {
93 let mut line_segments: Vec<Segment> = Vec::new();
94
95 for (col_idx, col_result) in rendered.iter().enumerate() {
96 if col_idx > 0 {
97 line_segments.push(Segment::new(" ".repeat(self.padding)));
98 }
99
100 if let Some(col_line) = col_result.lines.get(line_idx) {
101 line_segments.extend(col_line.iter().cloned());
102 } else {
103 line_segments.push(Segment::new(" ".repeat(col_width)));
105 }
106 }
107
108 if line_idx < max_lines - 1 {
109 line_segments.push(Segment::line());
110 }
111 lines.push(line_segments);
112 }
113
114 RenderResult {
115 lines,
116 items: Vec::new(),
117 }
118 }
119}
120
121impl Default for Columns {
122 fn default() -> Self {
123 Self::new()
124 }
125}