use crate::core::buffer::Buffer;
use crate::core::color::Color;
use crate::core::rect::Rect;
#[derive(Debug, Clone)]
pub struct StatusBarSection {
pub text: String,
pub color: Color,
pub bold: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub enum StatusBarPosition {
Top,
Bottom,
}
#[derive(Debug, Clone)]
pub struct StatusBar {
pub left_sections: Vec<StatusBarSection>,
pub center_sections: Vec<StatusBarSection>,
pub right_sections: Vec<StatusBarSection>,
pub position: StatusBarPosition,
pub bg: Color,
pub border_color: Color,
pub height: u16,
}
impl StatusBar {
pub fn new() -> Self {
Self {
left_sections: Vec::new(),
center_sections: Vec::new(),
right_sections: Vec::new(),
position: StatusBarPosition::Bottom,
bg: Color::rgb(13, 17, 23),
border_color: Color::rgb(48, 54, 61),
height: 1,
}
}
pub fn with_position(mut self, pos: StatusBarPosition) -> Self {
self.position = pos;
self
}
pub fn with_bg(mut self, bg: Color) -> Self {
self.bg = bg;
self
}
pub fn set_left(&mut self, text: &str, color: Color) {
self.left_sections.clear();
self.left_sections.push(StatusBarSection {
text: text.to_string(),
color,
bold: false,
});
}
pub fn set_center(&mut self, text: &str, color: Color) {
self.center_sections.clear();
self.center_sections.push(StatusBarSection {
text: text.to_string(),
color,
bold: false,
});
}
pub fn set_right(&mut self, text: &str, color: Color) {
self.right_sections.clear();
self.right_sections.push(StatusBarSection {
text: text.to_string(),
color,
bold: false,
});
}
pub fn push_left(&mut self, text: &str, color: Color) {
self.left_sections.push(StatusBarSection {
text: text.to_string(),
color,
bold: false,
});
}
pub fn push_right(&mut self, text: &str, color: Color) {
self.right_sections.push(StatusBarSection {
text: text.to_string(),
color,
bold: false,
});
}
pub fn clear(&mut self) {
self.left_sections.clear();
self.center_sections.clear();
self.right_sections.clear();
}
pub fn render(&self, buffer: &mut Buffer, area: Rect) {
let bar_rect = match self.position {
StatusBarPosition::Bottom => Rect::new(
area.x,
area.bottom().saturating_sub(self.height),
area.width,
self.height,
),
StatusBarPosition::Top => Rect::new(area.x, area.y, area.width, self.height),
};
buffer.fill(bar_rect, ' ', Color::WHITE, Some(self.bg));
if bar_rect.height > 1 {
for x in bar_rect.x as usize..bar_rect.right() as usize {
buffer.set(
x,
bar_rect.y as usize,
crate::core::buffer::Cell {
ch: '─',
fg: self.border_color,
bg: Some(self.bg),
bold: false,
italic: false,
underlined: false,
},
);
}
}
let left_text: String = self
.left_sections
.iter()
.map(|s| s.text.as_str())
.collect::<Vec<_>>()
.join(" │ ");
let center_text: String = self
.center_sections
.iter()
.map(|s| s.text.as_str())
.collect::<Vec<_>>()
.join(" │ ");
let right_text: String = self
.right_sections
.iter()
.map(|s| s.text.as_str())
.collect::<Vec<_>>()
.join(" │ ");
let left_color = self
.left_sections
.first()
.map(|s| s.color)
.unwrap_or(Color::rgb(139, 148, 158));
let center_color = self
.center_sections
.first()
.map(|s| s.color)
.unwrap_or(Color::rgb(139, 148, 158));
let right_color = self
.right_sections
.first()
.map(|s| s.color)
.unwrap_or(Color::rgb(139, 148, 158));
let bar_y = if bar_rect.height > 1 {
bar_rect.y as usize + 1
} else {
bar_rect.y as usize
};
let left_display: String = left_text.chars().take((area.width / 3) as usize).collect();
buffer.set_str(
(bar_rect.x + 2) as usize,
bar_y,
&left_display,
left_color,
Some(self.bg),
);
if !center_text.is_empty() {
let center_display: String = center_text
.chars()
.take((area.width / 3) as usize)
.collect();
let cx = bar_rect.x as usize + (area.width as usize - center_display.len()) / 2;
buffer.set_str(cx, bar_y, ¢er_display, center_color, Some(self.bg));
}
if !right_text.is_empty() {
let right_display: String =
right_text.chars().take((area.width / 3) as usize).collect();
let rx = bar_rect.right() as usize - right_display.len() - 2;
buffer.set_str(rx, bar_y, &right_display, right_color, Some(self.bg));
}
}
}
impl Default for StatusBar {
fn default() -> Self {
Self::new()
}
}