mirror of
https://github.com/ratatui-org/ratatui
synced 2024-12-03 09:59:31 +00:00
feat(list): support line alignment (#599)
The `List` widget now respects the alignment of `Line`s and renders them as expected.
This commit is contained in:
parent
18e19f6ce6
commit
c862aa5e9e
1 changed files with 166 additions and 2 deletions
|
@ -2,7 +2,7 @@ use unicode_width::UnicodeWidthStr;
|
|||
|
||||
use crate::{
|
||||
buffer::Buffer,
|
||||
layout::{Corner, Rect},
|
||||
layout::{Alignment, Corner, Rect},
|
||||
style::{Style, Styled},
|
||||
text::Text,
|
||||
widgets::{Block, HighlightSpacing, StatefulWidget, Widget},
|
||||
|
@ -286,7 +286,14 @@ impl<'a> StatefulWidget for List<'a> {
|
|||
} else {
|
||||
(x, list_area.width)
|
||||
};
|
||||
buf.set_line(elem_x, y + j as u16, line, max_element_width);
|
||||
let x_offset = match line.alignment {
|
||||
Some(Alignment::Center) => {
|
||||
(area.width / 2).saturating_sub(line.width() as u16 / 2)
|
||||
}
|
||||
Some(Alignment::Right) => area.width.saturating_sub(line.width() as u16),
|
||||
_ => 0,
|
||||
};
|
||||
buf.set_line(elem_x + x_offset, y + j as u16, line, max_element_width);
|
||||
}
|
||||
if is_selected {
|
||||
buf.set_style(area, self.highlight_style);
|
||||
|
@ -333,6 +340,7 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::{
|
||||
assert_buffer_eq,
|
||||
prelude::Alignment,
|
||||
style::{Color, Modifier, Stylize},
|
||||
text::{Line, Span},
|
||||
widgets::{Borders, StatefulWidget, Widget},
|
||||
|
@ -1065,4 +1073,160 @@ mod tests {
|
|||
.remove_modifier(Modifier::DIM)
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_with_alignment() {
|
||||
let items = [
|
||||
Line::from("Left").alignment(Alignment::Left),
|
||||
Line::from("Center").alignment(Alignment::Center),
|
||||
Line::from("Right").alignment(Alignment::Right),
|
||||
]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 10, 5);
|
||||
let expected = Buffer::with_lines(vec![
|
||||
"Left ",
|
||||
" Center ",
|
||||
" Right",
|
||||
" ",
|
||||
" ",
|
||||
]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_odd_line_odd_area() {
|
||||
let items = [
|
||||
Line::from("Odd").alignment(Alignment::Left),
|
||||
Line::from("Even").alignment(Alignment::Center),
|
||||
Line::from("Width").alignment(Alignment::Right),
|
||||
]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 7, 5);
|
||||
let expected =
|
||||
Buffer::with_lines(vec!["Odd ", " Even ", " Width", " ", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_even_line_even_area() {
|
||||
let items = [
|
||||
Line::from("Odd").alignment(Alignment::Left),
|
||||
Line::from("Even").alignment(Alignment::Center),
|
||||
Line::from("Width").alignment(Alignment::Right),
|
||||
]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 6, 4);
|
||||
let expected = Buffer::with_lines(vec!["Odd ", " Even ", " Width", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_odd_line_even_area() {
|
||||
let items = [
|
||||
Line::from("Odd").alignment(Alignment::Left),
|
||||
Line::from("Even").alignment(Alignment::Center),
|
||||
Line::from("Width").alignment(Alignment::Right),
|
||||
]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 8, 4);
|
||||
let expected = Buffer::with_lines(vec!["Odd ", " Even ", " Width", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_even_line_odd_area() {
|
||||
let items = [
|
||||
Line::from("Odd").alignment(Alignment::Left),
|
||||
Line::from("Even").alignment(Alignment::Center),
|
||||
Line::from("Width").alignment(Alignment::Right),
|
||||
]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 6, 5);
|
||||
let expected = Buffer::with_lines(vec!["Odd ", " Even ", " Width", " ", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_zero_line_width() {
|
||||
let items = [Line::from("This line has zero width").alignment(Alignment::Center)]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 0, 5);
|
||||
let expected = Buffer::with_lines(vec!["", "", "", "", ""]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_zero_area_width() {
|
||||
let items = [Line::from("Text").alignment(Alignment::Left)]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
// assert_buffer_eq! doesn't handle zero height buffers so we call this test manually
|
||||
// rather than using render_widget
|
||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 4, 1));
|
||||
Widget::render(list, Rect::new(0, 0, 4, 0), &mut buffer);
|
||||
let expected = Buffer::with_lines(vec![" "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_line_less_than_width() {
|
||||
let items = [Line::from("Small").alignment(Alignment::Center)]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 10, 5);
|
||||
let expected = Buffer::with_lines(vec![
|
||||
" Small ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
" ",
|
||||
]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_line_equal_to_width() {
|
||||
let items = [Line::from("Exact").alignment(Alignment::Left)]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 5, 3);
|
||||
let expected = Buffer::with_lines(vec!["Exact", " ", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_list_alignment_line_greater_than_width() {
|
||||
let items = [Line::from("Large line").alignment(Alignment::Left)]
|
||||
.into_iter()
|
||||
.map(ListItem::new)
|
||||
.collect::<Vec<ListItem>>();
|
||||
let list = List::new(items);
|
||||
let buffer = render_widget(list, 5, 3);
|
||||
let expected = Buffer::with_lines(vec!["Large", " ", " "]);
|
||||
assert_buffer_eq!(buffer, expected);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue