use crate::{style::*, InspectorModel, KeyCode, PAGE_SCROLL_STEP};
use nodo_runtime::proto::nodo as nodo_pb;
use ratatui::{
prelude::{Buffer, Constraint, Rect},
style::{Color, Modifier, Style},
text::Span,
widgets::{Cell, Row, StatefulWidget, Table, Widget},
};
use std::{cell::RefCell, sync::Arc, time::Duration};
pub struct SignalsController {
pub model: Arc<RefCell<InspectorModel>>,
}
impl SignalsController {
pub fn on_key(&mut self, key: KeyCode) {
match key {
KeyCode::Down => self.select_next(),
KeyCode::Up => self.select_previous(),
KeyCode::PageDown => self.on_page_down(),
KeyCode::PageUp => self.on_page_up(),
KeyCode::Enter => {}
_ => {}
}
}
fn select_next(&mut self) {
self.model.borrow_mut().signals_table_state.select_next();
}
fn select_previous(&mut self) {
self.model
.borrow_mut()
.signals_table_state
.select_previous();
}
fn on_page_down(&mut self) {
for _ in 0..PAGE_SCROLL_STEP {
self.select_next()
}
}
fn on_page_up(&mut self) {
for _ in 0..PAGE_SCROLL_STEP {
self.select_previous()
}
}
}
pub struct SignalsView {
pub model: Arc<RefCell<InspectorModel>>,
}
impl Widget for &SignalsView {
fn render(self, area: Rect, buf: &mut Buffer) {
let mut model = self.model.borrow_mut();
let entries: Vec<_> = model.tree.iter_signals().collect();
let combined_rows: Vec<_> = entries
.iter()
.map(
|(_, _, n, (signal_name, nodo_pb::NodeSignal { pubtime, value }))| {
Row::new(vec![
Cell::from(Span::styled(
n.info.node_name.clone(),
Style::default().fg(STYLE_COLOR_NODE_NAME),
)),
Cell::from(Span::styled(
signal_name.clone(),
Style::default().fg(STYLE_COLOR_DETAIL_NAME),
)),
Cell::from(match &value {
Some(cell) => Span::styled(
format!(
"{}",
match cell {
nodo_pb::node_signal::Value::Bool(_) => "bool",
nodo_pb::node_signal::Value::Int64(_) => "i64",
nodo_pb::node_signal::Value::Usize(_) => "usize",
nodo_pb::node_signal::Value::Float64(_) => "f64",
nodo_pb::node_signal::Value::String(_) => "String",
}
),
Style::default().fg(STYLE_COLOR_TYPENAME),
),
None => Span::styled(
String::from("N/A"),
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
),
}),
Cell::from(match &pubtime {
Some(cell) => Span::styled(
format!(
"{:0.03}",
Duration::new(cell.secs as u64, cell.nanos).as_secs_f32()
),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
),
None => Span::styled(
String::from("N/A"),
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
),
}),
Cell::from(match &value {
Some(cell) => Span::styled(
format!(
"{}",
match cell {
nodo_pb::node_signal::Value::Bool(v) => format!("{v:?}"),
nodo_pb::node_signal::Value::Int64(v) => format!("{v:?}"),
nodo_pb::node_signal::Value::Usize(v) => format!("{v:?}"),
nodo_pb::node_signal::Value::Float64(v) => format!("{v:?}"),
nodo_pb::node_signal::Value::String(v) => format!("{v:?}"),
}
),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
),
None => Span::styled(
String::from("N/A"),
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
),
}),
])
},
)
.collect();
let table = Table::new(
combined_rows,
&[
Constraint::Fill(1),
Constraint::Fill(1),
Constraint::Max(10),
Constraint::Max(10),
Constraint::Fill(3),
],
)
.header(
Row::new(vec![
"Node".to_string(),
"Signal".into(),
"Type".into(),
"Time".into(),
"Value".into(),
])
.style(
Style::default()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::REVERSED),
),
)
.style(Style::new().fg(Color::White))
.row_highlight_style(Style::new().add_modifier(Modifier::REVERSED));
StatefulWidget::render(table, area, buf, &mut model.signals_table_state);
}
}