chore(block): deprecate block::Title (#1372)

`ratatui::widgets::block::Title` is deprecated in favor of using `Line`
to represent titles.
This removes an unnecessary layer of wrapping (string -> Span -> Line ->
Title).

This struct will be removed in a future release of Ratatui (likely
0.31).
For more information see:
<https://github.com/ratatui/ratatui/issues/738>

To update your code:
```rust
Block::new().title(Title::from("foo"));
// becomes any of
Block::new().title("foo");
Block::new().title(Line::from("foo"));

Block::new().title(Title::from("foo").position(Position::TOP));
// becomes any of
Block::new().title_top("foo");
Block::new().title_top(Line::from("foo"));

Block::new().title(Title::from("foo").position(Position::BOTTOM));
// becomes any of
Block::new().title_bottom("foo");
Block::new().title_bottom(Line::from("foo"));
```
This commit is contained in:
Josh McKinney 2024-09-20 00:21:26 -07:00 committed by GitHub
parent b9653ba05a
commit 67c0ea243b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 133 additions and 176 deletions

View file

@ -2,10 +2,8 @@ use criterion::{criterion_group, BatchSize, Bencher, Criterion};
use ratatui::{
buffer::Buffer,
layout::{Alignment, Rect},
widgets::{
block::{Position, Title},
Block, Padding, Widget,
},
text::Line,
widgets::{Block, Padding, Widget},
};
/// Benchmark for rendering a block.
@ -32,11 +30,7 @@ fn block(c: &mut Criterion) {
&Block::bordered()
.padding(Padding::new(5, 5, 2, 2))
.title("test title")
.title(
Title::from("bottom left title")
.alignment(Alignment::Right)
.position(Position::Bottom),
),
.title_bottom(Line::from("bottom left title").alignment(Alignment::Right)),
|b, block| render(b, block, buffer_size),
);
}

View file

@ -19,10 +19,7 @@ use ratatui::{
layout::{Alignment, Constraint, Layout, Rect},
style::{Style, Stylize},
text::Line,
widgets::{
block::{Position, Title},
Block, BorderType, Borders, Padding, Paragraph, Wrap,
},
widgets::{Block, BorderType, Borders, Padding, Paragraph, Wrap},
DefaultTerminal, Frame,
};
@ -164,36 +161,12 @@ fn render_multiple_titles(paragraph: &Paragraph, frame: &mut Frame, area: Rect)
fn render_multiple_title_positions(paragraph: &Paragraph, frame: &mut Frame, area: Rect) {
let block = Block::bordered()
.title(
Title::from("top left")
.position(Position::Top)
.alignment(Alignment::Left),
)
.title(
Title::from("top center")
.position(Position::Top)
.alignment(Alignment::Center),
)
.title(
Title::from("top right")
.position(Position::Top)
.alignment(Alignment::Right),
)
.title(
Title::from("bottom left")
.position(Position::Bottom)
.alignment(Alignment::Left),
)
.title(
Title::from("bottom center")
.position(Position::Bottom)
.alignment(Alignment::Center),
)
.title(
Title::from("bottom right")
.position(Position::Bottom)
.alignment(Alignment::Right),
);
.title(Line::from("top left").left_aligned())
.title(Line::from("top center").centered())
.title(Line::from("top right").right_aligned())
.title_bottom(Line::from("bottom left").left_aligned())
.title_bottom(Line::from("bottom center").centered())
.title_bottom(Line::from("bottom right").right_aligned());
frame.render_widget(paragraph.clone().block(block), area);
}

View file

@ -18,11 +18,11 @@ use std::time::{Duration, Instant};
use color_eyre::Result;
use ratatui::{
crossterm::event::{self, Event, KeyCode},
layout::{Alignment, Constraint, Layout, Rect},
layout::{Constraint, Layout, Rect},
style::{Color, Modifier, Style, Stylize},
symbols::{self, Marker},
text::Span,
widgets::{block::Title, Axis, Block, Chart, Dataset, GraphType, LegendPosition},
text::{Line, Span},
widgets::{Axis, Block, Chart, Dataset, GraphType, LegendPosition},
DefaultTerminal, Frame,
};
@ -196,13 +196,7 @@ fn render_barchart(frame: &mut Frame, bar_chart: Rect) {
]);
let chart = Chart::new(vec![dataset])
.block(
Block::bordered().title(
Title::default()
.content("Bar chart".cyan().bold())
.alignment(Alignment::Center),
),
)
.block(Block::bordered().title_top(Line::from("Bar chart").cyan().bold().centered()))
.x_axis(
Axis::default()
.style(Style::default().gray())
@ -229,13 +223,7 @@ fn render_line_chart(frame: &mut Frame, area: Rect) {
.data(&[(1., 1.), (4., 4.)])];
let chart = Chart::new(datasets)
.block(
Block::bordered().title(
Title::default()
.content("Line chart".cyan().bold())
.alignment(Alignment::Center),
),
)
.block(Block::bordered().title(Line::from("Line chart").cyan().bold().centered()))
.x_axis(
Axis::default()
.title("X Axis")
@ -279,13 +267,7 @@ fn render_scatter(frame: &mut Frame, area: Rect) {
];
let chart = Chart::new(datasets)
.block(
Block::bordered().title(
Title::default()
.content("Scatter chart".cyan().bold())
.alignment(Alignment::Center),
),
)
.block(Block::bordered().title(Line::from("Scatter chart").cyan().bold().centered()))
.x_axis(
Axis::default()
.title("Year")

View file

@ -28,8 +28,8 @@ use ratatui::{
symbols::{self, line},
text::{Line, Text},
widgets::{
block::Title, Block, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState,
StatefulWidget, Tabs, Widget,
Block, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState, StatefulWidget, Tabs,
Widget,
},
DefaultTerminal,
};
@ -273,7 +273,7 @@ impl App {
fn tabs(self) -> impl Widget {
let tab_titles = SelectedTab::iter().map(SelectedTab::to_tab_title);
let block = Block::new()
.title(Title::from("Flex Layouts ".bold()))
.title("Flex Layouts ".bold())
.title(" Use ◄ ► to change tab, ▲ ▼ to scroll, - + to change spacing ");
Tabs::new(tab_titles)
.block(block)

View file

@ -21,8 +21,8 @@ use ratatui::{
crossterm::event::{self, Event, KeyCode, KeyEventKind},
layout::{Alignment, Constraint, Layout, Rect},
style::{palette::tailwind, Color, Style, Stylize},
text::Span,
widgets::{block::Title, Block, Borders, Gauge, Padding, Paragraph, Widget},
text::{Line, Span},
widgets::{Block, Borders, Gauge, Padding, Paragraph, Widget},
DefaultTerminal,
};
@ -196,7 +196,7 @@ impl App {
}
fn title_block(title: &str) -> Block {
let title = Title::from(title).alignment(Alignment::Center);
let title = Line::from(title).centered();
Block::new()
.borders(Borders::NONE)
.padding(Padding::vertical(1))

View file

@ -25,11 +25,11 @@ use rand::distributions::{Distribution, Uniform};
use ratatui::{
backend::Backend,
crossterm::event,
layout::{Alignment, Constraint, Layout, Rect},
layout::{Constraint, Layout, Rect},
style::{Color, Modifier, Style},
symbols,
text::{Line, Span},
widgets::{block, Block, Gauge, LineGauge, List, ListItem, Paragraph, Widget},
widgets::{Block, Gauge, LineGauge, List, ListItem, Paragraph, Widget},
Frame, Terminal, TerminalOptions, Viewport,
};
@ -231,7 +231,7 @@ fn run(
fn draw(frame: &mut Frame, downloads: &Downloads) {
let area = frame.area();
let block = Block::new().title(block::Title::from("Progress").alignment(Alignment::Center));
let block = Block::new().title(Line::from("Progress").centered());
frame.render_widget(block, area);
let vertical = Layout::vertical([Constraint::Length(2), Constraint::Length(4)]).margin(1);

View file

@ -21,7 +21,8 @@ use ratatui::{
crossterm::event::{self, Event, KeyCode, KeyEventKind},
layout::{Alignment, Constraint, Layout, Rect},
style::{palette::tailwind, Color, Style, Stylize},
widgets::{block::Title, Block, Borders, LineGauge, Padding, Paragraph, Widget},
text::Line,
widgets::{Block, Borders, LineGauge, Padding, Paragraph, Widget},
DefaultTerminal,
};
@ -170,9 +171,8 @@ impl App {
}
fn title_block(title: &str) -> Block {
let title = Title::from(title).alignment(Alignment::Center);
Block::default()
.title(title)
.title(Line::from(title).centered())
.borders(Borders::NONE)
.fg(CUSTOM_LABEL_COLOR)
.padding(Padding::vertical(1))

View file

@ -108,7 +108,7 @@ pub use title::{Position, Title};
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Block<'a> {
/// List of titles
titles: Vec<Title<'a>>,
titles: Vec<(Option<Position>, Line<'a>)>,
/// The style to be patched to all titles of the block
titles_style: Style,
/// The default alignment of the titles that don't have one
@ -243,9 +243,9 @@ impl<'a> Block<'a> {
/// [spans](crate::text::Span) (`Vec<Span>`).
///
/// By default, the titles will avoid being rendered in the corners of the block but will align
/// against the left or right edge of the block if there is no border on that edge.
/// The following demonstrates this behavior, notice the second title is one character off to
/// the left.
/// against the left or right edge of the block if there is no border on that edge. The
/// following demonstrates this behavior, notice the second title is one character off to the
/// left.
///
/// ```plain
/// ┌With at least a left border───
@ -274,9 +274,9 @@ impl<'a> Block<'a> {
///
/// Block::new()
/// .title("Title") // By default in the top left corner
/// .title(Title::from("Left").alignment(Alignment::Left)) // also on the left
/// .title(Title::from("Right").alignment(Alignment::Right))
/// .title(Title::from("Center").alignment(Alignment::Center));
/// .title(Line::from("Left").left_aligned()) // also on the left
/// .title(Line::from("Right").right_aligned())
/// .title(Line::from("Center").centered());
/// // Renders
/// // ┌Title─Left────Center─────────Right┐
/// ```
@ -288,13 +288,26 @@ impl<'a> Block<'a> {
/// - [`Block::title_alignment`]
/// - [`Block::title_position`]
///
/// # Future improvements
///
/// In a future release of Ratatui this method will be changed to accept `Into<Line>` instead of
/// `Into<Title>`. This allows us to remove the unnecessary `Title` struct and store the
/// position in the block itself. For more information see
/// <https://github.com/ratatui/ratatui/issues/738>.
///
/// [Block example]: https://github.com/ratatui/ratatui/blob/main/examples/README.md#block
#[must_use = "method moves the value of self and returns the modified value"]
pub fn title<T>(mut self, title: T) -> Self
where
T: Into<Title<'a>>,
{
self.titles.push(title.into());
let title = title.into();
let position = title.position;
let mut content = title.content;
if let Some(alignment) = title.alignment {
content = content.alignment(alignment);
}
self.titles.push((position, content));
self
}
@ -321,8 +334,8 @@ impl<'a> Block<'a> {
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn title_top<T: Into<Line<'a>>>(mut self, title: T) -> Self {
let title = Title::from(title).position(Position::Top);
self.titles.push(title);
let line = title.into();
self.titles.push((Some(Position::Top), line));
self
}
@ -349,8 +362,8 @@ impl<'a> Block<'a> {
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub fn title_bottom<T: Into<Line<'a>>>(mut self, title: T) -> Self {
let title = Title::from(title).position(Position::Bottom);
self.titles.push(title);
let line = title.into();
self.titles.push((Some(Position::Bottom), line));
self
}
@ -387,7 +400,7 @@ impl<'a> Block<'a> {
/// Block::new()
/// .title_alignment(Alignment::Center)
/// // This title won't be aligned in the center
/// .title(Title::from("right").alignment(Alignment::Right))
/// .title(Line::from("right").right_aligned())
/// .title("foo")
/// .title("bar");
/// ```
@ -417,7 +430,7 @@ impl<'a> Block<'a> {
/// Block::new()
/// .title_position(Position::Bottom)
/// // This title won't be aligned in the center
/// .title(Title::from("top").position(Position::Top))
/// .title_top("top")
/// .title("foo")
/// .title("bar");
/// ```
@ -642,7 +655,7 @@ impl<'a> Block<'a> {
fn has_title_at_position(&self, position: Position) -> bool {
self.titles
.iter()
.any(|title| title.position.unwrap_or(self.titles_position) == position)
.any(|(pos, _)| pos.unwrap_or(self.titles_position) == position)
}
}
@ -798,7 +811,7 @@ impl Block<'_> {
if titles_area.is_empty() {
break;
}
let title_width = title.content.width() as u16;
let title_width = title.width() as u16;
let title_area = Rect {
x: titles_area
.right()
@ -808,7 +821,7 @@ impl Block<'_> {
..titles_area
};
buf.set_style(title_area, self.titles_style);
title.content.render_ref(title_area, buf);
title.render_ref(title_area, buf);
// bump the width of the titles area to the left
titles_area.width = titles_area
@ -830,7 +843,7 @@ impl Block<'_> {
.collect_vec();
let total_width = titles
.iter()
.map(|title| title.content.width() as u16 + 1) // space between titles
.map(|title| title.width() as u16 + 1) // space between titles
.sum::<u16>()
.saturating_sub(1); // no space for the last title
@ -843,13 +856,13 @@ impl Block<'_> {
if titles_area.is_empty() {
break;
}
let title_width = title.content.width() as u16;
let title_width = title.width() as u16;
let title_area = Rect {
width: title_width.min(titles_area.width),
..titles_area
};
buf.set_style(title_area, self.titles_style);
title.content.render_ref(title_area, buf);
title.render_ref(title_area, buf);
// bump the titles area to the right and reduce its width
titles_area.x = titles_area.x.saturating_add(title_width + 1);
@ -866,13 +879,13 @@ impl Block<'_> {
if titles_area.is_empty() {
break;
}
let title_width = title.content.width() as u16;
let title_width = title.width() as u16;
let title_area = Rect {
width: title_width.min(titles_area.width),
..titles_area
};
buf.set_style(title_area, self.titles_style);
title.content.render_ref(title_area, buf);
title.render_ref(title_area, buf);
// bump the titles area to the right and reduce its width
titles_area.x = titles_area.x.saturating_add(title_width + 1);
@ -885,11 +898,12 @@ impl Block<'_> {
&self,
position: Position,
alignment: Alignment,
) -> impl DoubleEndedIterator<Item = &Title> {
self.titles.iter().filter(move |title| {
title.position.unwrap_or(self.titles_position) == position
&& title.alignment.unwrap_or(self.titles_alignment) == alignment
})
) -> impl DoubleEndedIterator<Item = &Line> {
self.titles
.iter()
.filter(move |(pos, _)| pos.unwrap_or(self.titles_position) == position)
.filter(move |(_, line)| line.alignment.unwrap_or(self.titles_alignment) == alignment)
.map(|(_, line)| line)
}
/// An area that is one line tall and spans the width of the block excluding the borders and
@ -1023,24 +1037,17 @@ mod tests {
let area = Rect::new(0, 0, 0, 1);
let expected = Rect::new(0, 1, 0, 0);
let block = Block::new().title(Title::from("Test").alignment(alignment));
let block = Block::new().title(Line::from("Test").alignment(alignment));
assert_eq!(block.inner(area), expected);
}
#[rstest]
#[case::top_top(Borders::TOP, Position::Top, Rect::new(0, 1, 0, 1))]
#[case::top_bot(Borders::BOTTOM, Position::Top, Rect::new(0, 1, 0, 0))]
#[case::bot_top(Borders::TOP, Position::Bottom, Rect::new(0, 1, 0, 0))]
#[case::top_top(Borders::BOTTOM, Position::Bottom, Rect::new(0, 0, 0, 1))]
fn inner_takes_into_account_border_and_title(
#[case] borders: Borders,
#[case] position: Position,
#[case] expected: Rect,
) {
#[case::top_top(Block::new().title_top("Test").borders(Borders::TOP), Rect::new(0, 1, 0, 1))]
#[case::top_bot(Block::new().title_top("Test").borders(Borders::BOTTOM), Rect::new(0, 1, 0, 0))]
#[case::bot_top(Block::new().title_bottom("Test").borders(Borders::TOP), Rect::new(0, 1, 0, 0))]
#[case::bot_bot(Block::new().title_bottom("Test").borders(Borders::BOTTOM), Rect::new(0, 0, 0, 1))]
fn inner_takes_into_account_border_and_title(#[case] block: Block, #[case] expected: Rect) {
let area = Rect::new(0, 0, 0, 2);
let block = Block::new()
.borders(borders)
.title(Title::from("Test").position(position));
assert_eq!(block.inner(area), expected);
}
@ -1050,32 +1057,33 @@ mod tests {
assert!(!block.has_title_at_position(Position::Top));
assert!(!block.has_title_at_position(Position::Bottom));
let block = Block::new().title(Title::from("Test").position(Position::Top));
let block = Block::new().title_top("test");
assert!(block.has_title_at_position(Position::Top));
assert!(!block.has_title_at_position(Position::Bottom));
let block = Block::new().title(Title::from("Test").position(Position::Bottom));
let block = Block::new().title_bottom("test");
assert!(!block.has_title_at_position(Position::Top));
assert!(block.has_title_at_position(Position::Bottom));
#[allow(deprecated)] // until Title is removed
let block = Block::new()
.title(Title::from("Test").position(Position::Top))
.title_position(Position::Bottom);
assert!(block.has_title_at_position(Position::Top));
assert!(!block.has_title_at_position(Position::Bottom));
#[allow(deprecated)] // until Title is removed
let block = Block::new()
.title(Title::from("Test").position(Position::Bottom))
.title_position(Position::Top);
assert!(!block.has_title_at_position(Position::Top));
assert!(block.has_title_at_position(Position::Bottom));
let block = Block::new()
.title(Title::from("Test").position(Position::Top))
.title(Title::from("Test").position(Position::Bottom));
let block = Block::new().title_top("test").title_bottom("test");
assert!(block.has_title_at_position(Position::Top));
assert!(block.has_title_at_position(Position::Bottom));
#[allow(deprecated)] // until Title is removed
let block = Block::new()
.title(Title::from("Test").position(Position::Top))
.title(Title::from("Test"))
@ -1083,6 +1091,7 @@ mod tests {
assert!(block.has_title_at_position(Position::Top));
assert!(block.has_title_at_position(Position::Bottom));
#[allow(deprecated)] // until Title is removed
let block = Block::new()
.title(Title::from("Test"))
.title(Title::from("Test").position(Position::Bottom))
@ -1130,16 +1139,10 @@ mod tests {
#[test]
fn vertical_space_takes_into_account_titles() {
let block = Block::new()
.title_position(Position::Top)
.title(Title::from("Test"));
let block = Block::new().title_top("Test");
assert_eq!(block.vertical_space(), (1, 0));
let block = Block::new()
.title_position(Position::Bottom)
.title(Title::from("Test"));
let block = Block::new().title_bottom("Test");
assert_eq!(block.vertical_space(), (0, 1));
}
@ -1158,10 +1161,7 @@ mod tests {
#[case] pos: Position,
#[case] vertical_space: (u16, u16),
) {
let block = block
.borders(borders)
.title_position(pos)
.title(Title::from("Test"));
let block = block.borders(borders).title_position(pos).title("Test");
assert_eq!(block.vertical_space(), vertical_space);
}
@ -1310,6 +1310,7 @@ mod tests {
use Alignment::*;
use Position::*;
let mut buffer = Buffer::empty(Rect::new(0, 0, 11, 3));
#[allow(deprecated)] // until Title is removed
Block::bordered()
.title(Title::from("A").position(Top).alignment(Left))
.title(Title::from("B").position(Top).alignment(Center))
@ -1375,7 +1376,7 @@ mod tests {
let mut buffer = Buffer::empty(Rect::new(0, 0, 8, 1));
Block::new()
.title_alignment(block_title_alignment)
.title(Title::from("test").alignment(alignment))
.title(Line::from("test").alignment(alignment))
.render(buffer.area, &mut buffer);
assert_eq!(buffer, Buffer::with_lines([expected]));
}

View file

@ -9,6 +9,17 @@ use crate::{layout::Alignment, text::Line};
///
/// It can be aligned (see [`Alignment`]) and positioned (see [`Position`]).
///
/// # Future Deprecation
///
/// This type is deprecated and will be removed in a future release. The reason for this is that the
/// position of the title should be stored in the block itself, not in the title. The `Line` type
/// has an alignment method that can be used to align the title. For more information see
/// <https://github.com/ratatui/ratatui/issues/738>.
///
/// Use [`Line`] instead, when the position is not defined as part of the title. When a specific
/// position is needed, use [`Block::title_top`](crate::widgets::Block::title_top) or
/// [`Block::title_bottom`](crate::widgets::Block::title_bottom) instead.
///
/// # Example
///
/// Title with no style.
@ -88,6 +99,7 @@ pub enum Position {
Bottom,
}
#[deprecated = "use Block::title_top() or Block::title_bottom() instead. This will be removed in a future release."]
impl<'a> Title<'a> {
/// Set the title content.
#[must_use = "method moves the value of self and returns the modified value"]

View file

@ -3,11 +3,8 @@ use ratatui::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Color, Style},
text::Span,
widgets::{
block::title::{Position, Title},
Block, Borders,
},
text::{Line, Span},
widgets::{Block, Borders},
Terminal,
};
use rstest::rstest;
@ -58,9 +55,9 @@ fn widgets_block_titles_overlap() {
// Left overrides the center
test_case(
Block::new()
.title(Title::from("aaaaa").alignment(Alignment::Left))
.title(Title::from("bbb").alignment(Alignment::Center))
.title(Title::from("ccc").alignment(Alignment::Right)),
.title(Line::from("aaaaa").left_aligned())
.title(Line::from("bbb").centered())
.title(Line::from("ccc").right_aligned()),
Rect::new(0, 0, 10, 1),
["aaaaab ccc"],
);
@ -68,9 +65,9 @@ fn widgets_block_titles_overlap() {
// Left alignment overrides the center alignment which overrides the right alignment
test_case(
Block::new()
.title(Title::from("aaaaa").alignment(Alignment::Left))
.title(Title::from("bbbbb").alignment(Alignment::Center))
.title(Title::from("ccccc").alignment(Alignment::Right)),
.title(Line::from("aaaaa").left_aligned())
.title(Line::from("bbbbb").centered())
.title(Line::from("ccccc").right_aligned()),
Rect::new(0, 0, 11, 1),
["aaaaabbbccc"],
);
@ -78,10 +75,10 @@ fn widgets_block_titles_overlap() {
// Multiple left alignment overrides the center alignment and the right alignment
test_case(
Block::new()
.title(Title::from("aaaaa").alignment(Alignment::Left))
.title(Title::from("aaaaa").alignment(Alignment::Left))
.title(Title::from("bbbbb").alignment(Alignment::Center))
.title(Title::from("ccccc").alignment(Alignment::Right)),
.title(Line::from("aaaaa").left_aligned())
.title(Line::from("aaaaa").left_aligned())
.title(Line::from("bbbbb").centered())
.title(Line::from("ccccc").right_aligned()),
Rect::new(0, 0, 11, 1),
["aaaaabaaaaa"],
);
@ -89,8 +86,8 @@ fn widgets_block_titles_overlap() {
// The right alignment doesn't override the center alignment, but pierces through it
test_case(
Block::new()
.title(Title::from("bbbbb").alignment(Alignment::Center))
.title(Title::from("ccccccccccc").alignment(Alignment::Right)),
.title(Line::from("bbbbb").centered())
.title(Line::from("ccccccccccc").right_aligned()),
Rect::new(0, 0, 11, 1),
["cccbbbbbccc"],
);
@ -275,7 +272,7 @@ fn widgets_block_title_alignment_top<'line, Lines>(
let block1 = Block::new()
.borders(borders)
.title(Title::from(Span::raw("Title")).alignment(alignment));
.title(Line::from("Title").alignment(alignment));
let block2 = Block::new()
.borders(borders)
@ -379,10 +376,8 @@ fn widgets_block_title_alignment_bottom<'line, Lines>(
let backend = TestBackend::new(15, 3);
let mut terminal = Terminal::new(backend).unwrap();
let title = Title::from(Span::styled("Title", Style::default()))
.alignment(alignment)
.position(Position::Bottom);
let block = Block::default().title(title).borders(borders);
let title = Line::from("Title").alignment(alignment);
let block = Block::default().title_bottom(title).borders(borders);
let area = Rect::new(1, 0, 13, 3);
terminal
.draw(|frame| frame.render_widget(block, area))
@ -391,84 +386,84 @@ fn widgets_block_title_alignment_bottom<'line, Lines>(
}
#[rstest]
#[case::left_with_all_borders(Title::from("foo"), Title::from("bar"), Borders::ALL, [
#[case::left_with_all_borders(Line::from("foo"), Line::from("bar"), Borders::ALL, [
" ┌foo─bar────┐ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::left_without_top_border(Title::from("foo"), Title::from("bar"), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
#[case::left_without_top_border(Line::from("foo"), Line::from("bar"), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
" │foo bar │ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::left_without_left_border(Title::from("foo"), Title::from("bar"), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
#[case::left_without_left_border(Line::from("foo"), Line::from("bar"), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
" foo─bar─────┐ ",
"",
" ────────────┘ ",
])]
#[case::left_without_right_border(Title::from("foo"), Title::from("bar"), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
#[case::left_without_right_border(Line::from("foo"), Line::from("bar"), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
" ┌foo─bar───── ",
"",
" └──────────── ",
])]
#[case::left_without_borders(Title::from("foo"), Title::from("bar"), Borders::NONE, [
#[case::left_without_borders(Line::from("foo"), Line::from("bar"), Borders::NONE, [
" foo bar ",
" ",
" ",
])]
#[case::center_with_borders(Title::from("foo").alignment(Alignment::Center), Title::from("bar").alignment(Alignment::Center), Borders::ALL, [
#[case::center_with_borders(Line::from("foo").centered(), Line::from("bar").centered(), Borders::ALL, [
" ┌──foo─bar──┐ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::center_without_top_border(Title::from("foo").alignment(Alignment::Center), Title::from("bar").alignment(Alignment::Center), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
#[case::center_without_top_border(Line::from("foo").centered(), Line::from("bar").centered(), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
" │ foo bar │ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::center_without_left_border(Title::from("foo").alignment(Alignment::Center), Title::from("bar").alignment(Alignment::Center), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
#[case::center_without_left_border(Line::from("foo").centered(), Line::from("bar").centered(), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
" ──foo─bar───┐ ",
"",
" ────────────┘ ",
])]
#[case::center_without_right_border(Title::from("foo").alignment(Alignment::Center), Title::from("bar").alignment(Alignment::Center), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
#[case::center_without_right_border(Line::from("foo").centered(), Line::from("bar").centered(), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
" ┌──foo─bar─── ",
"",
" └──────────── ",
])]
#[case::center_without_borders(Title::from("foo").alignment(Alignment::Center), Title::from("bar").alignment(Alignment::Center), Borders::NONE, [
#[case::center_without_borders(Line::from("foo").centered(), Line::from("bar").centered(), Borders::NONE, [
" foo bar ",
" ",
" ",
])]
#[case::right_with_all_borders(Title::from("foo").alignment(Alignment::Right), Title::from("bar").alignment(Alignment::Right), Borders::ALL, [
#[case::right_with_all_borders(Line::from("foo").right_aligned(), Line::from("bar").right_aligned(), Borders::ALL, [
" ┌────foo─bar┐ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::right_without_top_border(Title::from("foo").alignment(Alignment::Right), Title::from("bar").alignment(Alignment::Right), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
#[case::right_without_top_border(Line::from("foo").right_aligned(), Line::from("bar").right_aligned(), Borders::LEFT | Borders::BOTTOM | Borders::RIGHT, [
" │ foo bar│ ",
" │ │ ",
" └───────────┘ ",
])]
#[case::right_without_left_border(Title::from("foo").alignment(Alignment::Right), Title::from("bar").alignment(Alignment::Right), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
#[case::right_without_left_border(Line::from("foo").right_aligned(), Line::from("bar").right_aligned(), Borders::TOP | Borders::RIGHT | Borders::BOTTOM, [
" ─────foo─bar┐ ",
"",
" ────────────┘ ",
])]
#[case::right_without_right_border(Title::from("foo").alignment(Alignment::Right), Title::from("bar").alignment(Alignment::Right), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
#[case::right_without_right_border(Line::from("foo").right_aligned(), Line::from("bar").right_aligned(), Borders::LEFT | Borders::TOP | Borders::BOTTOM, [
" ┌─────foo─bar ",
"",
" └──────────── ",
])]
#[case::right_without_borders(Title::from("foo").alignment(Alignment::Right), Title::from("bar").alignment(Alignment::Right), Borders::NONE, [
#[case::right_without_borders(Line::from("foo").right_aligned(), Line::from("bar").right_aligned(), Borders::NONE, [
" foo bar ",
" ",
" ",
])]
fn widgets_block_multiple_titles<'line, Lines>(
#[case] title_a: Title,
#[case] title_b: Title,
#[case] title_a: Line,
#[case] title_b: Line,
#[case] borders: Borders,
#[case] expected: Lines,
) where