Skip to content

Commit

Permalink
fix(tabs): Tab widget now supports custom padding (#629)
Browse files Browse the repository at this point in the history
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 #502
  • Loading branch information
rhaskia committed Dec 4, 2023
1 parent 458fa90 commit 28ac55b
Showing 1 changed file with 118 additions and 6 deletions.
124 changes: 118 additions & 6 deletions src/widgets/tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use crate::{
///
/// 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
/// 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
///
Expand All @@ -24,7 +26,8 @@ use crate::{
/// .style(Style::default().white())
/// .highlight_style(Style::default().yellow())
/// .select(2)
/// .divider(symbols::DOT);
/// .divider(symbols::DOT)
/// .padding("->", "<-");
/// ```
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Tabs<'a> {
Expand All @@ -40,6 +43,10 @@ pub struct Tabs<'a> {
highlight_style: Style,
/// Tab divider
divider: Span<'a>,
/// Tab Left Padding
padding_left: Line<'a>,
/// Tab Right Padding
padding_right: Line<'a>,
}

impl<'a> Tabs<'a> {
Expand Down Expand Up @@ -72,6 +79,8 @@ impl<'a> Tabs<'a> {
style: Style::default(),
highlight_style: Style::default(),
divider: Span::raw(symbols::line::VERTICAL),
padding_left: Line::from(" "),
padding_right: Line::from(" "),
}
}

Expand All @@ -83,7 +92,7 @@ impl<'a> Tabs<'a> {

/// Sets the selected tab.
///
/// The first tab has index 0 (this is also the default index).
/// The first tab has index 0 (this is also the default index).
/// The selected tab can have a different style with [`Tabs::highlight_style`].
pub fn select(mut self, selected: usize) -> Tabs<'a> {
self.selected = selected;
Expand Down Expand Up @@ -121,7 +130,7 @@ impl<'a> Tabs<'a> {
/// ```
/// 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("-");
/// ```
pub fn divider<T>(mut self, divider: T) -> Tabs<'a>
Expand All @@ -131,6 +140,70 @@ impl<'a> Tabs<'a> {
self.divider = divider.into();
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> {
Expand Down Expand Up @@ -165,11 +238,21 @@ impl<'a> Widget for Tabs<'a> {
let titles_length = self.titles.len();
for (i, title) in self.titles.into_iter().enumerate() {
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);
if remaining_width == 0 {
break;
}

// Title
let pos = buf.set_line(x, tabs_area.top(), &title, remaining_width);
if i == self.selected {
buf.set_style(
Expand All @@ -182,11 +265,20 @@ impl<'a> Widget for Tabs<'a> {
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);
if remaining_width == 0 || last_title {
break;
}

let pos = buf.set_span(x, tabs_area.top(), &self.divider, remaining_width);
x = pos.0;
}
Expand Down Expand Up @@ -216,6 +308,8 @@ mod tests {
style: Style::default(),
highlight_style: Style::default(),
divider: Span::raw(symbols::line::VERTICAL),
padding_right: Line::from(" "),
padding_left: Line::from(" "),
}
);
}
Expand All @@ -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]
fn render_with_block() {
let tabs = Tabs::new(vec!["Tab1", "Tab2", "Tab3", "Tab4"])
Expand Down

0 comments on commit 28ac55b

Please sign in to comment.