fix(block): make inner aware of title positions (#657)

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.
This commit is contained in:
Jan Ferdinand Sauer 2023-12-03 13:57:59 +01:00 committed by GitHub
parent 753e246531
commit 56fc410105
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 3 deletions

View file

@ -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);
}
@ -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.
@ -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);

View file

@ -295,7 +295,7 @@ mod test {
backend::TestBackend,
style::{Color, Modifier, Stylize},
text::{Line, Span},
widgets::Borders,
widgets::{block::Position, Borders},
Terminal,
};
@ -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.";