Browse and listen to thousands of radio stations across the globe right from your terminal 🌎 📻 🎵✨
radio
rust
tokio
web-radio
command-line-tool
tui
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 from_args(_opts: &crate::cfg::SourceOptions) -> Self {
16 Vectorscope::default()
17 }
18
19 fn mode_str(&self) -> &'static str {
20 "vector"
21 }
22
23 fn channel_name(&self, index: usize) -> String {
24 format!("{}", index)
25 }
26
27 fn header(&self, _: &GraphConfig) -> String {
28 "live".into()
29 }
30
31 fn axis(&self, cfg: &GraphConfig, dimension: Dimension) -> Axis<'_> {
32 let (name, bounds) = match dimension {
33 Dimension::X => ("left -", [-cfg.scale, cfg.scale]),
34 Dimension::Y => ("| right", [-cfg.scale, cfg.scale]),
35 };
36 let mut a = Axis::default();
37 if cfg.show_ui {
38 // TODO don't make it necessary to check show_ui inside here
39 a = a.title(Span::styled(name, Style::default().fg(cfg.labels_color)));
40 }
41 a.style(Style::default().fg(cfg.axis_color)).bounds(bounds)
42 }
43
44 fn references(&self, cfg: &GraphConfig) -> Vec<DataSet> {
45 vec![
46 DataSet::new(
47 None,
48 vec![(-cfg.scale, 0.0), (cfg.scale, 0.0)],
49 cfg.marker_type,
50 GraphType::Line,
51 cfg.axis_color,
52 ),
53 DataSet::new(
54 None,
55 vec![(0.0, -cfg.scale), (0.0, cfg.scale)],
56 cfg.marker_type,
57 GraphType::Line,
58 cfg.axis_color,
59 ),
60 ]
61 }
62
63 fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet> {
64 let mut out = Vec::new();
65
66 for (n, chunk) in data.chunks(2).enumerate() {
67 let mut tmp = vec![];
68 match chunk.len() {
69 2 => {
70 for i in 0..std::cmp::min(chunk[0].len(), chunk[1].len()) {
71 if i > cfg.samples as usize {
72 break;
73 }
74 tmp.push((chunk[0][i], chunk[1][i]));
75 }
76 }
77 1 => {
78 for i in 0..chunk[0].len() {
79 if i > cfg.samples as usize {
80 break;
81 }
82 tmp.push((chunk[0][i], i as f64));
83 }
84 }
85 _ => continue,
86 }
87 // split it in two for easier coloring
88 // TODO configure splitting in multiple parts?
89 let pivot = tmp.len() / 2;
90 out.push(DataSet::new(
91 Some(self.channel_name((n * 2) + 1)),
92 tmp[pivot..].to_vec(),
93 cfg.marker_type,
94 if cfg.scatter {
95 GraphType::Scatter
96 } else {
97 GraphType::Line
98 },
99 cfg.palette((n * 2) + 1),
100 ));
101 out.push(DataSet::new(
102 Some(self.channel_name(n * 2)),
103 tmp[..pivot].to_vec(),
104 cfg.marker_type,
105 if cfg.scatter {
106 GraphType::Scatter
107 } else {
108 GraphType::Line
109 },
110 cfg.palette(n * 2),
111 ));
112 }
113
114 out
115 }
116}