use bevy_app::{App, Update};
use bevy_ecs::change_detection::DetectChanges;
use bevy_ecs::hierarchy::ChildOf;
use bevy_ecs::prelude::{Commands, Component, Entity, IntoScheduleConfigs, Query, Res, With};
use bevy_ui::{Node, Val};
use plurimus::core::ratatui_core::text::{Line, Span};
use plurimus::core::{TerminalSize, UiWidget};
use plurimus::widgets::ratatui_widgets::block::{Block, Padding};
use plurimus::widgets::ratatui_widgets::borders::Borders;
use plurimus::widgets::ratatui_widgets::paragraph::Paragraph;
use crate::commands::tui::edit::Draft;
use crate::commands::tui::layout::{cells_of, clipped, placed, sized};
use crate::commands::tui::present;
use crate::commands::tui::session::Session;
use crate::commands::tui::theme::{Repainted, Theme};
pub fn plugin(app: &mut App) {
app.add_systems(Update, draw_status.in_set(Repainted));
}
const BADGE: &str = "●";
const STATUS_MARGIN: u16 = 1;
const NAME_GAP: u16 = 1;
pub const MIN_COLS: u16 = 1 + STATUS_MARGIN;
#[derive(Component, Debug)]
struct StatusCell;
pub fn spawn(commands: &mut Commands, tab_row: Entity) {
commands.spawn((
StatusCell,
Node {
height: Val::Percent(100.0),
..sized(0.0, 1.0)
},
UiWidget::new(drawn(Line::default())),
placed(),
ChildOf(tab_row),
));
}
fn drawn(line: Line<'static>) -> Paragraph<'static> {
let foot = Block::new()
.borders(Borders::BOTTOM)
.padding(Padding::top(1));
Paragraph::new(line).block(foot)
}
fn draw_status(
theme: Res<Theme>,
draft: Res<Draft>,
session: Res<Session>,
size: Res<TerminalSize>,
mut cells: Query<(&mut UiWidget, &mut Node), With<StatusCell>>,
) {
if !theme.is_changed() && !draft.is_changed() && !session.is_changed() && !size.is_changed() {
return;
}
let marked = if draft.is_dirty() {
theme.accented()
} else {
theme.dimmed()
};
let issues = draft.issues().len();
let badge = (!session.is_empty()).then(|| Span::styled(BADGE, marked));
let count = (issues > 0).then(|| {
let count = format!(" {}", present::issue_count(issues));
Span::styled(count, theme.exceeded())
});
let marks: Vec<Span<'static>> = [badge, count].into_iter().flatten().collect();
let taken: u16 = marks.iter().map(|span| cells_of(&span.content)).sum();
let room = size
.cols
.saturating_sub(super::TABS_COLS + NAME_GAP + taken + STATUS_MARGIN);
let name = clipped(session.file_name().into_owned(), room);
let mut spans = vec![Span::styled(format!("{name} "), theme.dimmed())];
spans.extend(marks);
let line = Line::from(spans);
let width = Val::Px(f32::from(line.width() as u16 + STATUS_MARGIN));
let Ok((mut widget, mut node)) = cells.single_mut() else {
return;
};
*widget = UiWidget::new(drawn(line));
if node.width != width {
node.width = width;
}
}