mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
cmdsys: menubar pt.1
This commit is contained in:
parent
2b163e9e27
commit
38e8cfc214
7 changed files with 180 additions and 136 deletions
|
|
@ -6,28 +6,65 @@ pub trait Command<S>: Sized {
|
||||||
pub trait MatchInput<E: Engine, S>: Sized {
|
pub trait MatchInput<E: Engine, S>: Sized {
|
||||||
fn match_input (state: &S, input: &E::Input) -> Option<Self>;
|
fn match_input (state: &S, input: &E::Input) -> Option<Self>;
|
||||||
}
|
}
|
||||||
pub struct Menu<E: Engine, S: Handle<E>, C: Command<S>> {
|
pub struct MenuBar<E: Engine, S, C: Command<S>> {
|
||||||
|
pub menus: Vec<Menu<E, S, C>>,
|
||||||
|
pub index: usize,
|
||||||
|
}
|
||||||
|
impl<E: Engine, S, C: Command<S>> MenuBar<E, S, C> {
|
||||||
|
pub fn new () -> Self { Self { menus: vec![], index: 0 } }
|
||||||
|
pub fn add (mut self, menu: Menu<E, S, C>) -> Self {
|
||||||
|
self.menus.push(menu);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct Menu<E: Engine, S, C: Command<S>> {
|
||||||
|
pub title: String,
|
||||||
pub items: Vec<MenuItem<E, S, C>>,
|
pub items: Vec<MenuItem<E, S, C>>,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
impl<E: Engine, S: Handle<E>, C: Command<S>> Menu<E, S, C> {
|
impl<E: Engine, S, C: Command<S>> Menu<E, S, C> {
|
||||||
pub const fn item (command: C, name: &'static str, key: &'static str) -> MenuItem<E, S, C> {
|
pub fn new (title: impl AsRef<str>) -> Self {
|
||||||
MenuItem::Command(command, name, key)
|
Self {
|
||||||
|
title: title.as_ref().to_string(),
|
||||||
|
items: vec![],
|
||||||
|
index: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add (mut self, item: MenuItem<E, S, C>) -> Self {
|
||||||
|
self.items.push(item);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn sep (mut self) -> Self {
|
||||||
|
self.items.push(MenuItem::sep());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn cmd (mut self, hotkey: &'static str, text: &'static str, command: C) -> Self {
|
||||||
|
self.items.push(MenuItem::cmd(hotkey, text, command));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn off (mut self, hotkey: &'static str, text: &'static str) -> Self {
|
||||||
|
self.items.push(MenuItem::off(hotkey, text));
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub enum MenuItem<E: Engine, S: Handle<E>, C: Command<S>> {
|
pub enum MenuItem<E: Engine, S, C: Command<S>> {
|
||||||
/// Unused.
|
/// Unused.
|
||||||
__(PhantomData<E>, PhantomData<S>),
|
__(PhantomData<E>, PhantomData<S>),
|
||||||
/// A separator. Skip it.
|
/// A separator. Skip it.
|
||||||
Separator,
|
Separator,
|
||||||
/// A menu item with command, description and hotkey.
|
/// A menu item with command, description and hotkey.
|
||||||
Command(C, &'static str, &'static str)
|
Command(&'static str, &'static str, C),
|
||||||
|
/// A menu item that can't be activated but has description and hotkey
|
||||||
|
Disabled(&'static str, &'static str)
|
||||||
}
|
}
|
||||||
impl<E: Engine, S: Handle<E>, C: Command<S>> MenuItem<E, S, C> {
|
impl<E: Engine, S, C: Command<S>> MenuItem<E, S, C> {
|
||||||
pub fn sep () -> Self {
|
pub fn sep () -> Self {
|
||||||
Self::Separator
|
Self::Separator
|
||||||
}
|
}
|
||||||
pub fn cmd (command: C, text: &'static str, hotkey: &'static str) -> Self {
|
pub fn cmd (hotkey: &'static str, text: &'static str, command: C) -> Self {
|
||||||
Self::Command(command, text, hotkey)
|
Self::Command(hotkey, text, command)
|
||||||
|
}
|
||||||
|
pub fn off (hotkey: &'static str, text: &'static str) -> Self {
|
||||||
|
Self::Disabled(hotkey, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ pub struct Arranger<E: Engine> {
|
||||||
pub phrases_split: u16,
|
pub phrases_split: u16,
|
||||||
/// Width and height of app at last render
|
/// Width and height of app at last render
|
||||||
pub size: Measure<E>,
|
pub size: Measure<E>,
|
||||||
|
/// Menu bar
|
||||||
|
pub menu: MenuBar<E, Self, ArrangerCommand>,
|
||||||
}
|
}
|
||||||
/// Sections in the arranger app that may be focused
|
/// Sections in the arranger app that may be focused
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
|
|
@ -141,6 +143,59 @@ impl<E: Engine> Arranger<E> {
|
||||||
} else {
|
} else {
|
||||||
Arc::new(TransportTime::default())
|
Arc::new(TransportTime::default())
|
||||||
},
|
},
|
||||||
|
menu: {
|
||||||
|
use ArrangerCommand::*;
|
||||||
|
MenuBar::new()
|
||||||
|
.add({
|
||||||
|
use ArrangementCommand::*;
|
||||||
|
Menu::new("File")
|
||||||
|
.cmd("n", "New project", Arrangement(New))
|
||||||
|
.cmd("l", "Load project", Arrangement(Load))
|
||||||
|
.cmd("s", "Save project", Arrangement(Save))
|
||||||
|
})
|
||||||
|
.add({
|
||||||
|
use TransportCommand::*;
|
||||||
|
Menu::new("Transport")
|
||||||
|
.cmd("p", "Play", Transport(Play))
|
||||||
|
.cmd("s", "Play from start", Transport(PlayFromStart))
|
||||||
|
.cmd("a", "Pause", Transport(Pause))
|
||||||
|
})
|
||||||
|
.add({
|
||||||
|
use ArrangementCommand::*;
|
||||||
|
Menu::new("Track")
|
||||||
|
.cmd("a", "Append new", Arrangement(AddTrack))
|
||||||
|
.cmd("i", "Insert new", Arrangement(AddTrack))
|
||||||
|
.cmd("n", "Rename", Arrangement(AddTrack))
|
||||||
|
.cmd("d", "Delete", Arrangement(AddTrack))
|
||||||
|
.cmd(">", "Move up", Arrangement(AddTrack))
|
||||||
|
.cmd("<", "Move down", Arrangement(AddTrack))
|
||||||
|
})
|
||||||
|
.add({
|
||||||
|
use ArrangementCommand::*;
|
||||||
|
Menu::new("Scene")
|
||||||
|
.cmd("a", "Append new", Arrangement(AddScene))
|
||||||
|
.cmd("i", "Insert new", Arrangement(AddTrack))
|
||||||
|
.cmd("n", "Rename", Arrangement(AddTrack))
|
||||||
|
.cmd("d", "Delete", Arrangement(AddTrack))
|
||||||
|
.cmd(">", "Move up", Arrangement(AddTrack))
|
||||||
|
.cmd("<", "Move down", Arrangement(AddTrack))
|
||||||
|
})
|
||||||
|
.add({
|
||||||
|
use PhrasePoolCommand::*;
|
||||||
|
use PhraseRenameCommand as Rename;
|
||||||
|
use PhraseLengthCommand as Length;
|
||||||
|
Menu::new("Phrase")
|
||||||
|
.cmd("a", "Append new", Phrases(Append))
|
||||||
|
.cmd("i", "Insert new", Phrases(Insert))
|
||||||
|
.cmd("n", "Rename", Phrases(Rename(Rename::Begin)))
|
||||||
|
.cmd("t", "Set length", Phrases(Length(Length::Begin)))
|
||||||
|
.cmd("d", "Delete", Phrases(Delete))
|
||||||
|
.cmd("l", "Load from MIDI...", Phrases(Import))
|
||||||
|
.cmd("s", "Save to MIDI...", Phrases(Export))
|
||||||
|
.cmd(">", "Move up", Phrases(MoveUp))
|
||||||
|
.cmd("<", "Move down", Phrases(MoveDown))
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
app.update_focus();
|
app.update_focus();
|
||||||
app
|
app
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ pub enum ArrangerCommand {
|
||||||
}
|
}
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum ArrangementCommand {
|
pub enum ArrangementCommand {
|
||||||
|
New,
|
||||||
|
Load,
|
||||||
|
Save,
|
||||||
ToggleViewMode,
|
ToggleViewMode,
|
||||||
Delete,
|
Delete,
|
||||||
Activate,
|
Activate,
|
||||||
|
|
@ -67,6 +70,9 @@ impl <E: Engine> Command<Arrangement<E>> for ArrangementCommand {
|
||||||
fn run (&self, state: &mut Arrangement<E>) -> Perhaps<Self> {
|
fn run (&self, state: &mut Arrangement<E>) -> Perhaps<Self> {
|
||||||
use ArrangementCommand::*;
|
use ArrangementCommand::*;
|
||||||
match self {
|
match self {
|
||||||
|
New => todo!(),
|
||||||
|
Load => todo!(),
|
||||||
|
Save => todo!(),
|
||||||
ToggleViewMode => { state.mode.to_next(); },
|
ToggleViewMode => { state.mode.to_next(); },
|
||||||
Delete => { state.delete(); },
|
Delete => { state.delete(); },
|
||||||
Activate => { state.activate(); },
|
Activate => { state.activate(); },
|
||||||
|
|
|
||||||
|
|
@ -533,7 +533,7 @@ impl MatchInput<Tui, Arranger<Tui>> for ArrangerCommand {
|
||||||
key!(KeyCode::Down) => Some(Self::FocusDown),
|
key!(KeyCode::Down) => Some(Self::FocusDown),
|
||||||
key!(KeyCode::Left) => Some(Self::FocusLeft),
|
key!(KeyCode::Left) => Some(Self::FocusLeft),
|
||||||
key!(KeyCode::Right) => Some(Self::FocusRight),
|
key!(KeyCode::Right) => Some(Self::FocusRight),
|
||||||
key!(KeyCode::Char(' ')) => Some(Self::Transport(TransportCommand::TogglePlay)),
|
key!(KeyCode::Char(' ')) => Some(Self::Transport(TransportCommand::PlayToggle)),
|
||||||
_ => match state.focused() {
|
_ => match state.focused() {
|
||||||
ArrangerFocus::Transport => state.transport.as_ref()
|
ArrangerFocus::Transport => state.transport.as_ref()
|
||||||
.map(|t|TransportCommand::match_input(&*t.read().unwrap(), input)
|
.map(|t|TransportCommand::match_input(&*t.read().unwrap(), input)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ pub enum PhrasePoolCommand {
|
||||||
Duplicate,
|
Duplicate,
|
||||||
RandomColor,
|
RandomColor,
|
||||||
Edit,
|
Edit,
|
||||||
|
Import,
|
||||||
|
Export,
|
||||||
Rename(PhraseRenameCommand),
|
Rename(PhraseRenameCommand),
|
||||||
Length(PhraseLengthCommand),
|
Length(PhraseLengthCommand),
|
||||||
}
|
}
|
||||||
|
|
@ -91,89 +93,65 @@ impl<E: Engine> Command<Sequencer<E>> for SequencerCommand {
|
||||||
}
|
}
|
||||||
impl<E: Engine> Command<PhrasePool<E>> for PhrasePoolCommand {
|
impl<E: Engine> Command<PhrasePool<E>> for PhrasePoolCommand {
|
||||||
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
||||||
|
use PhrasePoolCommand::*;
|
||||||
|
use PhraseRenameCommand as Rename;
|
||||||
|
use PhraseLengthCommand as Length;
|
||||||
match self {
|
match self {
|
||||||
Self::Prev => {
|
Prev => { state.select_prev() },
|
||||||
state.select_prev()
|
Next => { state.select_next() },
|
||||||
},
|
Delete => { state.delete_selected() },
|
||||||
Self::Next => {
|
Append => { state.append_new(None, None) },
|
||||||
state.select_next()
|
Insert => { state.insert_new(None, None) },
|
||||||
},
|
Duplicate => { state.insert_dup() },
|
||||||
Self::Delete => {
|
Edit => { todo!(); }
|
||||||
state.delete_selected()
|
RandomColor => { state.randomize_color() },
|
||||||
},
|
MoveUp => { state.move_up() },
|
||||||
Self::Append => {
|
MoveDown => { state.move_down() },
|
||||||
state.append_new(None, None)
|
Rename(Rename::Begin) => { state.begin_rename() },
|
||||||
},
|
Rename(_) => { unreachable!() },
|
||||||
Self::Insert => {
|
Length(Length::Begin) => { state.begin_length() },
|
||||||
state.insert_new(None, None)
|
Length(_) => { unreachable!() },
|
||||||
},
|
Import => todo!(),
|
||||||
Self::Duplicate => {
|
Export => todo!(),
|
||||||
state.insert_dup()
|
|
||||||
},
|
|
||||||
Self::Edit => {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
Self::RandomColor => {
|
|
||||||
state.randomize_color()
|
|
||||||
},
|
|
||||||
Self::MoveUp => {
|
|
||||||
state.move_up()
|
|
||||||
},
|
|
||||||
Self::MoveDown => {
|
|
||||||
state.move_down()
|
|
||||||
},
|
|
||||||
Self::Rename(PhraseRenameCommand::Begin) => {
|
|
||||||
state.begin_rename()
|
|
||||||
},
|
|
||||||
Self::Rename(_) => {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
Self::Length(PhraseLengthCommand::Begin) => {
|
|
||||||
state.begin_length()
|
|
||||||
},
|
|
||||||
Self::Length(_) => {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: Engine> Command<PhrasePool<E>> for PhraseRenameCommand {
|
impl<E: Engine> Command<PhrasePool<E>> for PhraseRenameCommand {
|
||||||
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
||||||
|
use PhraseRenameCommand::*;
|
||||||
if let Some(PhrasePoolMode::Rename(phrase, ref mut old_name)) = state.mode {
|
if let Some(PhrasePoolMode::Rename(phrase, ref mut old_name)) = state.mode {
|
||||||
match self {
|
match self {
|
||||||
Self::Begin => {
|
Begin => { unreachable!(); },
|
||||||
unreachable!();
|
Backspace => {
|
||||||
},
|
|
||||||
Self::Backspace => {
|
|
||||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||||
let old_name = phrase.name.clone();
|
let old_name = phrase.name.clone();
|
||||||
phrase.name.pop();
|
phrase.name.pop();
|
||||||
return Ok(Some(Self::Set(old_name)))
|
return Ok(Some(Self::Set(old_name)))
|
||||||
},
|
},
|
||||||
Self::Append(c) => {
|
Append(c) => {
|
||||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||||
let old_name = phrase.name.clone();
|
let old_name = phrase.name.clone();
|
||||||
phrase.name.push(*c);
|
phrase.name.push(*c);
|
||||||
return Ok(Some(Self::Set(old_name)))
|
return Ok(Some(Self::Set(old_name)))
|
||||||
},
|
},
|
||||||
Self::Set(s) => {
|
Set(s) => {
|
||||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||||
phrase.name = s.into();
|
phrase.name = s.into();
|
||||||
return Ok(Some(Self::Set(old_name.clone())))
|
return Ok(Some(Self::Set(old_name.clone())))
|
||||||
},
|
},
|
||||||
Self::Confirm => {
|
Confirm => {
|
||||||
let old_name = old_name.clone();
|
let old_name = old_name.clone();
|
||||||
state.mode = None;
|
state.mode = None;
|
||||||
return Ok(Some(Self::Set(old_name)))
|
return Ok(Some(Self::Set(old_name)))
|
||||||
},
|
},
|
||||||
Self::Cancel => {
|
Cancel => {
|
||||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||||
phrase.name = old_name.clone();
|
phrase.name = old_name.clone();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else if *self == Self::Begin {
|
} else if *self == Begin {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
@ -182,46 +160,31 @@ impl<E: Engine> Command<PhrasePool<E>> for PhraseRenameCommand {
|
||||||
}
|
}
|
||||||
impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
|
impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
|
||||||
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
fn run (&self, state: &mut PhrasePool<E>) -> Perhaps<Self> {
|
||||||
|
use PhraseLengthCommand::*;
|
||||||
if let Some(PhrasePoolMode::Length(phrase, ref mut length, ref mut focus)) = state.mode {
|
if let Some(PhrasePoolMode::Length(phrase, ref mut length, ref mut focus)) = state.mode {
|
||||||
match self {
|
match self {
|
||||||
Self::Begin => {
|
Begin => { unreachable!(); },
|
||||||
unreachable!();
|
Cancel => { state.mode = None; },
|
||||||
|
Confirm => { return Self::Set(*length).run(state) },
|
||||||
|
Prev => { focus.prev() },
|
||||||
|
Next => { focus.next() },
|
||||||
|
Inc => {
|
||||||
|
use PhraseLengthFocus::*;
|
||||||
|
match focus {
|
||||||
|
Bar => { *length += 4 * PPQ },
|
||||||
|
Beat => { *length += PPQ },
|
||||||
|
Tick => { *length += 1 },
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Self::Prev => {
|
Dec => {
|
||||||
focus.prev()
|
use PhraseLengthFocus::*;
|
||||||
|
match focus {
|
||||||
|
Bar => { *length = length.saturating_sub(4 * PPQ) },
|
||||||
|
Beat => { *length = length.saturating_sub(PPQ) },
|
||||||
|
Tick => { *length = length.saturating_sub(1) },
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Self::Next => {
|
Set(length) => {
|
||||||
focus.next()
|
|
||||||
},
|
|
||||||
Self::Inc => match focus {
|
|
||||||
PhraseLengthFocus::Bar => {
|
|
||||||
*length += 4 * PPQ
|
|
||||||
},
|
|
||||||
PhraseLengthFocus::Beat => {
|
|
||||||
*length += PPQ
|
|
||||||
},
|
|
||||||
PhraseLengthFocus::Tick => {
|
|
||||||
*length += 1
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Self::Dec => match focus {
|
|
||||||
PhraseLengthFocus::Bar => {
|
|
||||||
*length = length.saturating_sub(4 * PPQ)
|
|
||||||
},
|
|
||||||
PhraseLengthFocus::Beat => {
|
|
||||||
*length = length.saturating_sub(PPQ)
|
|
||||||
},
|
|
||||||
PhraseLengthFocus::Tick => {
|
|
||||||
*length = length.saturating_sub(1)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Self::Cancel => {
|
|
||||||
state.mode = None;
|
|
||||||
},
|
|
||||||
Self::Confirm => {
|
|
||||||
return Self::Set(*length).run(state)
|
|
||||||
},
|
|
||||||
Self::Set(length) => {
|
|
||||||
let mut phrase = state.phrases[phrase].write().unwrap();
|
let mut phrase = state.phrases[phrase].write().unwrap();
|
||||||
let old_length = phrase.length;
|
let old_length = phrase.length;
|
||||||
phrase.length = *length;
|
phrase.length = *length;
|
||||||
|
|
@ -230,7 +193,7 @@ impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else if *self == Self::Begin {
|
} else if *self == Begin {
|
||||||
todo!()
|
todo!()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
@ -239,54 +202,35 @@ impl<E: Engine> Command<PhrasePool<E>> for PhraseLengthCommand {
|
||||||
}
|
}
|
||||||
impl<E: Engine> Command<PhraseEditor<E>> for PhraseEditorCommand {
|
impl<E: Engine> Command<PhraseEditor<E>> for PhraseEditorCommand {
|
||||||
fn run (&self, state: &mut PhraseEditor<E>) -> Perhaps<Self> {
|
fn run (&self, state: &mut PhraseEditor<E>) -> Perhaps<Self> {
|
||||||
|
use PhraseEditorCommand::*;
|
||||||
match self {
|
match self {
|
||||||
Self::ToggleDirection => {
|
ToggleDirection => { state.mode = !state.mode; },
|
||||||
state.mode = !state.mode;
|
EnterEditMode => { state.entered = true; },
|
||||||
},
|
ExitEditMode => { state.entered = false; },
|
||||||
Self::EnterEditMode => {
|
TimeZoomOut => { state.time_zoom_out() },
|
||||||
state.entered = true;
|
TimeZoomIn => { state.time_zoom_in() },
|
||||||
},
|
NoteLengthDec => { state.note_length_dec() },
|
||||||
Self::ExitEditMode => {
|
NoteLengthInc => { state.note_length_inc() },
|
||||||
state.entered = false;
|
NotePageUp => { state.note_page_up() },
|
||||||
},
|
NotePageDown => { state.note_page_down() },
|
||||||
Self::TimeZoomOut => {
|
NoteAppend => if state.entered {
|
||||||
state.time_zoom_out()
|
|
||||||
},
|
|
||||||
Self::TimeZoomIn => {
|
|
||||||
state.time_zoom_in()
|
|
||||||
},
|
|
||||||
Self::NoteLengthDec => {
|
|
||||||
state.note_length_dec()
|
|
||||||
},
|
|
||||||
Self::NoteLengthInc => {
|
|
||||||
state.note_length_inc()
|
|
||||||
},
|
|
||||||
Self::NotePageUp => {
|
|
||||||
state.note_page_up()
|
|
||||||
},
|
|
||||||
Self::NotePageDown => {
|
|
||||||
state.note_page_down()
|
|
||||||
},
|
|
||||||
Self::NoteAppend => if state.entered {
|
|
||||||
state.put();
|
state.put();
|
||||||
state.time_cursor_advance();
|
state.time_cursor_advance();
|
||||||
},
|
},
|
||||||
Self::NoteSet => if state.entered {
|
NoteSet => if state.entered { state.put(); },
|
||||||
state.put();
|
GoUp => match state.entered {
|
||||||
},
|
|
||||||
Self::GoUp => match state.entered {
|
|
||||||
true => state.note_cursor_inc(),
|
true => state.note_cursor_inc(),
|
||||||
false => state.note_scroll_inc(),
|
false => state.note_scroll_inc(),
|
||||||
},
|
},
|
||||||
Self::GoDown => match state.entered {
|
GoDown => match state.entered {
|
||||||
true => state.note_cursor_dec(),
|
true => state.note_cursor_dec(),
|
||||||
false => state.note_scroll_dec(),
|
false => state.note_scroll_dec(),
|
||||||
},
|
},
|
||||||
Self::GoLeft => match state.entered {
|
GoLeft => match state.entered {
|
||||||
true => state.time_cursor_dec(),
|
true => state.time_cursor_dec(),
|
||||||
false => state.time_scroll_dec(),
|
false => state.time_scroll_dec(),
|
||||||
},
|
},
|
||||||
Self::GoRight => match state.entered {
|
GoRight => match state.entered {
|
||||||
true => state.time_cursor_inc(),
|
true => state.time_cursor_inc(),
|
||||||
false => state.time_scroll_inc(),
|
false => state.time_scroll_inc(),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ impl MatchInput<Tui, Sequencer<Tui>> for SequencerCommand {
|
||||||
key!(KeyCode::Down) => Some(Self::FocusDown),
|
key!(KeyCode::Down) => Some(Self::FocusDown),
|
||||||
key!(KeyCode::Left) => Some(Self::FocusLeft),
|
key!(KeyCode::Left) => Some(Self::FocusLeft),
|
||||||
key!(KeyCode::Right) => Some(Self::FocusRight),
|
key!(KeyCode::Right) => Some(Self::FocusRight),
|
||||||
key!(KeyCode::Char(' ')) => Some(Self::Transport(TransportCommand::TogglePlay)),
|
key!(KeyCode::Char(' ')) => Some(Self::Transport(TransportCommand::PlayToggle)),
|
||||||
_ => match state.focused() {
|
_ => match state.focused() {
|
||||||
SequencerFocus::Transport => state.transport.as_ref()
|
SequencerFocus::Transport => state.transport.as_ref()
|
||||||
.map(|t|TransportCommand::match_input(&*t.read().unwrap(), input)
|
.map(|t|TransportCommand::match_input(&*t.read().unwrap(), input)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ use crate::*;
|
||||||
pub enum TransportCommand {
|
pub enum TransportCommand {
|
||||||
FocusNext,
|
FocusNext,
|
||||||
FocusPrev,
|
FocusPrev,
|
||||||
|
Play,
|
||||||
|
Pause,
|
||||||
|
PlayToggle,
|
||||||
PlayFromStart,
|
PlayFromStart,
|
||||||
TogglePlay,
|
|
||||||
Increment,
|
Increment,
|
||||||
Decrement,
|
Decrement,
|
||||||
FineIncrement,
|
FineIncrement,
|
||||||
|
|
@ -25,7 +27,7 @@ impl<E: Engine> Command<TransportToolbar<E>> for TransportCommand {
|
||||||
Self::FocusPrev => {
|
Self::FocusPrev => {
|
||||||
state.focus.prev();
|
state.focus.prev();
|
||||||
},
|
},
|
||||||
Self::TogglePlay => {
|
Self::PlayToggle => {
|
||||||
state.toggle_play()?;
|
state.toggle_play()?;
|
||||||
},
|
},
|
||||||
Self::Increment => {
|
Self::Increment => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue