use super::layout::{empty_lines, push_spaces};
use crate::{Line, Render, Text};
pub fn padding<T>(content: T) -> Padding<T> {
Padding::new(content)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Padding<T = Text> {
content: T,
top: usize,
bottom: usize,
left: usize,
right: usize,
}
impl<T> Padding<T> {
pub fn new(content: T) -> Self {
Self {
content,
top: 0,
bottom: 0,
left: 0,
right: 0,
}
}
pub fn top(mut self, top: usize) -> Self {
self.top = top;
self
}
pub fn bottom(mut self, bottom: usize) -> Self {
self.bottom = bottom;
self
}
pub fn left(mut self, left: usize) -> Self {
self.left = left;
self
}
pub fn right(mut self, right: usize) -> Self {
self.right = right;
self
}
pub fn vertical(mut self, vertical: usize) -> Self {
self.top = vertical;
self.bottom = vertical;
self
}
pub fn horizontal(mut self, horizontal: usize) -> Self {
self.left = horizontal;
self.right = horizontal;
self
}
pub fn all(mut self, padding: usize) -> Self {
self.top = padding;
self.bottom = padding;
self.left = padding;
self.right = padding;
self
}
pub fn content(&self) -> &T {
&self.content
}
pub fn content_mut(&mut self) -> &mut T {
&mut self.content
}
pub fn top_height(&self) -> usize {
self.top
}
pub fn bottom_height(&self) -> usize {
self.bottom
}
pub fn left_width(&self) -> usize {
self.left
}
pub fn right_width(&self) -> usize {
self.right
}
fn inner_width(&self, width: usize) -> usize {
width.saturating_sub(self.left.saturating_add(self.right))
}
}
impl<T: Render> Render for Padding<T> {
fn render(&self, width: u16) -> Text {
let width = usize::from(width);
if width == 0 {
return Text::empty();
}
let inner_width = self.inner_width(width);
let content = self
.content
.render(inner_width as u16)
.into_wrapped(inner_width);
let content_lines = content.into_lines();
let mut lines = Vec::with_capacity(self.top + content_lines.len() + self.bottom);
lines.extend(empty_lines(self.top));
lines.extend(
content_lines
.into_iter()
.map(|line| self.pad_content_line(line, width)),
);
lines.extend(empty_lines(self.bottom));
Text::from_lines(lines)
}
fn render_every_frame(&self) -> bool {
self.content.render_every_frame()
}
}
impl<T> Padding<T> {
fn pad_content_line(&self, line: Line, width: usize) -> Line {
let visible_left = self.left.min(width);
if visible_left == 0 {
return line;
}
let content_spans = line.into_spans();
let mut spans = Vec::with_capacity(content_spans.len() + 1);
push_spaces(&mut spans, visible_left);
spans.extend(content_spans);
Line::from_spans(spans)
}
}