liftof_tui/
menu.rs

1//! Menus for the main application and 
2//! individual tabs
3
4use ratatui::widgets::Tabs;
5use ratatui::text::{Span, Line};
6use ratatui::style::{Color, Modifier, Style};
7use ratatui::widgets::{Block, Borders};
8use ratatui::Frame;
9use ratatui::layout::Rect;
10
11use crate::colors::{
12    ColorTheme
13};
14
15#[derive(Copy, Clone, Debug, PartialEq)]
16pub enum ActiveMenu {
17  MainMenu,
18  RBMenu,
19  Paddles,
20  Trigger,
21  Events,
22  Monitoring,
23  Heartbeats,
24  Telemetry,
25}
26
27#[derive(Copy, Clone, Debug, PartialEq)]
28pub enum MenuItem {
29  Home,
30  //Status,
31  //Alerts,
32  //Commands,
33  //Dashboard,
34  TofEvents,
35  TofSummary,
36  TofHits,
37  RBWaveform,
38  ReadoutBoards,
39  MasterTrigger,
40  TOFCpu, 
41  Telemetry,
42  Settings,
43  Quit,
44}
45
46
47impl From<MenuItem> for usize {
48  fn from(input: MenuItem) -> usize {
49    match input {
50      MenuItem::Home          => 0,
51      MenuItem::TofEvents     => 1,
52      MenuItem::ReadoutBoards => 2,
53      MenuItem::TofSummary    => 3,
54      MenuItem::RBWaveform    => 4,
55      MenuItem::TofHits       => 5,
56      //MenuItem::Alerts        => 2,
57      //MenuItem::Commands      => 3,
58      //MenuItem::Dashboard     => 4,
59      MenuItem::MasterTrigger => 6,
60      MenuItem::TOFCpu        => 7,
61      MenuItem::Telemetry     => 8,
62      MenuItem::Settings      => 9,
63      MenuItem::Quit          => 10,
64    }   
65  }
66}
67
68
69#[derive(Copy, Clone, Debug, PartialEq)]
70pub enum UIMenuItem {
71  Unknown,
72  // main menu
73  Home,
74  Back,
75  Events,
76  ReadoutBoards,
77  Paddles,
78  Trigger,
79  Monitoring,
80  Telemetry,
81  Commands,
82  Settings,
83  Alerts,
84  Quit,
85  // rb menu
86  Waveforms,
87  GlobalRates,
88  RBMoniData,
89  PAMoniData,
90  PBMoniData,
91  LTBMoniData,
92  SelectBoard,
93  // event menu
94  TofSummary,
95  TofEvents,
96  TofHits,
97  RBWaveform,
98  // moni menu
99  PreampBias,
100  PreampTemp,
101  LTBThresholds,
102  // paddle menu
103  Signal,
104  RecoVars,
105  // heartbeats
106  Heartbeats,
107  EventBuilderHB,
108  TriggerHB,
109  DataSenderHB,
110  // Selection
111  Yes,
112  No,
113  // TelemetryMenu
114  Stream,
115  MergedEvents, 
116  GPS,
117}
118
119impl UIMenuItem {
120
121  pub fn get_title(&self) -> String {
122    match self {
123      UIMenuItem::Unknown        => String::from("Unknown"       ),
124      UIMenuItem::Home           => String::from("Home"          ),
125      UIMenuItem::Back           => String::from("Back"          ),
126      UIMenuItem::Events         => String::from("Events"        ),
127      UIMenuItem::ReadoutBoards  => String::from("ReadoutBoards" ),
128      UIMenuItem::Trigger        => String::from("Trigger"       ),
129      UIMenuItem::Alerts         => String::from("Alerts"        ),
130      UIMenuItem::Monitoring     => String::from("Monitoring"    ),
131      UIMenuItem::Telemetry      => String::from("Telemetry"     ),
132      UIMenuItem::Settings       => String::from("Settings"      ),
133      UIMenuItem::Commands       => String::from("Commands"      ),
134      UIMenuItem::Quit           => String::from("Quit"          ),
135      UIMenuItem::Waveforms      => String::from("Waveforms"     ),
136      UIMenuItem::GlobalRates    => String::from("GlobalRates"   ),
137      UIMenuItem::RBMoniData     => String::from("RBMoniData"    ),
138      UIMenuItem::PAMoniData     => String::from("PAMoniData"    ),
139      UIMenuItem::PBMoniData     => String::from("PBMoniData"    ),
140      UIMenuItem::LTBMoniData    => String::from("LTBMoniData"   ),
141      UIMenuItem::SelectBoard    => String::from("SelectBoard"   ),
142      UIMenuItem::TofSummary     => String::from("TofSummary"    ),
143      UIMenuItem::TofEvents      => String::from("TofEvents"     ),
144      UIMenuItem::TofHits        => String::from("TofHits"       ),
145      UIMenuItem::RBWaveform     => String::from("RBWaveform"    ),
146      UIMenuItem::PreampBias     => String::from("Preamp Bias Voltages"   ),
147      UIMenuItem::PreampTemp     => String::from("Preamp Temps"),
148      UIMenuItem::LTBThresholds  => String::from("LTBThresholds"),
149      UIMenuItem::Paddles        => String::from("Paddles"),
150      UIMenuItem::Signal         => String::from("Wf & Charge"),
151      UIMenuItem::RecoVars       => String::from("Reco Vars"),
152      UIMenuItem::Heartbeats     => String::from("Heartbeats"),
153      UIMenuItem::EventBuilderHB => String::from("EventBuilderHB"),
154      UIMenuItem::TriggerHB      => String::from("TriggerHB"),
155      UIMenuItem::DataSenderHB   => String::from("DataSenderHB"),
156      UIMenuItem::Yes            => String::from("Yes"),
157      UIMenuItem::No             => String::from("No"),
158      UIMenuItem::Stream         => String::from("Stream"),
159      UIMenuItem::MergedEvents   => String::from("MergedEvents"),
160      UIMenuItem::GPS            => String::from("GPS"),
161    // _ => String::from("Unknown"),
162    } 
163  }
164}
165
166
167pub trait UIMenu<'a> {
168
169  fn get_max_idx() -> usize {
170    Self::get_items().len() - 1
171  }
172
173  fn get_items() -> Vec<UIMenuItem>;
174
175  fn get_active_menu_item(&self) -> UIMenuItem;
176
177  fn set_active_menu_item(&mut self, item : UIMenuItem);
178
179  fn get_active_idx(&self) -> usize;
180
181  fn set_active_idx(&mut self, idx : usize);
182 
183  fn get_theme(&self) -> ColorTheme;
184
185  fn get_titles(theme : ColorTheme) -> Vec<Line<'a>> {
186    let mut titles = Vec::<Line>::new();
187    for item in Self::get_items().clone() {
188      let ti = item.get_title().clone();
189      let line =  Line::from(vec![Span::styled(ti, theme.style()),]);
190      titles.push(line);
191    }
192    titles
193  }
194
195  fn next(&mut self) {
196    if self.get_active_idx() + 1 > Self::get_max_idx() {
197      self.set_active_menu_item(Self::get_items()[0]);
198      self.set_active_idx(0);
199    } else {
200      self.set_active_menu_item(Self::get_items()[self.get_active_idx() + 1]);
201      self.set_active_idx(self.get_active_idx() + 1);
202    }
203  }
204
205  fn prev(&mut self) {
206    if self.get_active_idx() == 0 {
207      self.set_active_menu_item(Self::get_items()[Self::get_max_idx()]);
208      self.set_active_idx(Self::get_max_idx());
209    } else {
210      self.set_active_menu_item(Self::get_items()[self.get_active_idx() -1]);
211      self.set_active_idx(self.get_active_idx() - 1);
212    }
213  }
214  
215  fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
216    let theme = self.get_theme();
217    let tabs = Tabs::new(Self::get_titles(theme))
218      .select(self.get_active_idx())
219      .block(Block::default().title("Menu").borders(Borders::ALL))
220      .style(self.get_theme().style())
221      .highlight_style(self.get_theme().highlight())
222      .divider(Span::raw("|"));
223    frame.render_widget(tabs, *main_window);
224  }
225}
226
227
228#[derive(Debug, Clone)]
229pub struct MainMenu<'a> {
230  pub theme             : ColorTheme,
231  pub active_index      : usize,
232  pub titles            : Vec<Line<'a>>,
233  pub active_menu_item  : MenuItem,
234  pub active_menu_item2 : UIMenuItem,
235}
236
237impl UIMenu<'_> for MainMenu<'_> {
238  fn get_items() -> Vec<UIMenuItem> {
239    let items = vec![UIMenuItem::Home,
240                     UIMenuItem::Events,
241                     UIMenuItem::ReadoutBoards,
242                     UIMenuItem::Paddles,
243                     UIMenuItem::Trigger,
244                     UIMenuItem::Alerts,
245                     UIMenuItem::Heartbeats,
246                     UIMenuItem::Monitoring,
247                     UIMenuItem::Telemetry,
248                     UIMenuItem::Commands,
249                     UIMenuItem::Settings,
250                     UIMenuItem::Quit];
251    items
252  }
253
254  fn get_theme(&self) -> ColorTheme {
255    self.theme.clone()
256  }
257
258  fn set_active_menu_item(&mut self, item : UIMenuItem) {
259    self.active_menu_item2 = item;
260  }
261
262  fn set_active_idx(&mut self, idx : usize) {
263    self.active_index = idx;
264  }
265
266  fn get_active_idx(&self) -> usize {
267    self.active_index
268  }
269  
270  fn get_active_menu_item(&self) -> UIMenuItem {
271    self.active_menu_item2
272  }
273}
274
275impl MainMenu<'_> {
276  pub fn new(theme : ColorTheme) -> Self {
277    let titles = Self::get_titles(theme);
278    let theme_cl = theme.clone();
279    Self {
280      theme : theme_cl,
281      active_index : 0,
282      titles,
283      active_menu_item : MenuItem::Home,
284      active_menu_item2 : UIMenuItem::Home,
285    }
286  }
287}
288
289//======================================
290
291#[derive(Debug, Clone)]
292pub struct RBMenu2<'a>  {
293  pub theme             : ColorTheme,
294  pub active_menu_item  : RBMenuItem,
295  pub active_menu_item2 : UIMenuItem,
296  pub active_index      : usize, 
297  pub titles            : Vec<Line<'a>>,
298}
299
300impl UIMenu<'_> for RBMenu2<'_> {
301  
302  fn get_items() -> Vec<UIMenuItem> {
303    let items = vec![UIMenuItem::Back,
304                     UIMenuItem::Waveforms,
305                     UIMenuItem::GlobalRates,
306                     UIMenuItem::RBMoniData,
307                     UIMenuItem::PBMoniData,
308                     UIMenuItem::PAMoniData,
309                     UIMenuItem::LTBMoniData];
310                     //UIMenuItem::SelectBoard];
311    items
312  }
313
314  fn get_theme(&self) -> ColorTheme {
315    self.theme
316  }
317
318  fn set_active_idx(&mut self, idx : usize) {
319    self.active_index = idx;
320  }
321
322  fn get_active_idx(&self) -> usize {
323    self.active_index
324  }
325  
326  fn set_active_menu_item(&mut self, item : UIMenuItem) {
327    self.active_menu_item2 = item;
328  }
329  
330  fn get_active_menu_item(&self) -> UIMenuItem {
331    match self.active_index {
332      0 => UIMenuItem::Back,
333      1 => UIMenuItem::Waveforms,
334      2 => UIMenuItem::GlobalRates,
335      3 => UIMenuItem::RBMoniData,
336      4 => UIMenuItem::PAMoniData,
337      5 => UIMenuItem::PBMoniData,
338      6 => UIMenuItem::LTBMoniData,
339      7 => UIMenuItem::SelectBoard,
340      8 => UIMenuItem::Quit,
341      _ => UIMenuItem::Unknown
342    }
343  }
344}
345
346impl  RBMenu2<'_> {
347
348  pub fn new(theme : ColorTheme) -> Self {
349    let title_str  =  vec!["Back",
350                           "Waveforms",
351                           "GlobalRates",
352                           "RBMoniData", 
353                           "PBMoniData", "PAMoniData",
354                           "LTBMoniData",
355                           "SelectBoards [LTB & RB]"];
356
357    let titles : Vec<Line> = title_str
358                .iter()
359                .map(|t| {
360                   Line::from(vec![
361                     Span::styled(*t, theme.style()),
362                   ])
363                })
364                .collect();
365 
366    Self {
367      theme,
368      active_index : 0,
369      titles,
370      active_menu_item : RBMenuItem::Home,
371      active_menu_item2 : UIMenuItem::Home,
372    }
373  }
374}
375
376#[derive(Debug, Clone)]
377pub struct TriggerMenu<'a>  {
378  pub theme            : ColorTheme,
379  pub active_menu_item : UIMenuItem,
380  pub active_index     : usize, 
381  pub titles           : Vec<Line<'a>>,
382}
383
384impl UIMenu<'_> for TriggerMenu<'_> {
385  
386  fn get_items() -> Vec<UIMenuItem> {
387    let items = vec![UIMenuItem::Back,
388                     UIMenuItem::Quit];
389    items
390  }
391
392  fn get_theme(&self) -> ColorTheme {
393    self.theme
394  }
395
396  fn set_active_idx(&mut self, idx : usize) {
397    self.active_index = idx;
398  }
399
400  fn get_active_idx(&self) -> usize {
401    self.active_index
402  }
403  
404  fn set_active_menu_item(&mut self, item : UIMenuItem) {
405    self.active_menu_item = item;
406  }
407  
408  fn get_active_menu_item(&self) -> UIMenuItem {
409    self.active_menu_item
410  }
411}
412
413impl  TriggerMenu<'_> {
414
415  pub fn new(theme : ColorTheme) -> Self {
416    let theme_c = theme.clone();
417    let titles  = Self::get_titles(theme_c);
418    Self {
419      theme,
420      active_index : 0,
421      titles,
422      active_menu_item : UIMenuItem::Back,
423    }
424  }
425}
426
427//============================================
428
429#[derive(Debug, Clone)]
430pub struct EventMenu<'a>  {
431  pub theme            : ColorTheme,
432  pub active_menu_item : UIMenuItem,
433  pub active_index     : usize, 
434  pub titles           : Vec<Line<'a>>,
435}
436
437impl UIMenu<'_> for EventMenu<'_> {
438  
439  fn get_items() -> Vec<UIMenuItem> {
440    let items = vec![UIMenuItem::Back,
441                     UIMenuItem::TofSummary];
442    items
443  }
444
445  fn get_theme(&self) -> ColorTheme {
446    self.theme
447  }
448
449  fn set_active_idx(&mut self, idx : usize) {
450    self.active_index = idx;
451  }
452
453  fn get_active_idx(&self) -> usize {
454    self.active_index
455  }
456  
457  fn set_active_menu_item(&mut self, item : UIMenuItem) {
458    self.active_menu_item = item;
459  }
460  
461  fn get_active_menu_item(&self) -> UIMenuItem {
462    self.active_menu_item
463  }
464}
465
466impl  EventMenu<'_> {
467
468  pub fn new(theme : ColorTheme) -> Self {
469    let theme_c = theme.clone();
470    let titles  = Self::get_titles(theme_c);
471    Self {
472      theme,
473      active_index : 0,
474      titles,
475      active_menu_item : UIMenuItem::Back,
476    }
477  }
478}
479
480//============================================
481
482#[derive(Debug, Clone)]
483pub struct PaddleMenu<'a>  {
484  pub theme            : ColorTheme,
485  pub active_menu_item : UIMenuItem,
486  pub active_index     : usize, 
487  pub titles           : Vec<Line<'a>>,
488}
489
490impl UIMenu<'_> for PaddleMenu<'_> {
491  
492  fn get_items() -> Vec<UIMenuItem> {
493    let items = vec![UIMenuItem::Back,
494                     UIMenuItem::Signal,
495                     UIMenuItem::RecoVars];
496    items
497  }
498
499  fn get_theme(&self) -> ColorTheme {
500    self.theme
501  }
502
503  fn set_active_idx(&mut self, idx : usize) {
504    self.active_index = idx;
505  }
506
507  fn get_active_idx(&self) -> usize {
508    self.active_index
509  }
510  
511  fn set_active_menu_item(&mut self, item : UIMenuItem) {
512    self.active_menu_item = item;
513  }
514  
515  fn get_active_menu_item(&self) -> UIMenuItem {
516    self.active_menu_item
517  }
518}
519
520impl PaddleMenu<'_> {
521
522  pub fn new(theme : ColorTheme) -> Self {
523    let theme_c = theme.clone();
524    let titles  = Self::get_titles(theme_c);
525    Self {
526      theme,
527      active_index : 0,
528      titles,
529      active_menu_item : UIMenuItem::Back,
530    }
531  }
532}
533
534//============================================
535
536#[derive(Debug, Clone)]
537pub struct HBMenu<'a>  {
538  pub theme            : ColorTheme,
539  pub active_menu_item : UIMenuItem,
540  pub active_index     : usize, 
541  pub titles           : Vec<Line<'a>>,
542}
543
544impl UIMenu<'_> for HBMenu<'_> {
545  
546  fn get_items() -> Vec<UIMenuItem> {
547    let items = vec![UIMenuItem::Back,
548                     UIMenuItem::EventBuilderHB,
549                     UIMenuItem::TriggerHB,
550                     UIMenuItem::DataSenderHB];
551    items
552  }
553
554  fn get_theme(&self) -> ColorTheme {
555    self.theme
556  }
557
558  fn set_active_idx(&mut self, idx : usize) {
559    self.active_index = idx;
560  }
561
562  fn get_active_idx(&self) -> usize {
563    self.active_index
564  }
565  
566  fn set_active_menu_item(&mut self, item : UIMenuItem) {
567    self.active_menu_item = item;
568  }
569  
570  fn get_active_menu_item(&self) -> UIMenuItem {
571    self.active_menu_item
572  }
573}
574
575impl HBMenu<'_> {
576
577  pub fn new(theme : ColorTheme) -> Self {
578    let theme_c = theme.clone();
579    let titles  = Self::get_titles(theme_c);
580    Self {
581      theme,
582      active_index : 0,
583      titles,
584      active_menu_item : UIMenuItem::Back,
585    }
586  }
587}
588
589//============================================
590
591#[derive(Debug, Clone)]
592pub struct TelemetryMenu<'a>  {
593  pub theme            : ColorTheme,
594  pub active_menu_item : UIMenuItem,
595  pub active_index     : usize, 
596  pub titles           : Vec<Line<'a>>,
597}
598
599impl UIMenu<'_> for TelemetryMenu<'_> {
600  
601  fn get_items() -> Vec<UIMenuItem> {
602    let items = vec![UIMenuItem::Back,
603                     UIMenuItem::MergedEvents];
604    items
605  }
606
607  fn get_theme(&self) -> ColorTheme {
608    self.theme
609  }
610
611  fn set_active_idx(&mut self, idx : usize) {
612    self.active_index = idx;
613  }
614
615  fn get_active_idx(&self) -> usize {
616    self.active_index
617  }
618  
619  fn set_active_menu_item(&mut self, item : UIMenuItem) {
620    self.active_menu_item = item;
621  }
622  
623  fn get_active_menu_item(&self) -> UIMenuItem {
624    self.active_menu_item
625  }
626}
627
628impl TelemetryMenu<'_> {
629
630  pub fn new(theme : ColorTheme) -> Self {
631    let theme_c = theme.clone();
632    let titles  = Self::get_titles(theme_c);
633    Self {
634      theme,
635      active_index : 0,
636      titles,
637      active_menu_item : UIMenuItem::Back,
638    }
639  }
640}
641
642//============================================
643
644#[derive(Debug, Clone)]
645pub struct MoniMenu<'a>  {
646  pub theme            : ColorTheme,
647  pub active_menu_item : UIMenuItem,
648  pub active_index     : usize, 
649  pub titles           : Vec<Line<'a>>,
650}
651
652impl UIMenu<'_> for MoniMenu<'_> {
653  
654  fn get_items() -> Vec<UIMenuItem> {
655    let items = vec![UIMenuItem::Back,
656                     UIMenuItem::PreampBias,
657                     UIMenuItem::PreampTemp,
658                     UIMenuItem::LTBThresholds,
659                     UIMenuItem::Quit];
660    items
661  }
662
663  fn get_theme(&self) -> ColorTheme {
664    self.theme
665  }
666
667  fn set_active_idx(&mut self, idx : usize) {
668    self.active_index = idx;
669  }
670
671  fn get_active_idx(&self) -> usize {
672    self.active_index
673  }
674  
675  fn set_active_menu_item(&mut self, item : UIMenuItem) {
676    self.active_menu_item = item;
677  }
678  
679  fn get_active_menu_item(&self) -> UIMenuItem {
680    self.active_menu_item
681  }
682}
683
684impl  MoniMenu<'_> {
685
686  pub fn new(theme : ColorTheme) -> Self {
687    let theme_c = theme.clone();
688    let titles  = Self::get_titles(theme_c);
689    Self {
690      theme,
691      active_index : 0,
692      titles,
693      active_menu_item : UIMenuItem::Back,
694    }
695  }
696}
697
698//============================================
699
700///////////////////////////////////////////
701
702#[derive(Debug, Copy, Clone)]
703pub enum MTMenuItem {
704  Home,
705  Quit
706}
707
708impl From<MTMenuItem> for usize {
709  fn from(input: MTMenuItem) -> usize {
710    match input {
711      MTMenuItem::Home          => 0,
712      MTMenuItem::Quit          => 1,
713    }   
714  }
715}
716
717
718///////////////////////////////////////////
719
720/// Telemetry menu
721#[derive(Debug, Copy, Clone)]
722pub enum TEMenuItem {
723  Home,
724  Quit
725}
726
727impl From<TEMenuItem> for usize {
728  fn from(input: TEMenuItem) -> usize {
729    match input {
730      TEMenuItem::Home          => 0,
731      TEMenuItem::Quit          => 1,
732    }   
733  }
734}
735
736
737///////////////////////////////////////////
738
739#[derive(Debug, Copy, Clone, PartialEq)]
740pub enum RBMenuItem {
741  Home,
742  Info,
743  Waveforms,
744  RBMoniData,
745  PAMoniData,
746  PBMoniData,
747  LTBMoniData,
748  SelectRB,
749  Quit,
750}
751
752impl From<RBMenuItem> for usize {
753  fn from(input: RBMenuItem) -> usize {
754    match input {
755      RBMenuItem::Home          => 0,
756      RBMenuItem::Info          => 1,
757      RBMenuItem::Waveforms     => 2,
758      RBMenuItem::RBMoniData    => 3,
759      RBMenuItem::PAMoniData    => 4,
760      RBMenuItem::PBMoniData    => 5,
761      RBMenuItem::LTBMoniData   => 6,
762      RBMenuItem::SelectRB      => 7,
763      RBMenuItem::Quit          => 8,
764    }   
765  }
766}
767
768#[derive(Debug, Copy, Clone, PartialEq)]
769pub enum PAMoniMenuItem {
770  Back,
771  Temperatures,
772  Biases,
773  Quit,
774}
775
776impl From<PAMoniMenuItem> for usize {
777  fn from(input: PAMoniMenuItem) -> usize {
778    match input {
779      PAMoniMenuItem::Back          => 0,
780      PAMoniMenuItem::Temperatures  => 1,
781      PAMoniMenuItem::Biases        => 2,
782      PAMoniMenuItem::Quit          => 3
783    }
784  }
785}
786
787#[derive(Debug, Clone)]
788pub struct PAMoniMenu {
789  pub theme : ColorTheme,
790  pub active_menu_item : PAMoniMenuItem,
791}
792
793impl PAMoniMenu {
794  pub fn new(theme : ColorTheme) -> Self {
795    Self {
796      theme,
797      active_menu_item : PAMoniMenuItem::Temperatures,
798    }
799  }
800  
801  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
802    let menu_titles = vec!["Back", "Temperatures", "Biases", "Quit"];
803    let menu : Vec<Line> = menu_titles
804               .iter()
805               .map(|t| {
806                 if t == &"Biases" {
807                   let (a, b) = t.split_at(2);
808                   let (highlight, c) = b.split_at(1);
809                   Line::from(vec![
810                     Span::styled(a, self.theme.style()),
811                     Span::styled(
812                         highlight,
813                         Style::default()
814                             .fg(self.theme.hc)
815                             .add_modifier(Modifier::UNDERLINED),
816                     ),
817                     Span::styled(c, self.theme.style()),
818                   ])
819                 } else {
820                   let (first, rest) = t.split_at(1);
821                   Line::from(vec![
822                     Span::styled(
823                         first,
824                         Style::default()
825                             .fg(self.theme.hc)
826                             .add_modifier(Modifier::UNDERLINED),
827                     ),
828                     Span::styled(rest, self.theme.style()),
829                   ])
830                 }
831               })
832               .collect();
833
834    let tabs = Tabs::new(menu)
835        .select(usize::from(self.active_menu_item))
836        .block(Block::default().title("Menu").borders(Borders::ALL))
837        .style(self.theme.style())
838        .highlight_style(self.theme.highlight())
839        .divider(Span::raw("|"));
840    frame.render_widget(tabs, *main_window);
841  }
842}
843
844#[derive(Debug, Clone)]
845pub struct RBMenu  {
846  pub theme : ColorTheme,
847  pub active_menu_item : RBMenuItem,
848}
849
850impl  RBMenu {
851
852  pub fn new(theme : ColorTheme) -> RBMenu {
853    RBMenu {
854      theme,
855      active_menu_item : RBMenuItem::Home,
856    }
857  }
858
859  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
860    let menu_titles = vec!["Home", "Info", "Waveforms", "RBMoniData", "PAMoniData", "PBMoniData", "LTBMoniData", "SelectBoards [LTB & RB]", "Quit" ];
861    let menu : Vec<Line> = menu_titles
862               .iter()
863               .map(|t| {
864                 if t == &"PBMoniData" || t == &"Hits" {
865                   let (second, rest) = t.split_at(2);
866                   Line::from(vec![
867                     Span::styled(
868                       second,
869                       Style::default()
870                         .fg(self.theme.hc)
871                         .add_modifier(Modifier::UNDERLINED),
872                     ),
873                     Span::styled(rest, self.theme.style()),
874                   ])
875                 } else {
876                   let (first, rest) = t.split_at(1);
877                   Line::from(vec![
878                     Span::styled(
879                         first,
880                         Style::default()
881                             .fg(self.theme.hc)
882                             .add_modifier(Modifier::UNDERLINED),
883                     ),
884                     Span::styled(rest, self.theme.style()),
885                   ])
886                 }
887               })
888               .collect();
889
890    let tabs = Tabs::new(menu)
891        .select(usize::from(self.active_menu_item))
892        .block(Block::default().title("Menu").borders(Borders::ALL))
893        .style(self.theme.style())
894        .highlight_style(self.theme.highlight())
895        .divider(Span::raw("|"));
896    frame.render_widget(tabs, *main_window);
897  }
898}
899
900///////////////////////////////////////////
901
902#[derive(Debug, Copy, Clone)]
903pub enum SettingsMenuItem {
904  Home,
905  Quit
906}
907
908impl From<SettingsMenuItem> for usize {
909  fn from(input: SettingsMenuItem) -> usize {
910    match input {
911      SettingsMenuItem::Home          => 0,
912      SettingsMenuItem::Quit          => 1,
913    }   
914  }
915}
916
917#[derive(Debug, Clone)]
918pub struct SettingsMenu {
919  pub theme : ColorTheme,
920  pub active_menu_item : SettingsMenuItem,
921}
922
923impl  SettingsMenu {
924
925  pub fn new(theme : ColorTheme) -> SettingsMenu {
926    SettingsMenu {
927      theme,
928      active_menu_item : SettingsMenuItem::Home,
929    }
930  }
931
932  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
933    let menu_titles : Vec<&str> = vec!["Home", "Quit" ];
934    let menu : Vec<Line> = menu_titles
935               .iter()
936               .map(|t| {
937                 let (first, rest) = t.split_at(1);
938                 Line::from(vec![
939                   Span::styled(
940                       first,
941                       Style::default()
942                           .fg(Color::Yellow)
943                           .add_modifier(Modifier::UNDERLINED),
944                   ),
945                   Span::styled(rest, self.theme.style()),
946                 ])
947               })
948               .collect();
949
950    let tabs = Tabs::new(menu)
951        .select(usize::from(self.active_menu_item))
952        .block(Block::default().title("Menu").borders(Borders::ALL))
953        .style(self.theme.style())
954        .highlight_style(self.theme.highlight())
955        .divider(Span::raw("|"));
956    frame.render_widget(tabs, *main_window);
957  }
958}
959
960///////////////////////////////////////////
961
962#[derive(Debug, Copy, Clone)]
963pub enum TSMenuItem {
964  Home,
965  Quit
966}
967
968impl From<TSMenuItem> for usize {
969  fn from(input: TSMenuItem) -> usize {
970    match input {
971      TSMenuItem::Home          => 0,
972      TSMenuItem::Quit          => 1,
973    }   
974  }
975}
976
977#[derive(Debug, Clone)]
978pub struct TSMenu {
979  pub theme : ColorTheme,
980  pub active_menu_item : TSMenuItem,
981}
982
983impl TSMenu {
984
985  pub fn new(theme : ColorTheme) -> TSMenu  {
986    TSMenu {
987      theme,
988      active_menu_item : TSMenuItem::Home,
989    }
990  }
991
992  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
993    let menu_titles : Vec<&str> = vec!["Home", "Quit" ];
994    let menu : Vec<Line> = menu_titles
995               .iter()
996               .map(|t| {
997                 let (first, rest) = t.split_at(1);
998                 Line::from(vec![
999                   Span::styled(
1000                       first,
1001                       Style::default()
1002                           .fg(self.theme.hc)
1003                           .add_modifier(Modifier::UNDERLINED),
1004                   ),
1005                   Span::styled(rest, self.theme.style()),
1006                 ])
1007               })
1008               .collect();
1009
1010    let tabs = Tabs::new(menu)
1011        .select(usize::from(self.active_menu_item))
1012        .block(Block::default().title("Menu").borders(Borders::ALL))
1013        .style(self.theme.style())
1014        .highlight_style(self.theme.highlight())
1015        .divider(Span::raw("|"));
1016    frame.render_widget(tabs, *main_window);
1017  }
1018}
1019
1020///////////////////////////////////////////
1021
1022#[derive(Debug, Copy, Clone)]
1023pub enum RWMenuItem {
1024  Home,
1025  Quit
1026}
1027
1028impl From<RWMenuItem> for usize {
1029  fn from(input: RWMenuItem) -> usize {
1030    match input {
1031      RWMenuItem::Home          => 0,
1032      RWMenuItem::Quit          => 1,
1033    }   
1034  }
1035}
1036
1037#[derive(Debug, Clone)]
1038pub struct RWMenu {
1039  pub theme : ColorTheme,
1040  pub active_menu_item : RWMenuItem,
1041}
1042
1043impl RWMenu {
1044
1045  pub fn new(theme : ColorTheme) -> RWMenu  {
1046    RWMenu {
1047      theme,
1048      active_menu_item : RWMenuItem::Home,
1049    }
1050  }
1051
1052  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
1053    let menu_titles : Vec<&str> = vec!["Home", "Quit" ];
1054    let menu : Vec<Line> = menu_titles
1055               .iter()
1056               .map(|t| {
1057                 let (first, rest) = t.split_at(1);
1058                 Line::from(vec![
1059                   Span::styled(
1060                       first,
1061                       Style::default()
1062                           .fg(self.theme.hc)
1063                           .add_modifier(Modifier::UNDERLINED),
1064                   ),
1065                   Span::styled(rest, self.theme.style()),
1066                 ])
1067               })
1068               .collect();
1069
1070    let tabs = Tabs::new(menu)
1071        .select(usize::from(self.active_menu_item))
1072        .block(Block::default().title("Menu").borders(Borders::ALL))
1073        .style(self.theme.style())
1074        .highlight_style(self.theme.highlight())
1075        .divider(Span::raw("|"));
1076    frame.render_widget(tabs, *main_window);
1077  }
1078}
1079
1080///////////////////////////////////////////
1081
1082#[derive(Debug, Copy, Clone)]
1083pub enum THMenuItem {
1084  Home,
1085  Hits,
1086  Pulses,
1087  Paddles,
1088  SelectPaddle,
1089  Quit
1090}
1091
1092impl From<THMenuItem> for usize {
1093  fn from(input: THMenuItem) -> usize {
1094    match input {
1095      THMenuItem::Home          => 0,
1096      THMenuItem::Hits          => 1,
1097      THMenuItem::Pulses        => 2,
1098      THMenuItem::Paddles       => 3,
1099      THMenuItem::SelectPaddle  => 4,
1100      THMenuItem::Quit          => 5,
1101    }   
1102  }
1103}
1104
1105#[derive(Debug, Clone)]
1106pub struct THMenu {
1107  pub theme : ColorTheme,
1108  pub active_menu_item : THMenuItem,
1109}
1110
1111impl THMenu {
1112
1113  pub fn new(theme : ColorTheme) -> THMenu  {
1114    THMenu {
1115      theme,
1116      active_menu_item : THMenuItem::Home,
1117    }
1118  }
1119
1120  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
1121    let menu_titles : Vec<&str> = vec!["Home", "Hits", "Pulses", "Paddles", "SelectPaddle", "Quit" ];
1122    let menu : Vec<Line> = menu_titles
1123               .iter()
1124               .map(|t| {
1125                 if t == &"Paddles" || t == &"Hits" {
1126                   let (second, rest) = t.split_at(2);
1127                   Line::from(vec![
1128                     Span::styled(
1129                         second,
1130                         Style::default()
1131                             .fg(self.theme.hc)
1132                             .add_modifier(Modifier::UNDERLINED),
1133                     ),
1134                     Span::styled(rest, self.theme.style()),
1135                   ])
1136                 } else {
1137                   let (first, rest) = t.split_at(1);
1138                   Line::from(vec![
1139                     Span::styled(
1140                         first,
1141                         Style::default()
1142                             .fg(self.theme.hc)
1143                             .add_modifier(Modifier::UNDERLINED),
1144                     ),
1145                     Span::styled(rest, self.theme.style()),
1146                   ])
1147                 }
1148               })
1149               .collect();
1150
1151    let tabs = Tabs::new(menu)
1152        .select(usize::from(self.active_menu_item))
1153        .block(Block::default().title("Menu").borders(Borders::ALL))
1154        .style(self.theme.style())
1155        .highlight_style(self.theme.highlight())
1156        .divider(Span::raw("|"));
1157    frame.render_widget(tabs, *main_window);
1158  }
1159}
1160
1161