feat(widget): support adding padding to Block (#20)

Co-authored-by: Igor Mandello <igormandello@gmail.com>
Co-authored-by: Léon Sautour <leon@sautour.net>
This commit is contained in:
Orhun Parmaksız
2023-04-27 12:30:13 +02:00
committed by GitHub
parent 26cf1f7a89
commit 782820c34a
4 changed files with 141 additions and 38 deletions

View File

@@ -8,7 +8,7 @@ use ratatui::{
layout::{Alignment, Constraint, Direction, Layout},
style::{Color, Modifier, Style},
text::Span,
widgets::{Block, BorderType, Borders},
widgets::{Block, BorderType, Borders, Padding, Paragraph},
Frame, Terminal,
};
use std::{error::Error, io};
@@ -106,14 +106,32 @@ fn ui<B: Backend>(f: &mut Frame<B>) {
.split(chunks[1]);
// Bottom left block with all default borders
let block = Block::default().title("With borders").borders(Borders::ALL);
f.render_widget(block, bottom_chunks[0]);
let block = Block::default()
.title("With borders")
.borders(Borders::ALL)
.padding(Padding {
left: 4,
right: 4,
top: 2,
bottom: 2,
});
let text = Paragraph::new("text inside padded block").block(block);
f.render_widget(text, bottom_chunks[0]);
// Bottom right block with styled left and right border
let block = Block::default()
.title("With styled borders and doubled borders")
.border_style(Style::default().fg(Color::Cyan))
.borders(Borders::LEFT | Borders::RIGHT)
.border_type(BorderType::Double);
.border_type(BorderType::Double)
.padding(Padding::uniform(1));
let inner_block = Block::default()
.title("Block inside padded block")
.borders(Borders::ALL);
let inner_area = block.inner(bottom_chunks[1]);
f.render_widget(block, bottom_chunks[1]);
f.render_widget(inner_block, inner_area);
}

View File

@@ -26,6 +26,61 @@ impl BorderType {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Padding {
pub left: u16,
pub right: u16,
pub top: u16,
pub bottom: u16,
}
impl Padding {
pub fn new(left: u16, right: u16, top: u16, bottom: u16) -> Self {
Padding {
left,
right,
top,
bottom,
}
}
pub fn zero() -> Self {
Padding {
left: 0,
right: 0,
top: 0,
bottom: 0,
}
}
pub fn horizontal(value: u16) -> Self {
Padding {
left: value,
right: value,
top: 0,
bottom: 0,
}
}
pub fn vertical(value: u16) -> Self {
Padding {
left: 0,
right: 0,
top: value,
bottom: value,
}
}
pub fn uniform(value: u16) -> Self {
Padding {
left: value,
right: value,
top: value,
bottom: value,
}
}
}
/// Base widget to be used with all upper level ones. It may be used to display a box border around
/// the widget and/or add a title.
///
@@ -59,6 +114,8 @@ pub struct Block<'a> {
border_type: BorderType,
/// Widget style
style: Style,
/// Block padding
padding: Padding,
}
impl<'a> Default for Block<'a> {
@@ -71,6 +128,7 @@ impl<'a> Default for Block<'a> {
border_style: Default::default(),
border_type: BorderType::Plain,
style: Default::default(),
padding: Padding::zero(),
}
}
}
@@ -143,8 +201,24 @@ impl<'a> Block<'a> {
if self.borders.intersects(Borders::BOTTOM) {
inner.height = inner.height.saturating_sub(1);
}
inner.x = inner.x.saturating_add(self.padding.left);
inner.y = inner.y.saturating_add(self.padding.top);
inner.width = inner
.width
.saturating_sub(self.padding.left + self.padding.right);
inner.height = inner
.height
.saturating_sub(self.padding.top + self.padding.bottom);
inner
}
pub fn padding(mut self, padding: Padding) -> Block<'a> {
self.padding = padding;
self
}
}
impl<'a> Widget for Block<'a> {

View File

@@ -32,7 +32,7 @@ mod table;
mod tabs;
pub use self::barchart::BarChart;
pub use self::block::{Block, BorderType};
pub use self::block::{Block, BorderType, Padding};
pub use self::chart::{Axis, Chart, Dataset, GraphType};
pub use self::clear::Clear;
pub use self::gauge::{Gauge, LineGauge};

View File

@@ -3,7 +3,7 @@ use ratatui::{
buffer::Buffer,
layout::Alignment,
text::{Span, Spans, Text},
widgets::{Block, Borders, Paragraph, Wrap},
widgets::{Block, Borders, Padding, Paragraph, Wrap},
Terminal,
};
@@ -15,7 +15,7 @@ const SAMPLE_STRING: &str = "The library is based on the principle of immediate
#[test]
fn widgets_paragraph_can_wrap_its_content() {
let test_case = |alignment, expected| {
let backend = TestBackend::new(20, 10);
let backend = TestBackend::new(22, 12);
let mut terminal = Terminal::new(backend).unwrap();
terminal
@@ -23,7 +23,12 @@ fn widgets_paragraph_can_wrap_its_content() {
let size = f.size();
let text = vec![Spans::from(SAMPLE_STRING)];
let paragraph = Paragraph::new(text)
.block(Block::default().borders(Borders::ALL))
.block(Block::default().borders(Borders::ALL).padding(Padding {
left: 2,
right: 2,
top: 1,
bottom: 1,
}))
.alignment(alignment)
.wrap(Wrap { trim: true });
f.render_widget(paragraph, size);
@@ -35,46 +40,52 @@ fn widgets_paragraph_can_wrap_its_content() {
test_case(
Alignment::Left,
Buffer::with_lines(vec![
"┌──────────────────┐",
"The library is",
"based on the ",
"principle of",
"immediate ",
"rendering with",
"intermediate ",
"buffers. This",
"means that at each",
"└──────────────────┘",
"┌────────────────────",
" ",
" The library is",
" based on the",
" principle of",
" immediate ",
" rendering with",
" intermediate ",
" buffers. This ",
"│ means that at │",
"│ │",
"└────────────────────┘",
]),
);
test_case(
Alignment::Right,
Buffer::with_lines(vec![
"┌──────────────────┐",
"The library is",
" based on the",
"principle of",
" immediate",
"rendering with",
" intermediate",
"buffers. This",
"means that at each",
"└──────────────────┘",
"┌────────────────────",
" ",
"The library is ",
"based on the ",
"principle of ",
" immediate ",
"rendering with ",
" intermediate ",
" buffers. This ",
"│ means that at │",
"│ │",
"└────────────────────┘",
]),
);
test_case(
Alignment::Center,
Buffer::with_lines(vec![
"┌──────────────────┐",
"The library is",
"based on the",
"principle of",
" immediate",
"rendering with",
"intermediate",
"buffers. This",
"means that at each",
"└──────────────────┘",
"┌────────────────────",
" ",
"The library is",
" based on the ",
"principle of",
" immediate ",
"rendering with",
" intermediate ",
" buffers. This ",
"│ means that at │",
"│ │",
"└────────────────────┘",
]),
);
}