Skip to content

Commit

Permalink
feat(widget): support adding padding to Block (#20)
Browse files Browse the repository at this point in the history
Co-authored-by: Igor Mandello <[email protected]>
Co-authored-by: Léon Sautour <[email protected]>
  • Loading branch information
3 people authored Apr 27, 2023
1 parent 26cf1f7 commit 782820c
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 38 deletions.
26 changes: 22 additions & 4 deletions examples/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
}
74 changes: 74 additions & 0 deletions src/widgets/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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> {
Expand All @@ -71,6 +128,7 @@ impl<'a> Default for Block<'a> {
border_style: Default::default(),
border_type: BorderType::Plain,
style: Default::default(),
padding: Padding::zero(),
}
}
}
Expand Down Expand Up @@ -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> {
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
77 changes: 44 additions & 33 deletions tests/widgets_paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand All @@ -15,15 +15,20 @@ 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
.draw(|f| {
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);
Expand All @@ -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 │",
"│ │",
"└────────────────────┘",
]),
);
}
Expand Down

0 comments on commit 782820c

Please sign in to comment.