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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 │",
|
||||
"│ │",
|
||||
"└────────────────────┘",
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user