diff options
| -rw-r--r-- | src/app.rs | 26 | ||||
| -rw-r--r-- | src/input.rs | 42 | ||||
| -rw-r--r-- | src/main.rs | 87 |
3 files changed, 95 insertions, 60 deletions
@@ -7,14 +7,18 @@ pub struct App { pub tab_index: usize, tab_titles: [&'static str; 2], - pub rows: Vec<Row>, - pub selected_row: usize, - pub selected_column: InputParam, + rows: Vec<Row>, + selected_row: usize, + selected_column: InputParam, pub input_mode: InputMode, } impl App { + pub fn rows(&self) -> &Vec<Row> { + &self.rows + } + pub fn tab_titles(&self) -> &[&str] { &self.tab_titles } @@ -68,6 +72,22 @@ impl App { } } } + + pub fn selected_input_param(&self) -> &InputParam { + match self.selected_column { + InputParam::Rpm(_) => &self.rows[self.selected_row].rpm, + InputParam::Ve(_) => &self.rows[self.selected_row].ve, + InputParam::Map(_) => &self.rows[self.selected_row].map, + } + } + + pub fn selected_input_param_mut(&mut self) -> &mut InputParam { + match self.selected_column { + InputParam::Rpm(_) => &mut self.rows[self.selected_row].rpm, + InputParam::Ve(_) => &mut self.rows[self.selected_row].ve, + InputParam::Map(_) => &mut self.rows[self.selected_row].map, + } + } } impl Default for App { diff --git a/src/input.rs b/src/input.rs index 513aef6..8f80a1d 100644 --- a/src/input.rs +++ b/src/input.rs @@ -95,6 +95,12 @@ pub struct Row { pub map: InputParam, } +impl Row { + pub fn iter(&self) -> RowIter { + RowIter::from_row(&self) + } +} + impl Default for Row { fn default() -> Self { Self { @@ -104,3 +110,39 @@ impl Default for Row { } } } + +pub struct RowIter<'a> { + row: &'a Row, + iter_state: Option<InputParam>, +} + +impl<'a> RowIter<'a> { + fn from_row(row: &'a Row) -> Self { + Self { + row: row, + iter_state: Some(InputParam::Rpm(String::new())), + } + } +} + +impl<'a> Iterator for RowIter<'a> { + type Item = &'a InputParam; + + fn next(&mut self) -> Option<Self::Item> { + match self.iter_state { + Some(InputParam::Rpm(_)) => { + self.iter_state = Some(InputParam::Ve(String::new())); + Some(&self.row.rpm) + } + Some(InputParam::Ve(_)) => { + self.iter_state = Some(InputParam::Map(String::new())); + Some(&self.row.ve) + } + Some(InputParam::Map(_)) => { + self.iter_state = None; + Some(&self.row.map) + } + None => None, + } + } +} diff --git a/src/main.rs b/src/main.rs index 1fb4a39..f4163a8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use std::{error::Error, io}; +use std::{error::Error, io, ptr}; use tui::{ backend::{Backend, CrosstermBackend}, layout::{Constraint, Direction, Layout}, @@ -14,7 +14,7 @@ use tui::{ }; use volute::{ app::{App, CONFIG_TAB_INDEX, INPUT_TAB_INDEX}, - input::{InputMode, InputParam}, + input::InputMode, }; fn main() -> Result<(), Box<dyn Error>> { @@ -74,16 +74,8 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<( KeyCode::Esc | KeyCode::Enter => { app.input_mode = InputMode::Normal; } - KeyCode::Char(c) => match app.selected_column { - InputParam::Rpm(_) => app.rows[app.selected_row].rpm.push(c), - InputParam::Ve(_) => app.rows[app.selected_row].ve.push(c), - InputParam::Map(_) => app.rows[app.selected_row].map.push(c), - }, - KeyCode::Backspace => match app.selected_column { - InputParam::Rpm(_) => app.rows[app.selected_row].rpm.pop(), - InputParam::Ve(_) => app.rows[app.selected_row].ve.pop(), - InputParam::Map(_) => app.rows[app.selected_row].map.pop(), - }, + KeyCode::Char(c) => app.selected_input_param_mut().push(c), + KeyCode::Backspace => app.selected_input_param_mut().pop(), _ => {} }, }, @@ -118,10 +110,10 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) { .direction(Direction::Vertical) .constraints( [ - Constraint::Length(3), // Tabs - Constraint::Length(app.rows.len() as u16 + 3), // Input table - Constraint::Max(100), // Spacer - Constraint::Length(1), // Footer + Constraint::Length(3), // Tabs + Constraint::Length(app.rows().len() as u16 + 3), // Input table + Constraint::Max(100), // Spacer + Constraint::Length(1), // Footer ] .as_ref(), ) @@ -143,49 +135,30 @@ fn ui<B: Backend>(f: &mut Frame<B>, app: &App) { } fn input_table(app: &App) -> impl Widget { - // This is used so I can have named fields instead of indexing a vector of - // Cells when styling the selected input parameter. - struct VirtualRow<'a> { - rpm: Cell<'a>, - ve: Cell<'a>, - map: Cell<'a>, - } - - let mut rows: Vec<VirtualRow> = app - .rows - .iter() - .map(|row| VirtualRow { - rpm: Cell::from(row.rpm.string()), - ve: Cell::from(row.ve.string()), - map: Cell::from(row.map.string()), - }) - .collect(); - - // Highlight the selected parameter - let selected_parameter = match app.selected_column { - InputParam::Rpm(_) => &mut rows[app.selected_row].rpm, - InputParam::Ve(_) => &mut rows[app.selected_row].ve, - InputParam::Map(_) => &mut rows[app.selected_row].map, - }; - *selected_parameter = selected_parameter.clone().style(match app.input_mode { - InputMode::Normal => Style::default().fg(Color::Yellow), - InputMode::Insert => Style::default() - .fg(Color::Yellow) - .add_modifier(Modifier::ITALIC), + let rows = app.rows().iter().map(|row| { + let cells = row.iter().map(|item| { + if ptr::eq(item, app.selected_input_param()) { + Cell::from(item.string()).style(match app.input_mode { + InputMode::Normal => Style::default().fg(Color::Yellow), + InputMode::Insert => Style::default() + .fg(Color::Blue) + .add_modifier(Modifier::ITALIC), + }) + } else { + Cell::from(item.string()) + } + }); + widgets::Row::new(cells) }); - Table::new( - rows.iter() - .map(|row| widgets::Row::new(vec![row.rpm.clone(), row.ve.clone(), row.map.clone()])) - .collect::<Vec<widgets::Row>>(), - ) - .header(widgets::Row::new(vec!["rpm", "ve", "map"])) - .block(Block::default().borders(Borders::ALL).title("inputs")) - .widths(&[ - Constraint::Length(5), // rpm - Constraint::Length(3), // ve - Constraint::Length(3), // map - ]) + Table::new(rows) + .header(widgets::Row::new(vec!["rpm", "ve", "map"])) + .block(Block::default().borders(Borders::ALL).title("inputs")) + .widths(&[ + Constraint::Length(5), // rpm + Constraint::Length(3), // ve + Constraint::Length(3), // map + ]) } fn footer(app: &App) -> impl Widget { |