very colorized

This commit is contained in:
🪞👃🪞 2024-12-16 21:10:59 +01:00
parent a20b8e5518
commit 0d1d7a05b9
3 changed files with 46 additions and 31 deletions

View file

@ -2,6 +2,7 @@ use crate::{*, api::ClockCommand::{Play, Pause}};
use KeyCode::{Tab, BackTab, Char};
use SequencerCommand::*;
use PhraseCommand::*;
use PhrasePoolCommand::*;
/// Create app state from JACK handle.
impl TryFrom<&Arc<RwLock<JackClient>>> for SequencerTui {
@ -58,17 +59,29 @@ impl Command<SequencerTui> for SequencerCommand {
fn execute (self, state: &mut SequencerTui) -> Perhaps<Self> {
Ok(match self {
Self::Phrases(cmd) => {
let mut default = |cmd: PhrasesCommand|cmd.execute(&mut state.phrases).map(|x|x.map(Phrases));
match cmd {
// autoselect: automatically load selected phrase in editor
PhrasesCommand::Select(_) => {
let undo = cmd.execute(&mut state.phrases)?.map(Phrases);
Editor(Show(Some(state.phrases.phrase().clone()))).execute(state)?;
let undo = default(cmd)?;
state.editor.set_phrase(Some(state.phrases.phrase()));
undo
},
_ => cmd.execute(&mut state.phrases)?.map(Phrases)
// update color in all places simultaneously
PhrasesCommand::Phrase(SetColor(index, _)) => {
let undo = default(cmd)?;
state.editor.set_phrase(Some(state.phrases.phrase()));
undo
},
_ => default(cmd)?
}
},
Self::Editor(cmd) => {
let default = ||cmd.execute(&mut state.editor).map(|x|x.map(Editor));
match cmd {
_ => default()?
}
},
Self::Editor(cmd) => cmd.execute(&mut state.editor)?.map(Editor),
Self::Clock(cmd) => cmd.execute(state)?.map(Clock),
Self::Enqueue(phrase) => {
state.player.enqueue_next(phrase.as_ref());
@ -85,41 +98,41 @@ impl Command<SequencerTui> for SequencerCommand {
impl InputToCommand<Tui, SequencerTui> for SequencerCommand {
fn input_to_command (state: &SequencerTui, input: &TuiInput) -> Option<Self> {
Some(match input.event() {
// TODO: u: undo
key_pat!(Char('u')) => { todo!("undo") },
// TODO: Shift-U: redo
key_pat!(Char('U')) => { todo!("redo") },
// TODO: k: toggle on-screen keyboard
key_pat!(Ctrl-Char('k')) => { todo!("keyboard") },
// Toggle visibility of phrase pool column
// Tab: Toggle visibility of phrase pool column
key_pat!(Tab) => ShowPool(!state.show_pool),
// Enqueue currently edited phrase
// q: Enqueue currently edited phrase
key_pat!(Char('q')) => Enqueue(Some(state.phrases.phrase().clone())),
// 0: Enqueue phrase 0 (stop all)
key_pat!(Char('0')) => Enqueue(Some(state.phrases.phrases()[0].clone())),
// E: Toggle between editing currently playing or other phrase
key_pat!(Char('e')) => if let Some((_, Some(playing_phrase))) = state.player.play_phrase() {
let editing_phrase = state.editor.phrase().as_ref().map(|p|p.read().unwrap().clone());
let selected_phrase = state.phrases.phrase().clone();
if Some(selected_phrase.read().unwrap().clone()) != editing_phrase {
Editor(Show(Some(selected_phrase)))
// e: Toggle between editing currently playing or other phrase
key_pat!(Char('e')) => if let Some((_, Some(playing))) = state.player.play_phrase() {
let editing = state.editor.phrase().as_ref().map(|p|p.read().unwrap().clone());
let selected = state.phrases.phrase().clone();
Editor(Show(Some(if Some(selected.read().unwrap().clone()) != editing {
selected
} else {
Editor(Show(Some(playing_phrase.clone())))
}
playing.clone()
})))
} else {
return None
},
// Transport: Play/pause
key_pat!(Char(' ')) => Clock(if state.clock().is_stopped() {
Play(None)
} else {
Pause(None)
}),
Play(None) } else { Pause(None) }),
// Transport: Play from start or rewind to start
key_pat!(Shift-Char(' ')) => Clock(if state.clock().is_stopped() {
Play(Some(0))
} else {
Pause(Some(0))
}),
// Delegate to components:
Play(Some(0)) } else { Pause(Some(0)) }),
// For the rest, use the default keybindings of the components.
// The ones defined above supersede them.
_ => if let Some(command) = PhraseCommand::input_to_command(&state.editor, input) {
Editor(command)
} else if let Some(command) = PhrasesCommand::input_to_command(&state.phrases, input) {
@ -314,7 +327,8 @@ render!(|self: SequencerStatusBar|Tui::fixed_y(2, lay!([
Tui::fg_bg(TuiTheme::g(255), TuiTheme::g(50), row!([
single("SPACE", "play/pause"),
double(("", "cursor"), ("C-✣", "scroll"), ),
double((",.", "note"), ("<>", "triplet"),),
double(("a", "append"), ("s", "set note"),),
double((",.", "note"), ("<>", "triplet"), ),
double(("[]", "phrase"), ("{}", "order"), ),
double(("q", "enqueue"), ("e", "edit"), ),
]))

View file

@ -107,13 +107,14 @@ impl Command<PhraseEditorModel> for PhraseCommand {
pub struct PhraseEditorModel {
/// Renders the phrase
pub mode: Box<dyn PhraseViewMode>,
pub size: Measure<Tui>
}
impl Default for PhraseEditorModel {
fn default () -> Self {
Self { mode: Box::new(PianoHorizontal::new(None)), size: Measure::new() }
let mut mode = Box::new(PianoHorizontal::new(None));
mode.redraw();
Self { mode, size: Measure::new() }
}
}

View file

@ -47,7 +47,7 @@ render!(|self: PianoHorizontal|{
let notes = move||PianoHorizontalNotes { range, buffer };
let cursor = move||PianoHorizontalCursor { range, point };
let keys_width = 5;
Tui::fill_xy(Tui::bg(color.dark.rgb, Bsp::s(
Tui::fill_xy(Tui::bg(color.darker.rgb, Bsp::s(
Tui::fill_x(Tui::push_x(keys_width, timeline())),
Bsp::w(
Tui::shrink_x(keys_width, Tui::fill_xy(