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