mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-26 22:50:47 +00:00
fix(tabs): Tab widget now supports custom padding (#629)
The Tab widget now contains padding_left and and padding_right properties. Those values can be set with functions `padding_left()`, `padding_right()`, and `padding()` whic all accept `Into<Line>`. Fixes issue https://github.com/ratatui-org/ratatui/issues/502
This commit is contained in:
parent
458fa90362
commit
28ac55bc62
1 changed files with 118 additions and 6 deletions
|
@ -12,7 +12,9 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// Each tab title is stored as a [`Line`] which can be individually styled. The selected tab is set
|
/// Each tab title is stored as a [`Line`] which can be individually styled. The selected tab is set
|
||||||
/// using [`Tabs::select`] and styled using [`Tabs::highlight_style`]. The divider can be customized
|
/// using [`Tabs::select`] and styled using [`Tabs::highlight_style`]. The divider can be customized
|
||||||
/// with [`Tabs::divider`].
|
/// with [`Tabs::divider`]. Padding can be set with [`Tabs::padding`] or [`Tabs::left_padding`] and [`Tabs::right_padding`].
|
||||||
|
///
|
||||||
|
/// The divider defaults to |, and padding defaults to a singular space on each side.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -24,7 +26,8 @@ use crate::{
|
||||||
/// .style(Style::default().white())
|
/// .style(Style::default().white())
|
||||||
/// .highlight_style(Style::default().yellow())
|
/// .highlight_style(Style::default().yellow())
|
||||||
/// .select(2)
|
/// .select(2)
|
||||||
/// .divider(symbols::DOT);
|
/// .divider(symbols::DOT)
|
||||||
|
/// .padding("->", "<-");
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Tabs<'a> {
|
pub struct Tabs<'a> {
|
||||||
|
@ -40,6 +43,10 @@ pub struct Tabs<'a> {
|
||||||
highlight_style: Style,
|
highlight_style: Style,
|
||||||
/// Tab divider
|
/// Tab divider
|
||||||
divider: Span<'a>,
|
divider: Span<'a>,
|
||||||
|
/// Tab Left Padding
|
||||||
|
padding_left: Line<'a>,
|
||||||
|
/// Tab Right Padding
|
||||||
|
padding_right: Line<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tabs<'a> {
|
impl<'a> Tabs<'a> {
|
||||||
|
@ -72,6 +79,8 @@ impl<'a> Tabs<'a> {
|
||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
highlight_style: Style::default(),
|
highlight_style: Style::default(),
|
||||||
divider: Span::raw(symbols::line::VERTICAL),
|
divider: Span::raw(symbols::line::VERTICAL),
|
||||||
|
padding_left: Line::from(" "),
|
||||||
|
padding_right: Line::from(" "),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +130,7 @@ impl<'a> Tabs<'a> {
|
||||||
/// ```
|
/// ```
|
||||||
/// Use dash (`-`) as separator.
|
/// Use dash (`-`) as separator.
|
||||||
/// ```
|
/// ```
|
||||||
/// # use ratatui::{prelude::*, widgets::Tabs, symbols};
|
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||||
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).divider("-");
|
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).divider("-");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn divider<T>(mut self, divider: T) -> Tabs<'a>
|
pub fn divider<T>(mut self, divider: T) -> Tabs<'a>
|
||||||
|
@ -131,6 +140,70 @@ impl<'a> Tabs<'a> {
|
||||||
self.divider = divider.into();
|
self.divider = divider.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the padding between tabs.
|
||||||
|
///
|
||||||
|
/// Both default to space.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A space on either side of the tabs.
|
||||||
|
/// ```
|
||||||
|
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||||
|
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).padding(" ", " ");
|
||||||
|
/// ```
|
||||||
|
/// Nothing on either side of the tabs.
|
||||||
|
/// ```
|
||||||
|
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||||
|
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).padding("", "");
|
||||||
|
/// ```
|
||||||
|
pub fn padding<T, U>(mut self, left: T, right: U) -> Tabs<'a>
|
||||||
|
where
|
||||||
|
T: Into<Line<'a>>,
|
||||||
|
U: Into<Line<'a>>,
|
||||||
|
{
|
||||||
|
self.padding_left = left.into();
|
||||||
|
self.padding_right = right.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the left side padding between tabs.
|
||||||
|
///
|
||||||
|
/// Defaults to a space.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// An arrow on the left of tabs.
|
||||||
|
/// ```
|
||||||
|
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||||
|
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).padding_left("->");
|
||||||
|
/// ```
|
||||||
|
pub fn padding_left<T>(mut self, padding: T) -> Tabs<'a>
|
||||||
|
where
|
||||||
|
T: Into<Line<'a>>,
|
||||||
|
{
|
||||||
|
self.padding_left = padding.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the right side padding between tabs.
|
||||||
|
///
|
||||||
|
/// Defaults to a space.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// An arrow on the right of tabs.
|
||||||
|
/// ```
|
||||||
|
/// # use ratatui::{prelude::*, widgets::Tabs};
|
||||||
|
/// let tabs = Tabs::new(vec!["Tab 1", "Tab 2"]).padding_right("<-");
|
||||||
|
/// ```
|
||||||
|
pub fn padding_right<T>(mut self, padding: T) -> Tabs<'a>
|
||||||
|
where
|
||||||
|
T: Into<Line<'a>>,
|
||||||
|
{
|
||||||
|
self.padding_left = padding.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Styled for Tabs<'a> {
|
impl<'a> Styled for Tabs<'a> {
|
||||||
|
@ -165,11 +238,21 @@ impl<'a> Widget for Tabs<'a> {
|
||||||
let titles_length = self.titles.len();
|
let titles_length = self.titles.len();
|
||||||
for (i, title) in self.titles.into_iter().enumerate() {
|
for (i, title) in self.titles.into_iter().enumerate() {
|
||||||
let last_title = titles_length - 1 == i;
|
let last_title = titles_length - 1 == i;
|
||||||
x = x.saturating_add(1);
|
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||||
|
|
||||||
|
if remaining_width == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left Padding
|
||||||
|
let pos = buf.set_line(x, tabs_area.top(), &self.padding_left, remaining_width);
|
||||||
|
x = pos.0;
|
||||||
let remaining_width = tabs_area.right().saturating_sub(x);
|
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||||
if remaining_width == 0 {
|
if remaining_width == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Title
|
||||||
let pos = buf.set_line(x, tabs_area.top(), &title, remaining_width);
|
let pos = buf.set_line(x, tabs_area.top(), &title, remaining_width);
|
||||||
if i == self.selected {
|
if i == self.selected {
|
||||||
buf.set_style(
|
buf.set_style(
|
||||||
|
@ -182,11 +265,20 @@ impl<'a> Widget for Tabs<'a> {
|
||||||
self.highlight_style,
|
self.highlight_style,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
x = pos.0.saturating_add(1);
|
x = pos.0;
|
||||||
|
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||||
|
if remaining_width == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right Padding
|
||||||
|
let pos = buf.set_line(x, tabs_area.top(), &self.padding_right, remaining_width);
|
||||||
|
x = pos.0;
|
||||||
let remaining_width = tabs_area.right().saturating_sub(x);
|
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||||
if remaining_width == 0 || last_title {
|
if remaining_width == 0 || last_title {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = buf.set_span(x, tabs_area.top(), &self.divider, remaining_width);
|
let pos = buf.set_span(x, tabs_area.top(), &self.divider, remaining_width);
|
||||||
x = pos.0;
|
x = pos.0;
|
||||||
}
|
}
|
||||||
|
@ -216,6 +308,8 @@ mod tests {
|
||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
highlight_style: Style::default(),
|
highlight_style: Style::default(),
|
||||||
divider: Span::raw(symbols::line::VERTICAL),
|
divider: Span::raw(symbols::line::VERTICAL),
|
||||||
|
padding_right: Line::from(" "),
|
||||||
|
padding_left: Line::from(" "),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -235,6 +329,24 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_no_padding() {
|
||||||
|
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"]).padding("", "");
|
||||||
|
assert_buffer_eq!(
|
||||||
|
render(tabs, Rect::new(0, 0, 30, 1)),
|
||||||
|
Buffer::with_lines(vec!["Tab1│Tab2│Tab3│Tab4 "])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_more_padding() {
|
||||||
|
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"]).padding(" ", " ");
|
||||||
|
assert_buffer_eq!(
|
||||||
|
render(tabs, Rect::new(0, 0, 30, 1)),
|
||||||
|
Buffer::with_lines(vec![" Tab1 │ Tab2 │ Tab3 │"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn render_with_block() {
|
fn render_with_block() {
|
||||||
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"])
|
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"])
|
||||||
|
|
Loading…
Reference in a new issue