1use crate::console::RenderContext;
6use crate::renderable::{BoxedRenderable, Renderable, Segment};
7use crate::text::Span;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct PaddingSpec {
12 pub top: usize,
14 pub right: usize,
16 pub bottom: usize,
18 pub left: usize,
20}
21
22impl PaddingSpec {
23 pub fn all(size: usize) -> Self {
25 PaddingSpec {
26 top: size,
27 right: size,
28 bottom: size,
29 left: size,
30 }
31 }
32
33 pub fn symmetric(vertical: usize, horizontal: usize) -> Self {
35 PaddingSpec {
36 top: vertical,
37 right: horizontal,
38 bottom: vertical,
39 left: horizontal,
40 }
41 }
42
43 pub fn new(top: usize, right: usize, bottom: usize, left: usize) -> Self {
45 PaddingSpec {
46 top,
47 right,
48 bottom,
49 left,
50 }
51 }
52
53 pub fn none() -> Self {
55 PaddingSpec::all(0)
56 }
57}
58
59pub struct Padding {
61 child: BoxedRenderable,
62 spec: PaddingSpec,
63}
64
65impl Padding {
66 pub fn new(child: impl Renderable + Send + Sync + 'static, spec: PaddingSpec) -> Self {
68 Padding {
69 child: Box::new(child),
70 spec,
71 }
72 }
73
74 pub fn all(child: impl Renderable + Send + Sync + 'static, size: usize) -> Self {
76 Padding::new(child, PaddingSpec::all(size))
77 }
78
79 pub fn symmetric(
81 child: impl Renderable + Send + Sync + 'static,
82 vertical: usize,
83 horizontal: usize,
84 ) -> Self {
85 Padding::new(child, PaddingSpec::symmetric(vertical, horizontal))
86 }
87}
88
89impl Renderable for Padding {
90 fn render(&self, context: &RenderContext) -> Vec<Segment> {
91 let child_width = context
93 .width
94 .saturating_sub(self.spec.left + self.spec.right);
95 let child_context = RenderContext { width: child_width, height: None };
96
97 let child_segments = self.child.render(&child_context);
99
100 let mut result = Vec::new();
101
102 for _ in 0..self.spec.top {
104 result.push(Segment::line(vec![Span::raw(" ".repeat(context.width))]));
105 }
106
107 for segment in child_segments {
109 let mut padded_spans = Vec::new();
110
111 if self.spec.left > 0 {
113 padded_spans.push(Span::raw(" ".repeat(self.spec.left)));
114 }
115
116 padded_spans.extend(segment.spans);
118
119 if self.spec.right > 0 {
121 padded_spans.push(Span::raw(" ".repeat(self.spec.right)));
122 }
123
124 if segment.newline {
125 result.push(Segment::line(padded_spans));
126 } else {
127 result.push(Segment::new(padded_spans));
128 }
129 }
130
131 for _ in 0..self.spec.bottom {
133 result.push(Segment::line(vec![Span::raw(" ".repeat(context.width))]));
134 }
135
136 result
137 }
138}