mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
unified compact flag in groovebox
This commit is contained in:
parent
c9a79b1f29
commit
511ff91864
12 changed files with 129 additions and 188 deletions
|
|
@ -1,144 +0,0 @@
|
|||
use crate::*;
|
||||
use super::*;
|
||||
use PhraseLengthFocus::*;
|
||||
use PhraseLengthCommand::*;
|
||||
use KeyCode::{Up, Down, Left, Right, Enter, Esc};
|
||||
|
||||
/// Displays and edits phrase length.
|
||||
#[derive(Clone)]
|
||||
pub struct PhraseLength {
|
||||
/// Pulses per beat (quaver)
|
||||
pub ppq: usize,
|
||||
/// Beats per bar
|
||||
pub bpb: usize,
|
||||
/// Length of phrase in pulses
|
||||
pub pulses: usize,
|
||||
/// Selected subdivision
|
||||
pub focus: Option<PhraseLengthFocus>,
|
||||
}
|
||||
|
||||
impl PhraseLength {
|
||||
pub fn new (pulses: usize, focus: Option<PhraseLengthFocus>) -> Self {
|
||||
Self { ppq: PPQ, bpb: 4, pulses, focus }
|
||||
}
|
||||
pub fn bars (&self) -> usize {
|
||||
self.pulses / (self.bpb * self.ppq)
|
||||
}
|
||||
pub fn beats (&self) -> usize {
|
||||
(self.pulses % (self.bpb * self.ppq)) / self.ppq
|
||||
}
|
||||
pub fn ticks (&self) -> usize {
|
||||
self.pulses % self.ppq
|
||||
}
|
||||
pub fn bars_string (&self) -> String {
|
||||
format!("{}", self.bars())
|
||||
}
|
||||
pub fn beats_string (&self) -> String {
|
||||
format!("{}", self.beats())
|
||||
}
|
||||
pub fn ticks_string (&self) -> String {
|
||||
format!("{:>02}", self.ticks())
|
||||
}
|
||||
}
|
||||
|
||||
/// Focused field of `PhraseLength`
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PhraseLengthFocus {
|
||||
/// Editing the number of bars
|
||||
Bar,
|
||||
/// Editing the number of beats
|
||||
Beat,
|
||||
/// Editing the number of ticks
|
||||
Tick,
|
||||
}
|
||||
|
||||
impl PhraseLengthFocus {
|
||||
pub fn next (&mut self) {
|
||||
*self = match self {
|
||||
Self::Bar => Self::Beat,
|
||||
Self::Beat => Self::Tick,
|
||||
Self::Tick => Self::Bar,
|
||||
}
|
||||
}
|
||||
pub fn prev (&mut self) {
|
||||
*self = match self {
|
||||
Self::Bar => Self::Tick,
|
||||
Self::Beat => Self::Bar,
|
||||
Self::Tick => Self::Beat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render!(Tui: (self: PhraseLength) => {
|
||||
let bars = ||self.bars_string();
|
||||
let beats = ||self.beats_string();
|
||||
let ticks = ||self.ticks_string();
|
||||
match self.focus {
|
||||
None =>
|
||||
row!(" ", bars(), ".", beats(), ".", ticks()),
|
||||
Some(PhraseLengthFocus::Bar) =>
|
||||
row!("[", bars(), "]", beats(), ".", ticks()),
|
||||
Some(PhraseLengthFocus::Beat) =>
|
||||
row!(" ", bars(), "[", beats(), "]", ticks()),
|
||||
Some(PhraseLengthFocus::Tick) =>
|
||||
row!(" ", bars(), ".", beats(), "[", ticks()),
|
||||
}
|
||||
});
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum PhraseLengthCommand {
|
||||
Begin,
|
||||
Cancel,
|
||||
Set(usize),
|
||||
Next,
|
||||
Prev,
|
||||
Inc,
|
||||
Dec,
|
||||
}
|
||||
|
||||
command!(|self:PhraseLengthCommand,state:PoolModel|{
|
||||
match state.phrases_mode_mut().clone() {
|
||||
Some(PoolMode::Length(phrase, ref mut length, ref mut focus)) => match self {
|
||||
Cancel => { *state.phrases_mode_mut() = None; },
|
||||
Prev => { focus.prev() },
|
||||
Next => { focus.next() },
|
||||
Inc => match focus {
|
||||
Bar => { *length += 4 * PPQ },
|
||||
Beat => { *length += PPQ },
|
||||
Tick => { *length += 1 },
|
||||
},
|
||||
Dec => match focus {
|
||||
Bar => { *length = length.saturating_sub(4 * PPQ) },
|
||||
Beat => { *length = length.saturating_sub(PPQ) },
|
||||
Tick => { *length = length.saturating_sub(1) },
|
||||
},
|
||||
Set(length) => {
|
||||
let mut phrase = state.phrases()[phrase].write().unwrap();
|
||||
let old_length = phrase.length;
|
||||
phrase.length = length;
|
||||
std::mem::drop(phrase);
|
||||
*state.phrases_mode_mut() = None;
|
||||
return Ok(Some(Self::Set(old_length)))
|
||||
},
|
||||
_ => unreachable!()
|
||||
},
|
||||
_ => unreachable!()
|
||||
};
|
||||
None
|
||||
});
|
||||
|
||||
input_to_command!(PhraseLengthCommand:<Tui>|state:PoolModel,from|{
|
||||
if let Some(PoolMode::Length(_, length, _)) = state.phrases_mode() {
|
||||
match from.event() {
|
||||
key_pat!(Up) => Self::Inc,
|
||||
key_pat!(Down) => Self::Dec,
|
||||
key_pat!(Right) => Self::Next,
|
||||
key_pat!(Left) => Self::Prev,
|
||||
key_pat!(Enter) => Self::Set(*length),
|
||||
key_pat!(Esc) => Self::Cancel,
|
||||
_ => return None
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue