Skip to main content

scope/display/
vectorscope.rs

1use ratatui::{
2	style::Style,
3	text::Span,
4	widgets::{Axis, GraphType},
5};
6
7use crate::input::Matrix;
8
9use super::{DataSet, Dimension, DisplayMode, GraphConfig};
10
11#[derive(Default)]
12pub struct Vectorscope {}
13
14impl DisplayMode for Vectorscope {
15	fn mode_str(&self) -> &'static str {
16		"vector"
17	}
18
19	fn channel_name(&self, index: usize) -> String {
20		format!("{}", index)
21	}
22
23	fn header(&self, _: &GraphConfig) -> String {
24		"live".into()
25	}
26
27	fn axis(&'_ self, cfg: &GraphConfig, dimension: Dimension) -> Axis<'_> {
28		let (name, bounds) = match dimension {
29			Dimension::X => ("left -", [-cfg.scale, cfg.scale]),
30			Dimension::Y => ("| right", [-cfg.scale, cfg.scale]),
31		};
32		let mut a = Axis::default();
33		if cfg.show_ui {
34			// TODO don't make it necessary to check show_ui inside here
35			a = a.title(Span::styled(name, Style::default().fg(cfg.labels_color)));
36		}
37		a.style(Style::default().fg(cfg.axis_color)).bounds(bounds)
38	}
39
40	fn references(&self, cfg: &GraphConfig) -> Vec<DataSet> {
41		vec![
42			DataSet::new(
43				None,
44				vec![(-cfg.scale, 0.0), (cfg.scale, 0.0)],
45				cfg.marker_type,
46				GraphType::Line,
47				cfg.axis_color,
48			),
49			DataSet::new(
50				None,
51				vec![(0.0, -cfg.scale), (0.0, cfg.scale)],
52				cfg.marker_type,
53				GraphType::Line,
54				cfg.axis_color,
55			),
56		]
57	}
58
59	fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet> {
60		let mut out = Vec::new();
61
62		for (n, chunk) in data.chunks(2).enumerate() {
63			let mut tmp = vec![];
64			match chunk.len() {
65				2 => {
66					for i in 0..std::cmp::min(chunk[0].len(), chunk[1].len()) {
67						if i > cfg.samples as usize {
68							break;
69						}
70						tmp.push((chunk[0][i], chunk[1][i]));
71					}
72				}
73				1 => {
74					for i in 0..chunk[0].len() {
75						if i > cfg.samples as usize {
76							break;
77						}
78						tmp.push((chunk[0][i], i as f64));
79					}
80				}
81				_ => continue,
82			}
83			// split it in two for easier coloring
84			// TODO configure splitting in multiple parts?
85			let pivot = tmp.len() / 2;
86			out.push(DataSet::new(
87				Some(self.channel_name((n * 2) + 1)),
88				tmp[pivot..].to_vec(),
89				cfg.marker_type,
90				if cfg.scatter {
91					GraphType::Scatter
92				} else {
93					GraphType::Line
94				},
95				cfg.palette((n * 2) + 1),
96			));
97			out.push(DataSet::new(
98				Some(self.channel_name(n * 2)),
99				tmp[..pivot].to_vec(),
100				cfg.marker_type,
101				if cfg.scatter {
102					GraphType::Scatter
103				} else {
104					GraphType::Line
105				},
106				cfg.palette(n * 2),
107			));
108		}
109
110		out
111	}
112}