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 {
96 width: child_width,
97 height: None,
98 };
99
100 let child_segments = self.child.render(&child_context);
102
103 let mut result = Vec::new();
104
105 for _ in 0..self.spec.top {
107 result.push(Segment::line(vec![Span::raw(" ".repeat(context.width))]));
108 }
109
110 for segment in child_segments {
112 let mut padded_spans = Vec::new();
113
114 if self.spec.left > 0 {
116 padded_spans.push(Span::raw(" ".repeat(self.spec.left)));
117 }
118
119 padded_spans.extend(segment.spans);
121
122 if self.spec.right > 0 {
124 padded_spans.push(Span::raw(" ".repeat(self.spec.right)));
125 }
126
127 if segment.newline {
128 result.push(Segment::line(padded_spans));
129 } else {
130 result.push(Segment::new(padded_spans));
131 }
132 }
133
134 for _ in 0..self.spec.bottom {
136 result.push(Segment::line(vec![Span::raw(" ".repeat(context.width))]));
137 }
138
139 result
140 }
141}