diff --git a/src/widgets/list.rs b/src/widgets/list.rs index 3f491d44..6c330a7e 100644 --- a/src/widgets/list.rs +++ b/src/widgets/list.rs @@ -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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + 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::>(); + let list = List::new(items); + let buffer = render_widget(list, 5, 3); + let expected = Buffer::with_lines(vec!["Large", " ", " "]); + assert_buffer_eq!(buffer, expected); + } }