mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
flatten workspace into 1 crate
This commit is contained in:
parent
7c4e1e2166
commit
d926422c67
147 changed files with 66 additions and 126 deletions
144
src/pool/phrase_length.rs
Normal file
144
src/pool/phrase_length.rs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
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();
|
||||
row!(move|add|match self.focus {
|
||||
None =>
|
||||
add(&row!([" ", bars(), ".", beats(), ".", ticks()])),
|
||||
Some(PhraseLengthFocus::Bar) =>
|
||||
add(&row!(["[", bars(), "]", beats(), ".", ticks()])),
|
||||
Some(PhraseLengthFocus::Beat) =>
|
||||
add(&row!([" ", bars(), "[", beats(), "]", ticks()])),
|
||||
Some(PhraseLengthFocus::Tick) =>
|
||||
add(&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