@@ -22,6 +22,20 @@ pub use title::{Position, Title};
22
22
/// [`Title`] using [`Block::title`]. It can also be [styled](Block::style) and
23
23
/// [padded](Block::padding).
24
24
///
25
+ /// You can call the title methods multiple times to add multiple titles. Each title will be
26
+ /// rendered with a single space separating titles that are in the same position or alignment. When
27
+ /// both centered and non-centered titles are rendered, the centered space is calculated based on
28
+ /// the full width of the block, rather than the leftover width.
29
+ ///
30
+ /// Titles are not rendered in the corners of the block unless there is no border on that edge.
31
+ /// If the block is too small and multiple titles overlap, the border may get cut off at a corner.
32
+ ///
33
+ /// ```plain
34
+ /// ┌With at least a left border───
35
+ ///
36
+ /// Without left border───
37
+ /// ```
38
+ ///
25
39
/// # Examples
26
40
///
27
41
/// ```
@@ -228,6 +242,62 @@ impl<'a> Block<'a> {
228
242
self
229
243
}
230
244
245
+ /// Adds a title to the top of the block.
246
+ ///
247
+ /// You can provide any type that can be converted into [`Line`] including: strings, string
248
+ /// slices (`&str`), borrowed strings (`Cow<str>`), [spans](crate::text::Span), or vectors of
249
+ /// [spans](crate::text::Span) (`Vec<Span>`).
250
+ ///
251
+ /// # Example
252
+ ///
253
+ /// ```
254
+ /// # use ratatui::{ prelude::*, widgets::* };
255
+ /// Block::bordered()
256
+ /// .title_top("Left1") // By default in the top left corner
257
+ /// .title_top(Line::from("Left2").left_aligned())
258
+ /// .title_top(Line::from("Right").right_aligned())
259
+ /// .title_top(Line::from("Center").centered());
260
+ ///
261
+ /// // Renders
262
+ /// // ┌Left1─Left2───Center─────────Right┐
263
+ /// // │ │
264
+ /// // └──────────────────────────────────┘
265
+ /// ```
266
+ #[ must_use = "method moves the value of self and returns the modified value" ]
267
+ pub fn title_top < T : Into < Line < ' a > > > ( mut self , title : T ) -> Self {
268
+ let title = Title :: from ( title) . position ( Position :: Top ) ;
269
+ self . titles . push ( title) ;
270
+ self
271
+ }
272
+
273
+ /// Adds a title to the bottom of the block.
274
+ ///
275
+ /// You can provide any type that can be converted into [`Line`] including: strings, string
276
+ /// slices (`&str`), borrowed strings (`Cow<str>`), [spans](crate::text::Span), or vectors of
277
+ /// [spans](crate::text::Span) (`Vec<Span>`).
278
+ ///
279
+ /// # Example
280
+ ///
281
+ /// ```
282
+ /// # use ratatui::{ prelude::*, widgets::* };
283
+ /// Block::bordered()
284
+ /// .title_bottom("Left1") // By default in the top left corner
285
+ /// .title_bottom(Line::from("Left2").left_aligned())
286
+ /// .title_bottom(Line::from("Right").right_aligned())
287
+ /// .title_bottom(Line::from("Center").centered());
288
+ ///
289
+ /// // Renders
290
+ /// // ┌──────────────────────────────────┐
291
+ /// // │ │
292
+ /// // └Left1─Left2───Center─────────Right┘
293
+ /// ```
294
+ #[ must_use = "method moves the value of self and returns the modified value" ]
295
+ pub fn title_bottom < T : Into < Line < ' a > > > ( mut self , title : T ) -> Self {
296
+ let title = Title :: from ( title) . position ( Position :: Bottom ) ;
297
+ self . titles . push ( title) ;
298
+ self
299
+ }
300
+
231
301
/// Applies the style to all titles.
232
302
///
233
303
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
@@ -655,6 +725,7 @@ impl Block<'_> {
655
725
. right ( )
656
726
. saturating_sub ( title_width)
657
727
. max ( titles_area. left ( ) ) ,
728
+ width : title_width. min ( titles_area. width ) ,
658
729
..titles_area
659
730
} ;
660
731
buf. set_style ( title_area, self . titles_style ) ;
@@ -1130,6 +1201,50 @@ mod tests {
1130
1201
)
1131
1202
}
1132
1203
1204
+ #[ test]
1205
+ fn title ( ) {
1206
+ let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 15 , 3 ) ) ;
1207
+ use Alignment :: * ;
1208
+ use Position :: * ;
1209
+ Block :: bordered ( )
1210
+ . title ( Title :: from ( "A" ) . position ( Top ) . alignment ( Left ) )
1211
+ . title ( Title :: from ( "B" ) . position ( Top ) . alignment ( Center ) )
1212
+ . title ( Title :: from ( "C" ) . position ( Top ) . alignment ( Right ) )
1213
+ . title ( Title :: from ( "D" ) . position ( Bottom ) . alignment ( Left ) )
1214
+ . title ( Title :: from ( "E" ) . position ( Bottom ) . alignment ( Center ) )
1215
+ . title ( Title :: from ( "F" ) . position ( Bottom ) . alignment ( Right ) )
1216
+ . render ( buffer. area , & mut buffer) ;
1217
+ assert_buffer_eq ! (
1218
+ buffer,
1219
+ Buffer :: with_lines( vec![
1220
+ "┌A─────B─────C┐" ,
1221
+ "│ │" ,
1222
+ "└D─────E─────F┘" ,
1223
+ ] )
1224
+ ) ;
1225
+ }
1226
+
1227
+ #[ test]
1228
+ fn title_top_bottom ( ) {
1229
+ let mut buffer = Buffer :: empty ( Rect :: new ( 0 , 0 , 15 , 3 ) ) ;
1230
+ Block :: bordered ( )
1231
+ . title_top ( Line :: raw ( "A" ) . left_aligned ( ) )
1232
+ . title_top ( Line :: raw ( "B" ) . centered ( ) )
1233
+ . title_top ( Line :: raw ( "C" ) . right_aligned ( ) )
1234
+ . title_bottom ( Line :: raw ( "D" ) . left_aligned ( ) )
1235
+ . title_bottom ( Line :: raw ( "E" ) . centered ( ) )
1236
+ . title_bottom ( Line :: raw ( "F" ) . right_aligned ( ) )
1237
+ . render ( buffer. area , & mut buffer) ;
1238
+ assert_buffer_eq ! (
1239
+ buffer,
1240
+ Buffer :: with_lines( vec![
1241
+ "┌A─────B─────C┐" ,
1242
+ "│ │" ,
1243
+ "└D─────E─────F┘" ,
1244
+ ] )
1245
+ ) ;
1246
+ }
1247
+
1133
1248
#[ test]
1134
1249
fn title_alignment ( ) {
1135
1250
let tests = vec ! [
0 commit comments