@@ -933,41 +933,74 @@ impl Block<'_> {
933933 }
934934
935935 /// Render titles in the center of the block
936- ///
937- /// Currently this method aligns the titles to the left inside a centered area. This is not
938- /// ideal and should be fixed in the future to align the titles to the center of the block and
939- /// truncate both sides of the titles if the block is too small to fit all titles.
940- #[ expect( clippy:: similar_names) ]
941936 fn render_center_titles ( & self , position : TitlePosition , area : Rect , buf : & mut Buffer ) {
937+ let area = self . titles_area ( area, position) ;
942938 let titles = self
943939 . filtered_titles ( position, Alignment :: Center )
944940 . collect_vec ( ) ;
941+ // titles are rendered with a space after each title except the last one
945942 let total_width = titles
946943 . iter ( )
947- . map ( |title| title. width ( ) as u16 + 1 ) // space between titles
944+ . map ( |title| title. width ( ) as u16 + 1 )
948945 . sum :: < u16 > ( )
949- . saturating_sub ( 1 ) ; // no space for the last title
946+ . saturating_sub ( 1 ) ;
947+
948+ if total_width <= area. width {
949+ self . render_centered_titles_without_truncation ( titles, total_width, area, buf) ;
950+ } else {
951+ self . render_centered_titles_with_truncation ( titles, total_width, area, buf) ;
952+ }
953+ }
950954
951- let titles_area = self . titles_area ( area, position) ;
952- let mut titles_area = Rect {
953- x : titles_area. left ( ) + ( titles_area. width . saturating_sub ( total_width) / 2 ) ,
954- ..titles_area
955- } ;
955+ fn render_centered_titles_without_truncation (
956+ & self ,
957+ titles : Vec < & Line < ' _ > > ,
958+ total_width : u16 ,
959+ area : Rect ,
960+ buf : & mut Buffer ,
961+ ) {
962+ // titles fit in the area, center them
963+ let x = area. left ( ) + area. width . saturating_sub ( total_width) / 2 ;
964+ let mut area = Rect { x, ..area } ;
956965 for title in titles {
957- if titles_area. is_empty ( ) {
958- break ;
959- }
960- let title_width = title. width ( ) as u16 ;
961- let title_area = Rect {
962- width : title_width. min ( titles_area. width ) ,
963- ..titles_area
964- } ;
966+ let width = title. width ( ) as u16 ;
967+ let title_area = Rect { width, ..area } ;
965968 buf. set_style ( title_area, self . titles_style ) ;
966969 title. render ( title_area, buf) ;
970+ // Move the rendering cursor to the right, leaving 1 column space.
971+ area. x = area. x . saturating_add ( width + 1 ) ;
972+ area. width = area. width . saturating_sub ( width + 1 ) ;
973+ }
974+ }
967975
968- // bump the titles area to the right and reduce its width
969- titles_area. x = titles_area. x . saturating_add ( title_width + 1 ) ;
970- titles_area. width = titles_area. width . saturating_sub ( title_width + 1 ) ;
976+ fn render_centered_titles_with_truncation (
977+ & self ,
978+ titles : Vec < & Line < ' _ > > ,
979+ total_width : u16 ,
980+ mut area : Rect ,
981+ buf : & mut Buffer ,
982+ ) {
983+ // titles do not fit in the area, truncate the left side using an offset. The right side
984+ // is truncated by the area width.
985+ let mut offset = total_width. saturating_sub ( area. width ) / 2 ;
986+ for title in titles {
987+ if area. is_empty ( ) {
988+ break ;
989+ }
990+ let width = area. width . min ( title. width ( ) as u16 ) . saturating_sub ( offset) ;
991+ let title_area = Rect { width, ..area } ;
992+ buf. set_style ( title_area, self . titles_style ) ;
993+ if offset > 0 {
994+ // truncate the left side of the title to fit the area
995+ title. clone ( ) . right_aligned ( ) . render ( title_area, buf) ;
996+ offset = offset. saturating_sub ( width) . saturating_sub ( 1 ) ;
997+ } else {
998+ // truncate the right side of the title to fit the area if needed
999+ title. clone ( ) . left_aligned ( ) . render ( title_area, buf) ;
1000+ }
1001+ // Leave 1 column of spacing between titles.
1002+ area. x = area. x . saturating_add ( width + 1 ) ;
1003+ area. width = area. width . saturating_sub ( width + 1 ) ;
9711004 }
9721005 }
9731006
@@ -1936,6 +1969,16 @@ mod tests {
19361969 pretty_assertions:: assert_eq!( Buffer :: with_lines( expected. lines( ) ) , buffer) ;
19371970 }
19381971
1972+ #[ test]
1973+ fn left_titles ( ) {
1974+ let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 1 ) ) ;
1975+ Block :: new ( )
1976+ . title ( "L12" )
1977+ . title ( "L34" )
1978+ . render ( buffer. area , & mut buffer) ;
1979+ assert_eq ! ( buffer, Buffer :: with_lines( [ "L12 L34 " ] ) ) ;
1980+ }
1981+
19391982 #[ test]
19401983 fn left_titles_truncated ( ) {
19411984 let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 1 ) ) ;
@@ -1946,20 +1989,34 @@ mod tests {
19461989 assert_eq ! ( buffer, Buffer :: with_lines( [ "L12345 L67" ] ) ) ;
19471990 }
19481991
1949- /// Note: this test is probably not what you'd expect, but it is how it works in the current
1950- /// implementation. Update this if the behavior changes.
1951- ///
1952- /// This probably should render the titles centered as a whole and then truncate both titles
1953- /// to fit, but instead it renders each title and truncates them individually. This causes the
1954- /// left title to be displayed in full, while the right title is truncated.
1992+ #[ test]
1993+ fn center_titles ( ) {
1994+ let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 1 ) ) ;
1995+ Block :: new ( )
1996+ . title ( Line :: from ( "C12" ) . centered ( ) )
1997+ . title ( Line :: from ( "C34" ) . centered ( ) )
1998+ . render ( buffer. area , & mut buffer) ;
1999+ assert_eq ! ( buffer, Buffer :: with_lines( [ " C12 C34 " ] ) ) ;
2000+ }
2001+
19552002 #[ test]
19562003 fn center_titles_truncated ( ) {
19572004 let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 1 ) ) ;
19582005 Block :: new ( )
19592006 . title ( Line :: from ( "C12345" ) . centered ( ) )
19602007 . title ( Line :: from ( "C67890" ) . centered ( ) )
19612008 . render ( buffer. area , & mut buffer) ;
1962- assert_eq ! ( buffer, Buffer :: with_lines( [ "C12345 678" ] ) ) ;
2009+ assert_eq ! ( buffer, Buffer :: with_lines( [ "12345 C678" ] ) ) ;
2010+ }
2011+
2012+ #[ test]
2013+ fn right_titles ( ) {
2014+ let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 10 , 1 ) ) ;
2015+ Block :: new ( )
2016+ . title ( Line :: from ( "R12" ) . right_aligned ( ) )
2017+ . title ( Line :: from ( "R34" ) . right_aligned ( ) )
2018+ . render ( buffer. area , & mut buffer) ;
2019+ assert_eq ! ( buffer, Buffer :: with_lines( [ " R12 R34" ] ) ) ;
19632020 }
19642021
19652022 #[ test]
0 commit comments