mod calendar;
mod canvas;
mod chart;
mod decode;
mod layout;
mod table;
pub use layout::do_split;
use crate::terminal::{TerminalState, WidgetCommand};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{
Bar, BarChart, BarGroup, Block, Gauge, LineGauge, List, ListItem, ListState, Paragraph,
Scrollbar, ScrollbarState, Sparkline, Tabs, Wrap,
};
use calendar::render_calendar;
use canvas::render_canvas;
use chart::render_chart;
use decode::{alignment_from_u8, borders_from_u8, scrollbar_orientation_from_u8};
use table::{render_table, render_table_ex};
pub fn render_all_commands(state: &mut TerminalState) {
let commands = std::mem::take(&mut state.commands);
let area_map = std::mem::take(&mut state.area_map);
state
.terminal
.draw(|frame| {
for cmd in &commands {
match cmd {
WidgetCommand::Block { area_id, title, borders, style } => {
if let Some(&area) = area_map.get(area_id) {
frame.render_widget(
Block::default()
.title(title.as_str())
.borders(borders_from_u8(*borders))
.style(*style),
area,
);
}
}
WidgetCommand::Paragraph { area_id, text, alignment, wrap, style } => {
if let Some(&area) = area_map.get(area_id) {
let mut para = Paragraph::new(text.as_str())
.alignment(alignment_from_u8(*alignment))
.style(*style);
if *wrap {
para = para.wrap(Wrap { trim: false });
}
frame.render_widget(para, area);
}
}
WidgetCommand::StyledParagraph { area_id, alignment, wrap, lines } => {
if let Some(&area) = area_map.get(area_id) {
let ratatui_lines: Vec<Line> = lines
.iter()
.map(|spans| {
Line::from(
spans
.iter()
.map(|s| Span::styled(s.text.clone(), s.style))
.collect::<Vec<_>>(),
)
})
.collect();
let mut para = Paragraph::new(ratatui_lines)
.alignment(alignment_from_u8(*alignment));
if *wrap {
para = para.wrap(Wrap { trim: false });
}
frame.render_widget(para, area);
}
}
WidgetCommand::List { area_id, items, selected, style } => {
if let Some(&area) = area_map.get(area_id) {
let list_items: Vec<ListItem> = items
.lines()
.map(ListItem::new)
.collect();
let list = List::new(list_items)
.style(*style)
.highlight_symbol("> ")
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
if *selected >= 0 {
let mut list_state = ListState::default()
.with_selected(Some(*selected as usize));
frame.render_stateful_widget(list, area, &mut list_state);
} else {
frame.render_widget(list, area);
}
}
}
WidgetCommand::Gauge { area_id, ratio, label, style } => {
if let Some(&area) = area_map.get(area_id) {
frame.render_widget(
Gauge::default()
.ratio(ratio.clamp(0.0, 1.0))
.label(label.as_str())
.style(*style),
area,
);
}
}
WidgetCommand::LineGauge { area_id, ratio, label, style } => {
if let Some(&area) = area_map.get(area_id) {
frame.render_widget(
LineGauge::default()
.ratio(ratio.clamp(0.0, 1.0))
.label(label.as_str())
.style(*style),
area,
);
}
}
WidgetCommand::Tabs { area_id, titles, selected, style } => {
if let Some(&area) = area_map.get(area_id) {
let tab_lines: Vec<Line> = titles
.lines()
.map(|t| Line::from(t.to_owned()))
.collect();
let highlight = Style::default()
.fg(Color::Black)
.bg(style.fg.unwrap_or(Color::Cyan))
.add_modifier(Modifier::BOLD);
frame.render_widget(
Tabs::new(tab_lines)
.select(*selected as usize)
.style(*style)
.highlight_style(highlight),
area,
);
}
}
WidgetCommand::Sparkline { area_id, data, style } => {
if let Some(&area) = area_map.get(area_id) {
frame.render_widget(
Sparkline::default().data(data).style(*style),
area,
);
}
}
WidgetCommand::BarChart { area_id, bars, bar_width, bar_gap, style } => {
if let Some(&area) = area_map.get(area_id) {
let bar_items: Vec<Bar> = bars
.iter()
.map(|(label, value)| {
Bar::default().label(label.as_str()).value(*value)
})
.collect();
let group = BarGroup::default().bars(&bar_items);
frame.render_widget(
BarChart::default()
.data(group)
.bar_width(*bar_width)
.bar_gap(*bar_gap)
.style(*style),
area,
);
}
}
WidgetCommand::Table { area_id, data, style } => {
if let Some(&area) = area_map.get(area_id) {
render_table(frame, area, data, *style);
}
}
WidgetCommand::TableEx {
area_id,
data,
col_constraints,
selected_row,
style,
} => {
if let Some(&area) = area_map.get(area_id) {
render_table_ex(
frame, area, data, col_constraints, *selected_row, *style,
);
}
}
WidgetCommand::Scrollbar {
area_id,
content_length,
position,
viewport_length,
orientation,
} => {
if let Some(&area) = area_map.get(area_id) {
let orient = scrollbar_orientation_from_u8(*orientation);
let mut scroll_state = ScrollbarState::default()
.content_length(*content_length as usize)
.position(*position as usize)
.viewport_content_length(*viewport_length as usize);
frame.render_stateful_widget(
Scrollbar::new(orient),
area,
&mut scroll_state,
);
}
}
WidgetCommand::Calendar { area_id, year, month, day } => {
if let Some(&area) = area_map.get(area_id) {
render_calendar(frame, area, *year, *month, *day);
}
}
WidgetCommand::Chart { area_id, x_axis, y_axis, datasets } => {
if let Some(&area) = area_map.get(area_id) {
render_chart(frame, area, x_axis, y_axis, datasets);
}
}
WidgetCommand::Canvas {
area_id,
x_min,
x_max,
y_min,
y_max,
marker,
shapes,
} => {
if let Some(&area) = area_map.get(area_id) {
render_canvas(
frame, area, *x_min, *x_max, *y_min, *y_max, *marker, shapes,
);
}
}
}
}
})
.expect("terminal draw failed");
state.area_map = area_map;
}