1pub mod oscilloscope;
2pub mod spectroscope;
3pub mod vectorscope;
4
5use crossterm::event::Event;
6use ratatui::{
7 style::{Color, Style},
8 symbols::Marker,
9 widgets::{Axis, Dataset, GraphType},
10};
11
12use crate::input::Matrix;
13
14pub enum Dimension {
15 X,
16 Y,
17}
18
19#[derive(Debug, Clone, Default)]
20pub struct GraphConfig {
21 pub pause: bool,
22 pub samples: u32,
23 pub sampling_rate: u32,
24 pub scale: f64,
25 pub width: u32,
26 pub scatter: bool,
27 pub references: bool,
28 pub show_ui: bool,
29 pub marker_type: Marker,
30 pub palette: Vec<Color>,
31 pub labels_color: Color,
32 pub axis_color: Color,
33}
34
35impl GraphConfig {
36 pub fn palette(&self, index: usize) -> Color {
37 *self
38 .palette
39 .get(index % self.palette.len())
40 .unwrap_or(&Color::White)
41 }
42}
43
44#[allow(clippy::ptr_arg)] pub trait DisplayMode {
46 fn axis(&'_ self, cfg: &GraphConfig, dimension: Dimension) -> Axis<'_>; fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet>;
49 fn mode_str(&self) -> &'static str;
50
51 fn channel_name(&self, index: usize) -> String {
53 format!("{}", index)
54 }
55 fn header(&self, _cfg: &GraphConfig) -> String {
56 "".into()
57 }
58 fn references(&self, _cfg: &GraphConfig) -> Vec<DataSet> {
59 vec![]
60 }
61 fn handle(&mut self, _event: Event) {}
62}
63
64pub struct DataSet {
65 name: Option<String>,
66 data: Vec<(f64, f64)>,
67 marker_type: Marker,
68 graph_type: GraphType,
69 color: Color,
70}
71
72impl<'a> From<&'a DataSet> for Dataset<'a> {
73 fn from(ds: &'a DataSet) -> Dataset<'a> {
74 let mut out = Dataset::default(); if let Some(name) = &ds.name {
76 out = out.name(name.clone());
77 }
78 out.marker(ds.marker_type)
79 .graph_type(ds.graph_type)
80 .style(Style::default().fg(ds.color))
81 .data(&ds.data)
82 }
83}
84
85impl DataSet {
87 pub fn new(
88 name: Option<String>,
89 data: Vec<(f64, f64)>,
90 marker_type: Marker,
91 graph_type: GraphType,
92 color: Color,
93 ) -> Self {
94 DataSet {
95 name,
96 data,
97 marker_type,
98 graph_type,
99 color,
100 }
101 }
102}
103
104pub(crate) fn update_value_f(
105 val: &mut f64,
106 base: f64,
107 magnitude: f64,
108 range: std::ops::Range<f64>,
109) {
110 let delta = base * magnitude;
111 if *val + delta > range.end {
112 *val = range.end
113 } else if *val + delta < range.start {
114 *val = range.start
115 } else {
116 *val += delta;
117 }
118}
119
120pub(crate) fn update_value_i(
121 val: &mut u32,
122 inc: bool,
123 base: u32,
124 magnitude: f64,
125 range: std::ops::Range<u32>,
126) {
127 let delta = (base as f64 * magnitude) as u32;
128 if inc {
129 if range.end - delta < *val {
130 *val = range.end
131 } else {
132 *val += delta
133 }
134 } else if range.start + delta > *val {
135 *val = range.start
136 } else {
137 *val -= delta
138 }
139}