use super::*;
pub(super) type TabHits = (
Vec<(usize, Rect)>,
Vec<(usize, Rect)>,
Option<Rect>,
Option<Rect>,
);
pub(super) fn draw_tabbar(f: &mut RenderTarget, area: Rect, app: &mut App, t: &Theme) -> TabHits {
f.render_widget(Block::new().style(Style::new().bg(t.mantle)), area);
let left_hidden = !app.sidebars.left.visible && !app.sidebars.left.docks.is_empty();
let tog_w = if !left_hidden {
0
} else {
let r = Rect::new(area.x, area.y, 3, 1);
let hov = app
.hover
.is_some_and(|(c, rr)| c >= r.x && c < r.right() && rr == r.y);
let style = if hov {
Style::new().fg(t.crust).bg(t.accent).bold()
} else {
Style::new().fg(t.accent).bg(t.surface0).bold()
};
f.render_widget(Paragraph::new(Span::styled(" » ", style)), r);
app.sidebar_toggle_rect = Some(r);
3u16
};
let right_hidden = !app.sidebars.right.visible && !app.sidebars.right.docks.is_empty();
let right_tog_w = if !right_hidden {
0
} else {
let r = Rect::new(area.right().saturating_sub(3), area.y, 3, 1);
let hov = app
.hover
.is_some_and(|(c, rr)| c >= r.x && c < r.right() && rr == r.y);
let style = if hov {
Style::new().fg(t.crust).bg(t.accent).bold()
} else {
Style::new().fg(t.accent).bg(t.surface0).bold()
};
f.render_widget(Paragraph::new(Span::styled(" « ", style)), r);
app.right_sidebar_toggle_rect = Some(r);
3u16
};
let ws = app.ws();
let n = ws.tabs.len();
let active = ws.active_tab;
let mut tab_rects = Vec::new();
let mut close_rects = Vec::new();
let mut prev_rect = None;
let mut next_rect = None;
const CELL: u16 = 10; const GAP: u16 = 1;
const ARROW: u16 = 2;
let plus_w: u16 = 3;
let unit = CELL + GAP;
let left = area.x + 1 + tog_w;
let right = area.right().saturating_sub(right_tog_w);
let total = right.saturating_sub(left);
let fit_plain = ((total + GAP).saturating_sub(plus_w) / unit) as usize;
let need_scroll = n > fit_plain;
let avail = if need_scroll {
total.saturating_sub(plus_w + 2 * ARROW)
} else {
total.saturating_sub(plus_w)
};
let max_vis = (((avail + GAP) / unit).max(1) as usize).min(n.max(1));
let mut scroll = (active + 1).saturating_sub(max_vis);
scroll = scroll.min(n.saturating_sub(max_vis));
let mut x = left;
if need_scroll {
let style = if scroll > 0 {
Style::new().fg(t.accent).bold()
} else {
Style::new().fg(t.overlay0)
};
let r = Rect::new(x, area.y, ARROW, 1);
f.render_widget(Paragraph::new(Span::styled("‹ ", style)), r);
prev_rect = Some(r);
x += ARROW;
}
let end = (scroll + max_vis).min(n);
for i in scroll..end {
let is_git = ws.tabs.get(i).is_some_and(|tb| tb.is_git());
let is_orch = ws.tabs.get(i).is_some_and(|tb| tb.is_orch());
let name = ws.tabs.get(i).and_then(|tb| tb.name.as_deref());
let title = |w: usize| {
if let Some(nm) = name {
let label: String = if nm.chars().count() > w {
nm.chars().take(w.saturating_sub(1)).chain(['…']).collect()
} else {
nm.to_string()
};
format!("{label:^w$}")
} else if is_git {
format!("{:^w$}", "⎇ git", w = w)
} else if is_orch {
format!("{:^w$}", "◇ orch", w = w)
} else {
format!("{:^w$}", i + 1, w = w)
}
};
if i == active {
let label = title((CELL - 2) as usize);
let style = Style::new().fg(t.crust).bg(t.accent).bold();
f.render_widget(
Paragraph::new(Span::styled(label, style)),
Rect::new(x, area.y, CELL - 2, 1),
);
let close = Rect::new(x + CELL - 2, area.y, 2, 1);
f.render_widget(
Paragraph::new(Span::styled("✕ ", Style::new().fg(t.crust).bg(t.accent))),
close,
);
close_rects.push((i, close));
} else {
let label = title(CELL as usize);
f.render_widget(
Paragraph::new(Span::styled(
label,
Style::new().fg(t.subtext0).bg(t.mantle),
)),
Rect::new(x, area.y, CELL, 1),
);
}
tab_rects.push((i, Rect::new(x, area.y, CELL, 1)));
x += unit;
}
if need_scroll {
let style = if end < n {
Style::new().fg(t.accent).bold()
} else {
Style::new().fg(t.overlay0)
};
let r = Rect::new(x, area.y, ARROW, 1);
f.render_widget(Paragraph::new(Span::styled("› ", style)), r);
next_rect = Some(r);
x += ARROW;
}
if x + plus_w <= right {
let rect = Rect::new(x, area.y, plus_w, 1);
f.render_widget(
Paragraph::new(Span::styled(
" + ",
Style::new().fg(t.accent).bg(t.surface0).bold(),
)),
rect,
);
tab_rects.push((n, rect));
}
(tab_rects, close_rects, prev_rect, next_rect)
}