1use std::fmt;
4
5use ctl_text::{Context, Line, Measurement, Renderable};
6
7#[derive(Default)]
13pub struct Stack<'a> {
14 children: Vec<Box<dyn Renderable + 'a>>,
15 spacing: u16,
16}
17
18impl<'a> Stack<'a> {
19 #[must_use]
21 pub fn new() -> Self {
22 Self::default()
23 }
24
25 #[must_use]
28 pub fn spacing(mut self, lines: u16) -> Self {
29 self.spacing = lines;
30 self
31 }
32
33 #[must_use]
35 pub fn push(mut self, child: impl Renderable + 'a) -> Self {
36 self.children.push(Box::new(child));
37 self
38 }
39}
40
41impl fmt::Debug for Stack<'_> {
42 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
43 formatter
44 .debug_struct("Stack")
45 .field("children", &self.children.len())
46 .field("spacing", &self.spacing)
47 .finish()
48 }
49}
50
51impl Renderable for Stack<'_> {
52 fn measure(&self, context: &Context) -> Measurement {
53 self.children
54 .iter()
55 .map(|child| child.measure(context))
56 .fold(Measurement::exact(0), |widest, child| {
57 Measurement::new(
58 widest.minimum().max(child.minimum()),
59 widest.maximum().max(child.maximum()),
60 )
61 })
62 }
63
64 fn render(&self, context: &Context) -> Vec<Line> {
65 let mut lines: Vec<Line> = Vec::new();
66 for child in &self.children {
67 let rendered = child.render(context);
68 if rendered.iter().all(Line::is_empty) {
69 continue;
70 }
71 if !lines.is_empty() {
72 lines.extend((0..self.spacing).map(|_| Line::new()));
73 }
74 lines.extend(rendered);
75 }
76 lines
77 }
78}