use crate::*; pub trait StatusBar: Copy + Widget { type State; fn hotkey_fg () -> Color where Self: Sized; fn update (&mut self, state: &Self::State) where Self: Sized; fn command (commands: &[[impl Widget;3]]) -> impl Widget + '_ where Self: Sized { let hotkey_fg = Self::hotkey_fg(); Stack::right(move |add|{ Ok(for [a, b, c] in commands.iter() { add(&row!( " ", widget(a), widget(b).bold(true).fg(hotkey_fg), widget(c), ))?; }) }) } } #[derive(Copy, Clone)] pub struct TransportStatusBar; impl StatusBar for TransportStatusBar { type State = (); fn hotkey_fg () -> Color { TuiTheme::hotkey_fg() } fn update (&mut self, state: &()) { todo!() } } impl Content for TransportStatusBar { type Engine = Tui; fn content (&self) -> impl Widget { todo!(); "" } } /// Status bar for sequencer app #[derive(Copy, Clone)] pub enum SequencerStatusBar { Transport, PhrasePool, PhraseEditor, } impl StatusBar for SequencerStatusBar { type State = (); fn hotkey_fg () -> Color { TuiTheme::hotkey_fg() } fn update (&mut self, state: &()) { todo!() } } impl Content for SequencerStatusBar { type Engine = Tui; fn content (&self) -> impl Widget { todo!(); "" } } /// Status bar for arranger app #[derive(Copy, Clone, Debug)] pub enum ArrangerStatus { Transport, ArrangerMix, ArrangerTrack, ArrangerScene, ArrangerClip, PhrasePool, PhraseView, PhraseEdit, } impl StatusBar for ArrangerStatus { type State = (ArrangerFocus, ArrangerSelection, bool); fn hotkey_fg () -> Color where Self: Sized { TuiTheme::hotkey_fg() } fn update (&mut self, (focused, selected, entered): &Self::State) { *self = match focused { ArrangerFocus::Menu => { todo!() }, ArrangerFocus::Transport => ArrangerStatus::Transport, ArrangerFocus::Arranger => match selected { ArrangerSelection::Mix => ArrangerStatus::ArrangerMix, ArrangerSelection::Track(_) => ArrangerStatus::ArrangerTrack, ArrangerSelection::Scene(_) => ArrangerStatus::ArrangerScene, ArrangerSelection::Clip(_, _) => ArrangerStatus::ArrangerClip, }, ArrangerFocus::PhrasePool => ArrangerStatus::PhrasePool, ArrangerFocus::PhraseEditor => match entered { true => ArrangerStatus::PhraseEdit, false => ArrangerStatus::PhraseView, }, } } } impl Content for ArrangerStatus { type Engine = Tui; fn content (&self) -> impl Widget { let label = match self { Self::Transport => "TRANSPORT", Self::ArrangerMix => "PROJECT", Self::ArrangerTrack => "TRACK", Self::ArrangerScene => "SCENE", Self::ArrangerClip => "CLIP", Self::PhrasePool => "SEQ LIST", Self::PhraseView => "VIEW SEQ", Self::PhraseEdit => "EDIT SEQ", }; let status_bar_bg = TuiTheme::status_bar_bg(); let mode_bg = TuiTheme::mode_bg(); let mode_fg = TuiTheme::mode_fg(); let mode = TuiStyle::bold(format!(" {label} "), true).bg(mode_bg).fg(mode_fg); let commands = match self { Self::ArrangerMix => Self::command(&[ ["", "c", "olor"], ["", "<>", "resize"], ["", "+-", "zoom"], ["", "n", "ame/number"], ["", "Enter", " stop all"], ]), Self::ArrangerClip => Self::command(&[ ["", "g", "et"], ["", "s", "et"], ["", "a", "dd"], ["", "i", "ns"], ["", "d", "up"], ["", "e", "dit"], ["", "c", "olor"], ["re", "n", "ame"], ["", ",.", "select"], ["", "Enter", " launch"], ]), Self::ArrangerTrack => Self::command(&[ ["re", "n", "ame"], ["", ",.", "resize"], ["", "<>", "move"], ["", "i", "nput"], ["", "o", "utput"], ["", "m", "ute"], ["", "s", "olo"], ["", "Del", "ete"], ["", "Enter", " stop"], ]), Self::ArrangerScene => Self::command(&[ ["re", "n", "ame"], ["", "Del", "ete"], ["", "Enter", " launch"], ]), Self::PhrasePool => Self::command(&[ ["", "a", "ppend"], ["", "i", "nsert"], ["", "d", "uplicate"], ["", "Del", "ete"], ["", "c", "olor"], ["re", "n", "ame"], ["leng", "t", "h"], ["", ",.", "move"], ["", "+-", "resize view"], ]), Self::PhraseView => Self::command(&[ ["", "enter", " edit"], ["", "arrows/pgup/pgdn", " scroll"], ["", "+=", "zoom"], ]), Self::PhraseEdit => Self::command(&[ ["", "esc", " exit"], ["", "a", "ppend"], ["", "s", "et"], ["", "][", "length"], ["", "+-", "zoom"], ]), _ => Self::command(&[]) }; //let commands = commands.iter().reduce(String::new(), |s, (a, b, c)| format!("{s} {a}{b}{c}")); row!(mode, commands).fill_x().bg(status_bar_bg) } }