use crate::_private::NonExhaustive;
use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::Style;
use ratatui::text::Span;
#[cfg(feature = "unstable-widget-ref")]
use ratatui::widgets::StatefulWidgetRef;
use ratatui::widgets::{StatefulWidget, Widget};
use std::fmt::Debug;
#[derive(Debug, Default, Clone)]
pub struct StatusLine {
style: Vec<Style>,
widths: Vec<Constraint>,
}
#[derive(Debug, Clone)]
pub struct StatusLineState {
pub area: Rect,
pub areas: Vec<Rect>,
pub status: Vec<String>,
pub non_exhaustive: NonExhaustive,
}
impl StatusLine {
pub fn new() -> Self {
Self {
style: Default::default(),
widths: Default::default(),
}
}
pub fn layout<It, Item>(mut self, widths: It) -> Self
where
It: IntoIterator<Item = Item>,
Item: Into<Constraint>,
{
self.widths = widths.into_iter().map(|v| v.into()).collect();
self
}
pub fn styles(mut self, style: impl IntoIterator<Item = impl Into<Style>>) -> Self {
self.style = style.into_iter().map(|v| v.into()).collect();
self
}
}
impl Default for StatusLineState {
fn default() -> Self {
Self {
area: Default::default(),
areas: Default::default(),
status: Default::default(),
non_exhaustive: NonExhaustive,
}
}
}
impl StatusLineState {
pub fn new() -> Self {
Self::default()
}
pub fn clear_status(&mut self) {
self.status.clear();
}
pub fn status<S: Into<String>>(&mut self, idx: usize, msg: S) {
while self.status.len() <= idx {
self.status.push("".to_string());
}
self.status[idx] = msg.into();
}
}
#[cfg(feature = "unstable-widget-ref")]
impl StatefulWidgetRef for StatusLine {
type State = StatusLineState;
fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
render_ref(self, area, buf, state);
}
}
impl StatefulWidget for StatusLine {
type State = StatusLineState;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
render_ref(&self, area, buf, state);
}
}
fn render_ref(widget: &StatusLine, area: Rect, buf: &mut Buffer, state: &mut StatusLineState) {
state.area = area;
let layout = Layout::horizontal(widget.widths.iter()).split(state.area);
for (i, rect) in layout.iter().enumerate() {
let style = widget.style.get(i).copied().unwrap_or_default();
let txt = state.status.get(i).map(|v| v.as_str()).unwrap_or("");
buf.set_style(*rect, style);
Span::from(txt).render(*rect, buf);
}
}