modify pool width; wip: status bars

This commit is contained in:
🪞👃🪞 2024-10-18 23:25:01 +03:00
parent 4994e218f7
commit 0699b9d105
5 changed files with 104 additions and 40 deletions

View file

@ -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 {

View file

@ -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(())
} }
} }

View file

@ -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 = ||{

View file

@ -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)

View file

@ -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 {