mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-08 04:36:45 +01:00
modify pool width; wip: status bars
This commit is contained in:
parent
4994e218f7
commit
0699b9d105
5 changed files with 104 additions and 40 deletions
|
|
@ -14,6 +14,12 @@ pub struct Arranger<E: Engine> {
|
||||||
pub editor: PhraseEditor<E>,
|
pub editor: PhraseEditor<E>,
|
||||||
/// This allows the sequencer view to be moved or hidden.
|
/// This allows the sequencer view to be moved or hidden.
|
||||||
pub show_sequencer: Option<tek_core::Direction>,
|
pub show_sequencer: Option<tek_core::Direction>,
|
||||||
|
/// Status bar
|
||||||
|
pub status: ArrangerStatusBar,
|
||||||
|
/// Height of arrangement
|
||||||
|
pub arrangement_split: u16,
|
||||||
|
/// Width of phrase pool
|
||||||
|
pub phrases_split: u16,
|
||||||
}
|
}
|
||||||
/// 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)]
|
||||||
|
|
@ -27,6 +33,13 @@ pub enum ArrangerFocus {
|
||||||
/// The phrase editor (sequencer) is focused
|
/// The phrase editor (sequencer) is focused
|
||||||
PhraseEditor,
|
PhraseEditor,
|
||||||
}
|
}
|
||||||
|
/// Status bar for arranger ap
|
||||||
|
pub enum ArrangerStatusBar {
|
||||||
|
Transport,
|
||||||
|
Arrangement,
|
||||||
|
PhrasePool,
|
||||||
|
PhraseEditor,
|
||||||
|
}
|
||||||
/// Represents the tracks and scenes of the composition.
|
/// Represents the tracks and scenes of the composition.
|
||||||
pub struct Arrangement<E: Engine> {
|
pub struct Arrangement<E: Engine> {
|
||||||
/// Name of arranger
|
/// Name of arranger
|
||||||
|
|
@ -91,14 +104,30 @@ pub enum ArrangementViewMode {
|
||||||
Vertical(usize),
|
Vertical(usize),
|
||||||
}
|
}
|
||||||
/// Arrangement, rendered vertically (session/grid mode).
|
/// Arrangement, rendered vertically (session/grid mode).
|
||||||
pub struct VerticalArranger<'a, E: Engine>(
|
pub struct VerticalArranger<'a, E: Engine>(pub &'a Arrangement<E>, pub usize);
|
||||||
pub &'a Arrangement<E>, pub usize
|
|
||||||
);
|
|
||||||
/// Arrangement, rendered horizontally (arrangement/track mode).
|
/// Arrangement, rendered horizontally (arrangement/track mode).
|
||||||
pub struct HorizontalArranger<'a, E: Engine>(
|
pub struct HorizontalArranger<'a, E: Engine>(pub &'a Arrangement<E>);
|
||||||
pub &'a Arrangement<E>
|
/// General methods for arranger
|
||||||
);
|
|
||||||
impl<E: Engine> Arranger<E> {
|
impl<E: Engine> Arranger<E> {
|
||||||
|
pub fn new (
|
||||||
|
transport: Option<Arc<RwLock<TransportToolbar<E>>>>,
|
||||||
|
arrangement: Arrangement<E>,
|
||||||
|
phrases: Arc<RwLock<PhrasePool<E>>>,
|
||||||
|
) -> Self {
|
||||||
|
let mut app = Self {
|
||||||
|
focus_cursor: (0, 1),
|
||||||
|
show_sequencer: Some(tek_core::Direction::Down),
|
||||||
|
editor: PhraseEditor::new(),
|
||||||
|
status: ArrangerStatusBar::Transport,
|
||||||
|
transport,
|
||||||
|
arrangement,
|
||||||
|
phrases,
|
||||||
|
phrases_split: 20,
|
||||||
|
arrangement_split: 20,
|
||||||
|
};
|
||||||
|
app.update_focus();
|
||||||
|
app
|
||||||
|
}
|
||||||
/// Toggle global play/pause
|
/// Toggle global play/pause
|
||||||
pub fn toggle_play (&mut self) -> Perhaps<bool> {
|
pub fn toggle_play (&mut self) -> Perhaps<bool> {
|
||||||
match self.transport {
|
match self.transport {
|
||||||
|
|
|
||||||
|
|
@ -51,16 +51,11 @@ impl ArrangerCli {
|
||||||
}
|
}
|
||||||
)?
|
)?
|
||||||
);
|
);
|
||||||
let mut app = Arranger {
|
Tui::run(Arc::new(RwLock::new(Arranger::new(
|
||||||
focus_cursor: (0, 1),
|
self.transport.then_some(transport),
|
||||||
transport: self.transport.then_some(transport),
|
|
||||||
show_sequencer: Some(tek_core::Direction::Down),
|
|
||||||
editor: PhraseEditor::new(),
|
|
||||||
arrangement,
|
arrangement,
|
||||||
phrases,
|
phrases,
|
||||||
};
|
))))?;
|
||||||
app.update_focus();
|
|
||||||
Tui::run(Arc::new(RwLock::new(app)))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,24 @@ impl Arranger<Tui> {
|
||||||
fn handle_focused (&mut self, from: &TuiInput) -> Perhaps<bool> {
|
fn handle_focused (&mut self, from: &TuiInput) -> Perhaps<bool> {
|
||||||
match self.focused() {
|
match self.focused() {
|
||||||
ArrangerFocus::Transport => self.transport.handle(from),
|
ArrangerFocus::Transport => self.transport.handle(from),
|
||||||
ArrangerFocus::PhrasePool => self.phrases.handle(from),
|
|
||||||
ArrangerFocus::PhraseEditor => self.editor.handle(from),
|
|
||||||
ArrangerFocus::Arrangement => self.handle_arrangement(from),
|
ArrangerFocus::Arrangement => self.handle_arrangement(from),
|
||||||
|
ArrangerFocus::PhrasePool => self.handle_pool(from),
|
||||||
|
ArrangerFocus::PhraseEditor => self.editor.handle(from),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Helper for phrase event passthru when phrase pool is focused
|
||||||
|
fn handle_pool (&mut self, from: &TuiInput) -> Perhaps<bool> {
|
||||||
|
match from.event() {
|
||||||
|
key!(KeyCode::Char('<')) => {
|
||||||
|
self.phrases_split = self.phrases_split.saturating_sub(1).max(12);
|
||||||
|
},
|
||||||
|
key!(KeyCode::Char('>')) => {
|
||||||
|
self.phrases_split = self.phrases_split + 1;
|
||||||
|
},
|
||||||
|
_ => return self.arrangement.handle(from)
|
||||||
|
}
|
||||||
|
Ok(Some(true))
|
||||||
|
}
|
||||||
/// Helper for phrase event passthru when arrangement is focused
|
/// Helper for phrase event passthru when arrangement is focused
|
||||||
fn handle_arrangement (&mut self, from: &TuiInput) -> Perhaps<bool> {
|
fn handle_arrangement (&mut self, from: &TuiInput) -> Perhaps<bool> {
|
||||||
let mut handle_phrase = ||{
|
let mut handle_phrase = ||{
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ impl Content for Arranger<Tui> {
|
||||||
add(&self.transport)?;
|
add(&self.transport)?;
|
||||||
let arrangement = &self.arrangement as &dyn Widget<Engine = Tui>;
|
let arrangement = &self.arrangement as &dyn Widget<Engine = Tui>;
|
||||||
if let Some(direction) = self.show_sequencer {
|
if let Some(direction) = self.show_sequencer {
|
||||||
add(&arrangement.split(direction, 20,
|
add(&arrangement.split(direction, self.arrangement_split,
|
||||||
self.phrases.clone().split(direction.ccw(), 20,
|
self.phrases.clone().split(direction.ccw(), self.phrases_split,
|
||||||
&self.editor as &dyn Widget<Engine = Tui>
|
&self.editor as &dyn Widget<Engine = Tui>
|
||||||
).min_y(20)
|
).min_y(self.arrangement_split)
|
||||||
).fill_y())
|
).fill_y())
|
||||||
} else {
|
} else {
|
||||||
add(&self.arrangement)
|
add(&self.arrangement)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,20 @@ pub struct Sequencer<E: Engine> {
|
||||||
}
|
}
|
||||||
/// Sections in the sequencer app that may be focused
|
/// Sections in the sequencer app that may be focused
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum SequencerFocus { Transport, PhrasePool, PhraseEditor }
|
pub enum SequencerFocus {
|
||||||
|
/// The transport (toolbar) is focused
|
||||||
|
Transport,
|
||||||
|
/// The phrase list (pool) is focused
|
||||||
|
PhrasePool,
|
||||||
|
/// The phrase editor (sequencer) is focused
|
||||||
|
PhraseEditor,
|
||||||
|
}
|
||||||
|
/// Status bar for sequencer app
|
||||||
|
pub enum SequencerStatusBar {
|
||||||
|
Transport,
|
||||||
|
PhrasePool,
|
||||||
|
PhraseEditor,
|
||||||
|
}
|
||||||
/// Contains all phrases in a project
|
/// Contains all phrases in a project
|
||||||
pub struct PhrasePool<E: Engine> {
|
pub struct PhrasePool<E: Engine> {
|
||||||
_engine: PhantomData<E>,
|
_engine: PhantomData<E>,
|
||||||
|
|
@ -35,7 +48,9 @@ pub struct PhrasePool<E: Engine> {
|
||||||
}
|
}
|
||||||
/// Modes for phrase pool
|
/// Modes for phrase pool
|
||||||
pub enum PhrasePoolMode {
|
pub enum PhrasePoolMode {
|
||||||
|
/// Renaming a pattern
|
||||||
Rename(usize, String),
|
Rename(usize, String),
|
||||||
|
/// Editing the length of a pattern
|
||||||
Length(usize, usize, PhraseLengthFocus),
|
Length(usize, usize, PhraseLengthFocus),
|
||||||
}
|
}
|
||||||
/// A MIDI sequence.
|
/// A MIDI sequence.
|
||||||
|
|
@ -328,11 +343,16 @@ impl<E: Engine> PhrasePlayer<E> {
|
||||||
self.overdub = !self.overdub;
|
self.overdub = !self.overdub;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Displays and edits phrase length
|
||||||
pub struct PhraseLength<E: Engine> {
|
pub struct PhraseLength<E: Engine> {
|
||||||
_engine: PhantomData<E>,
|
_engine: PhantomData<E>,
|
||||||
|
/// Pulses per beat (quaver)
|
||||||
pub ppq: usize,
|
pub ppq: usize,
|
||||||
|
/// Beats per bar
|
||||||
pub bpb: usize,
|
pub bpb: usize,
|
||||||
|
/// Length of phrase in pulses
|
||||||
pub pulses: usize,
|
pub pulses: usize,
|
||||||
|
/// Selected subdivision
|
||||||
pub focus: Option<PhraseLengthFocus>,
|
pub focus: Option<PhraseLengthFocus>,
|
||||||
}
|
}
|
||||||
impl<E: Engine> PhraseLength<E> {
|
impl<E: Engine> PhraseLength<E> {
|
||||||
|
|
@ -365,7 +385,14 @@ impl<E: Engine> PhraseLength<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Copy,Clone)]
|
#[derive(Copy,Clone)]
|
||||||
pub enum PhraseLengthFocus { Bar, Beat, Tick }
|
pub enum PhraseLengthFocus {
|
||||||
|
/// Editing the number of bars
|
||||||
|
Bar,
|
||||||
|
/// Editing the number of beats
|
||||||
|
Beat,
|
||||||
|
/// Editing the number of ticks
|
||||||
|
Tick,
|
||||||
|
}
|
||||||
impl PhraseLengthFocus {
|
impl PhraseLengthFocus {
|
||||||
pub fn next (&mut self) {
|
pub fn next (&mut self) {
|
||||||
*self = match self {
|
*self = match self {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue