scope/display/
mod.rs

1pub mod oscilloscope;
2pub mod vectorscope;
3pub mod spectroscope;
4
5use crossterm::event::Event;
6use ratatui::{widgets::{Dataset, Axis, GraphType}, style::{Style, Color}, symbols::Marker};
7
8use crate::input::Matrix;
9
10pub enum Dimension {
11	X, Y
12}
13
14#[derive(Debug, Clone, Default)]
15pub struct GraphConfig {
16	pub pause: bool,
17	pub samples: u32,
18	pub sampling_rate: u32,
19	pub scale: f64,
20	pub width: u32,
21	pub scatter: bool,
22	pub references: bool,
23	pub show_ui: bool,
24	pub marker_type: Marker,
25	pub palette: Vec<Color>,
26	pub labels_color: Color,
27	pub axis_color: Color,
28}
29
30impl GraphConfig {
31	pub fn palette(&self, index: usize) -> Color {
32		*self.palette.get(index % self.palette.len()).unwrap_or(&Color::White)
33	}
34}
35
36#[allow(clippy::ptr_arg)] // TODO temporarily! it's a shitty solution
37pub trait DisplayMode {
38	// MUST define
39	fn axis(&self, cfg: &GraphConfig, dimension: Dimension) -> Axis; // TODO simplify this
40	fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet>;
41	fn mode_str(&self) -> &'static str;
42
43	// SHOULD override
44	fn channel_name(&self, index: usize) -> String { format!("{}", index) }
45	fn header(&self, _cfg: &GraphConfig) -> String { "".into() }
46	fn references(&self, _cfg: &GraphConfig) -> Vec<DataSet> { vec![] }
47	fn handle(&mut self, _event: Event) {}
48}
49
50pub struct DataSet {
51	name: Option<String>,
52	data: Vec<(f64, f64)>,
53	marker_type: Marker,
54	graph_type: GraphType,
55	color: Color,
56}
57
58impl<'a> From::<&'a DataSet> for Dataset<'a> {
59	fn from(ds: &'a DataSet) -> Dataset<'a> {
60		let mut out = Dataset::default(); // TODO creating a binding is kinda ugly, is it avoidable?
61		if let Some(name) = &ds.name {
62			out = out.name(name.clone());
63		}
64		out
65			.marker(ds.marker_type)
66			.graph_type(ds.graph_type)
67			.style(Style::default().fg(ds.color))
68			.data(&ds.data)
69		}
70}
71
72// TODO this is pretty ugly but I need datasets which own the data
73impl DataSet {
74	pub fn new(
75		name: Option<String>,
76		data: Vec<(f64, f64)>,
77		marker_type: Marker,
78		graph_type: GraphType,
79		color: Color
80	) -> Self {
81		DataSet { name, data, marker_type, graph_type, color }
82	}
83}
84
85
86pub(crate) fn update_value_f(val: &mut f64, base: f64, magnitude: f64, range: std::ops::Range<f64>) {
87	let delta = base * magnitude;
88	if *val + delta > range.end {
89		*val = range.end
90	} else if *val + delta < range.start {
91		*val = range.start
92	} else {
93		*val += delta;
94	}
95}
96
97pub(crate) fn update_value_i(val: &mut u32, inc: bool, base: u32, magnitude: f64, range: std::ops::Range<u32>) {
98	let delta = (base as f64 * magnitude) as u32;
99	if inc {
100		if range.end - delta < *val {
101			*val = range.end
102		} else {
103			*val += delta
104		}
105	} else if range.start + delta > *val {
106		*val = range.start
107	} else {
108		*val -= delta
109	}
110}