Skip to content

Commit

Permalink
fix(block): make inner aware of title positions (#657)
Browse files Browse the repository at this point in the history
Previously, when computing the inner rendering area of a block, all
titles were assumed to be positioned at the top, which caused the
height of the inner area to be miscalculated.
  • Loading branch information
jan-ferdinand committed Dec 3, 2023
1 parent 753e246 commit 56fc410
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 3 deletions.
83 changes: 81 additions & 2 deletions src/widgets/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,14 +508,15 @@ impl<'a> Block<'a> {
inner.x = inner.x.saturating_add(1).min(inner.right());
inner.width = inner.width.saturating_sub(1);
}
if self.borders.intersects(Borders::TOP) || !self.titles.is_empty() {
if self.borders.intersects(Borders::TOP) || self.have_title_at_position(Position::Top) {
inner.y = inner.y.saturating_add(1).min(inner.bottom());
inner.height = inner.height.saturating_sub(1);
}
if self.borders.intersects(Borders::RIGHT) {
inner.width = inner.width.saturating_sub(1);
}
if self.borders.intersects(Borders::BOTTOM) {
if self.borders.intersects(Borders::BOTTOM) || self.have_title_at_position(Position::Bottom)
{
inner.height = inner.height.saturating_sub(1);
}

Expand All @@ -532,6 +533,12 @@ impl<'a> Block<'a> {
inner
}

fn have_title_at_position(&self, position: Position) -> bool {
self.titles
.iter()
.any(|title| title.position.unwrap_or(self.titles_position) == position)
}

/// Defines the padding inside a `Block`.
///
/// See [`Padding`] for more information.
Expand Down Expand Up @@ -939,6 +946,78 @@ mod tests {
);
}

#[test]
fn inner_takes_into_account_border_and_title() {
let test_rect = Rect::new(0, 0, 0, 2);

let top_top = Block::default()
.title(Title::from("Test").position(Position::Top))
.borders(Borders::TOP);
assert_eq!(top_top.inner(test_rect), Rect::new(0, 1, 0, 1));

let top_bot = Block::default()
.title(Title::from("Test").position(Position::Top))
.borders(Borders::BOTTOM);
assert_eq!(top_bot.inner(test_rect), Rect::new(0, 1, 0, 0));

let bot_top = Block::default()
.title(Title::from("Test").position(Position::Bottom))
.borders(Borders::TOP);
assert_eq!(bot_top.inner(test_rect), Rect::new(0, 1, 0, 0));

let bot_bot = Block::default()
.title(Title::from("Test").position(Position::Bottom))
.borders(Borders::BOTTOM);
assert_eq!(bot_bot.inner(test_rect), Rect::new(0, 0, 0, 1));
}

#[test]
fn have_title_at_position_takes_into_account_all_positioning_declarations() {
let block = Block::default();
assert!(!block.have_title_at_position(Position::Top));
assert!(!block.have_title_at_position(Position::Bottom));

let block = Block::default().title(Title::from("Test").position(Position::Top));
assert!(block.have_title_at_position(Position::Top));
assert!(!block.have_title_at_position(Position::Bottom));

let block = Block::default().title(Title::from("Test").position(Position::Bottom));
assert!(!block.have_title_at_position(Position::Top));
assert!(block.have_title_at_position(Position::Bottom));

let block = Block::default()
.title(Title::from("Test").position(Position::Top))
.title_position(Position::Bottom);
assert!(block.have_title_at_position(Position::Top));
assert!(!block.have_title_at_position(Position::Bottom));

let block = Block::default()
.title(Title::from("Test").position(Position::Bottom))
.title_position(Position::Top);
assert!(!block.have_title_at_position(Position::Top));
assert!(block.have_title_at_position(Position::Bottom));

let block = Block::default()
.title(Title::from("Test").position(Position::Top))
.title(Title::from("Test").position(Position::Bottom));
assert!(block.have_title_at_position(Position::Top));
assert!(block.have_title_at_position(Position::Bottom));

let block = Block::default()
.title(Title::from("Test").position(Position::Top))
.title(Title::from("Test"))
.title_position(Position::Bottom);
assert!(block.have_title_at_position(Position::Top));
assert!(block.have_title_at_position(Position::Bottom));

let block = Block::default()
.title(Title::from("Test"))
.title(Title::from("Test").position(Position::Bottom))
.title_position(Position::Top);
assert!(block.have_title_at_position(Position::Top));
assert!(block.have_title_at_position(Position::Bottom));
}

#[test]
fn border_type_can_be_const() {
const _PLAIN: border::Set = BorderType::border_symbols(BorderType::Plain);
Expand Down
16 changes: 15 additions & 1 deletion src/widgets/paragraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ mod test {
backend::TestBackend,
style::{Color, Modifier, Stylize},
text::{Line, Span},
widgets::Borders,
widgets::{block::Position, Borders},
Terminal,
};

Expand Down Expand Up @@ -478,6 +478,20 @@ mod test {
);
}

#[test]
fn test_render_paragraph_with_block_with_bottom_title_and_border() {
let block = Block::default()
.title("Title")
.title_position(Position::Bottom)
.borders(Borders::BOTTOM);
let paragraph = Paragraph::new("Hello, world!").block(block);

test_case(
&paragraph,
Buffer::with_lines(vec!["Hello, world! ", "Title──────────"]),
);
}

#[test]
fn test_render_paragraph_with_word_wrap() {
let text = "This is a long line of text that should wrap and contains a superultramegagigalong word.";
Expand Down

0 comments on commit 56fc410

Please sign in to comment.