Browse and listen to thousands of radio stations across the globe right from your terminal ๐ ๐ป ๐ตโจ
radio
rust
tokio
web-radio
command-line-tool
tui
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)]
20pub struct GraphConfig {
21 pub pause: bool,
22 pub samples: u32,
23 #[allow(dead_code)]
24 pub sampling_rate: u32,
25 pub scale: f64,
26 pub width: u32,
27 pub scatter: bool,
28 pub references: bool,
29 pub show_ui: bool,
30 pub marker_type: Marker,
31 pub palette: Vec<Color>,
32 pub labels_color: Color,
33 pub axis_color: Color,
34}
35
36impl GraphConfig {
37 pub fn palette(&self, index: usize) -> Color {
38 *self
39 .palette
40 .get(index % self.palette.len())
41 .unwrap_or(&Color::White)
42 }
43}
44
45#[allow(clippy::ptr_arg)]
46pub trait DisplayMode {
47 // MUST define
48 fn from_args(args: &crate::cfg::SourceOptions) -> Self
49 where
50 Self: Sized;
51 fn axis(&self, cfg: &GraphConfig, dimension: Dimension) -> Axis<'_>; // TODO simplify this
52 fn process(&mut self, cfg: &GraphConfig, data: &Matrix<f64>) -> Vec<DataSet>;
53 fn mode_str(&self) -> &'static str;
54
55 // SHOULD override
56 fn channel_name(&self, index: usize) -> String {
57 format!("{}", index)
58 }
59 fn header(&self, _cfg: &GraphConfig) -> String {
60 "".into()
61 }
62 fn references(&self, _cfg: &GraphConfig) -> Vec<DataSet> {
63 vec![]
64 }
65 fn handle(&mut self, _event: Event) {}
66}
67
68pub struct DataSet {
69 name: Option<String>,
70 data: Vec<(f64, f64)>,
71 marker_type: Marker,
72 graph_type: GraphType,
73 color: Color,
74}
75
76impl<'a> From<&'a DataSet> for Dataset<'a> {
77 fn from(ds: &'a DataSet) -> Dataset<'a> {
78 let mut out = Dataset::default(); // TODO creating a binding is kinda ugly, is it avoidable?
79 if let Some(name) = &ds.name {
80 out = out.name(name.clone());
81 }
82 out.marker(ds.marker_type)
83 .graph_type(ds.graph_type)
84 .style(Style::default().fg(ds.color))
85 .data(&ds.data)
86 }
87}
88
89// TODO this is pretty ugly but I need datasets which own the data
90impl DataSet {
91 pub fn new(
92 name: Option<String>,
93 data: Vec<(f64, f64)>,
94 marker_type: Marker,
95 graph_type: GraphType,
96 color: Color,
97 ) -> Self {
98 DataSet {
99 name,
100 data,
101 marker_type,
102 graph_type,
103 color,
104 }
105 }
106}