mirror of
https://github.com/ratatui-org/ratatui
synced 2024-12-04 02:20:01 +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::{
|
use crate::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::{Corner, Rect},
|
layout::{Alignment, Corner, Rect},
|
||||||
style::{Style, Styled},
|
style::{Style, Styled},
|
||||||
text::Text,
|
text::Text,
|
||||||
widgets::{Block, HighlightSpacing, StatefulWidget, Widget},
|
widgets::{Block, HighlightSpacing, StatefulWidget, Widget},
|
||||||
|
@ -286,7 +286,14 @@ impl<'a> StatefulWidget for List<'a> {
|
||||||
} else {
|
} else {
|
||||||
(x, list_area.width)
|
(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 {
|
if is_selected {
|
||||||
buf.set_style(area, self.highlight_style);
|
buf.set_style(area, self.highlight_style);
|
||||||
|
@ -333,6 +340,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
assert_buffer_eq,
|
assert_buffer_eq,
|
||||||
|
prelude::Alignment,
|
||||||
style::{Color, Modifier, Stylize},
|
style::{Color, Modifier, Stylize},
|
||||||
text::{Line, Span},
|
text::{Line, Span},
|
||||||
widgets::{Borders, StatefulWidget, Widget},
|
widgets::{Borders, StatefulWidget, Widget},
|
||||||
|
@ -1065,4 +1073,160 @@ mod tests {
|
||||||
.remove_modifier(Modifier::DIM)
|
.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