aboutsummaryrefslogtreecommitdiffstats
path: root/src/ratatui/widgets/tabs.rs
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@elliehuxtable.com>2023-03-31 22:57:37 +0100
committerGitHub <noreply@github.com>2023-03-31 22:57:37 +0100
commita515b06bcb556c1be2d0fc3095cd778d413fe40d (patch)
tree4b544de9aa53d6976177c08b91aa3943ef4d9e92 /src/ratatui/widgets/tabs.rs
parentfeat: add github action to test the nix builds (#833) (diff)
downloadatuin-a515b06bcb556c1be2d0fc3095cd778d413fe40d.zip
Vendor ratatui temporarily (#835)
* Vendor ratatui temporarily Once https://github.com/tui-rs-revival/ratatui/pull/114 has been merged, we can undo this! But otherwise we can't publish to crates.io with a git dependency. * make tests pass * Shush. * these literally just fail in nix, nowhere else idk how to work with nix properly, and they're also not our tests
Diffstat (limited to '')
-rw-r--r--src/ratatui/widgets/tabs.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/ratatui/widgets/tabs.rs b/src/ratatui/widgets/tabs.rs
new file mode 100644
index 00000000..9b5f5469
--- /dev/null
+++ b/src/ratatui/widgets/tabs.rs
@@ -0,0 +1,129 @@
+use crate::ratatui::{
+ buffer::Buffer,
+ layout::Rect,
+ style::Style,
+ symbols,
+ text::{Span, Spans},
+ widgets::{Block, Widget},
+};
+
+/// A widget to display available tabs in a multiple panels context.
+///
+/// # Examples
+///
+/// ```
+/// # use ratatui::widgets::{Block, Borders, Tabs};
+/// # use ratatui::style::{Style, Color};
+/// # use ratatui::text::{Spans};
+/// # use ratatui::symbols::{DOT};
+/// let titles = ["Tab1", "Tab2", "Tab3", "Tab4"].iter().cloned().map(Spans::from).collect();
+/// Tabs::new(titles)
+/// .block(Block::default().title("Tabs").borders(Borders::ALL))
+/// .style(Style::default().fg(Color::White))
+/// .highlight_style(Style::default().fg(Color::Yellow))
+/// .divider(DOT);
+/// ```
+#[derive(Debug, Clone)]
+pub struct Tabs<'a> {
+ /// A block to wrap this widget in if necessary
+ block: Option<Block<'a>>,
+ /// One title for each tab
+ titles: Vec<Spans<'a>>,
+ /// The index of the selected tabs
+ selected: usize,
+ /// The style used to draw the text
+ style: Style,
+ /// Style to apply to the selected item
+ highlight_style: Style,
+ /// Tab divider
+ divider: Span<'a>,
+}
+
+impl<'a> Tabs<'a> {
+ pub fn new(titles: Vec<Spans<'a>>) -> Tabs<'a> {
+ Tabs {
+ block: None,
+ titles,
+ selected: 0,
+ style: Default::default(),
+ highlight_style: Default::default(),
+ divider: Span::raw(symbols::line::VERTICAL),
+ }
+ }
+
+ pub fn block(mut self, block: Block<'a>) -> Tabs<'a> {
+ self.block = Some(block);
+ self
+ }
+
+ pub fn select(mut self, selected: usize) -> Tabs<'a> {
+ self.selected = selected;
+ self
+ }
+
+ pub fn style(mut self, style: Style) -> Tabs<'a> {
+ self.style = style;
+ self
+ }
+
+ pub fn highlight_style(mut self, style: Style) -> Tabs<'a> {
+ self.highlight_style = style;
+ self
+ }
+
+ pub fn divider<T>(mut self, divider: T) -> Tabs<'a>
+ where
+ T: Into<Span<'a>>,
+ {
+ self.divider = divider.into();
+ self
+ }
+}
+
+impl<'a> Widget for Tabs<'a> {
+ fn render(mut self, area: Rect, buf: &mut Buffer) {
+ buf.set_style(area, self.style);
+ let tabs_area = match self.block.take() {
+ Some(b) => {
+ let inner_area = b.inner(area);
+ b.render(area, buf);
+ inner_area
+ }
+ None => area,
+ };
+
+ if tabs_area.height < 1 {
+ return;
+ }
+
+ let mut x = tabs_area.left();
+ 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;
+ }
+ let pos = buf.set_spans(x, tabs_area.top(), &title, remaining_width);
+ if i == self.selected {
+ buf.set_style(
+ Rect {
+ x,
+ y: tabs_area.top(),
+ width: pos.0.saturating_sub(x),
+ height: 1,
+ },
+ self.highlight_style,
+ );
+ }
+ x = pos.0.saturating_add(1);
+ 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;
+ }
+ }
+}