So much better
This commit is contained in:
131
src/app.rs
131
src/app.rs
@@ -16,7 +16,8 @@ use crate::services::pattern_editor;
|
||||
use crate::settings::Settings;
|
||||
use crate::state::{
|
||||
AudioSettings, DictFocus, EditorContext, FlashKind, Focus, LiveKeyState, Metrics, Modal,
|
||||
OptionsState, PanelState, PatternField, PatternsNav, PlaybackState, ProjectState, UiState,
|
||||
OptionsState, PanelState, PatternField, PatternPropsField, PatternsNav, PlaybackState,
|
||||
ProjectState, StagedChange, UiState,
|
||||
};
|
||||
use crate::views::{dict_view, help_view};
|
||||
|
||||
@@ -399,48 +400,76 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_pattern_playback(
|
||||
pub fn stage_pattern_toggle(
|
||||
&mut self,
|
||||
bank: usize,
|
||||
pattern: usize,
|
||||
snapshot: &SequencerSnapshot,
|
||||
) {
|
||||
let is_playing = snapshot.is_playing(bank, pattern);
|
||||
let pattern_data = self.project_state.project.pattern_at(bank, pattern);
|
||||
|
||||
let pending = self
|
||||
let existing = self
|
||||
.playback
|
||||
.queued_changes
|
||||
.staged_changes
|
||||
.iter()
|
||||
.position(|c| c.pattern_id().bank == bank && c.pattern_id().pattern == pattern);
|
||||
.position(|c| {
|
||||
c.change.pattern_id().bank == bank && c.change.pattern_id().pattern == pattern
|
||||
});
|
||||
|
||||
if let Some(idx) = pending {
|
||||
self.playback.queued_changes.remove(idx);
|
||||
if let Some(idx) = existing {
|
||||
self.playback.staged_changes.remove(idx);
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} change cancelled",
|
||||
"B{:02}:P{:02} unstaged",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
} else if is_playing {
|
||||
self.playback
|
||||
.queued_changes
|
||||
.push(PatternChange::Stop { bank, pattern });
|
||||
self.playback.staged_changes.push(StagedChange {
|
||||
change: PatternChange::Stop { bank, pattern },
|
||||
quantization: pattern_data.quantization,
|
||||
sync_mode: pattern_data.sync_mode,
|
||||
});
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} queued to stop",
|
||||
"B{:02}:P{:02} staged to stop",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
} else {
|
||||
self.playback
|
||||
.queued_changes
|
||||
.push(PatternChange::Start { bank, pattern });
|
||||
self.playback.staged_changes.push(StagedChange {
|
||||
change: PatternChange::Start { bank, pattern },
|
||||
quantization: pattern_data.quantization,
|
||||
sync_mode: pattern_data.sync_mode,
|
||||
});
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} queued to play",
|
||||
"B{:02}:P{:02} staged to play",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_staged_changes(&mut self) {
|
||||
if self.playback.staged_changes.is_empty() {
|
||||
self.ui.set_status("No changes to commit".to_string());
|
||||
return;
|
||||
}
|
||||
let count = self.playback.staged_changes.len();
|
||||
self.playback
|
||||
.queued_changes
|
||||
.append(&mut self.playback.staged_changes);
|
||||
self.ui.set_status(format!("Committed {count} changes"));
|
||||
}
|
||||
|
||||
pub fn clear_staged_changes(&mut self) {
|
||||
if self.playback.staged_changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
let count = self.playback.staged_changes.len();
|
||||
self.playback.staged_changes.clear();
|
||||
self.ui.set_status(format!("Cleared {count} staged changes"));
|
||||
}
|
||||
|
||||
pub fn select_edit_pattern(&mut self, pattern: usize) {
|
||||
self.editor_ctx.pattern = pattern;
|
||||
self.editor_ctx.step = 0;
|
||||
@@ -724,6 +753,20 @@ impl App {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn open_pattern_props_modal(&mut self, bank: usize, pattern: usize) {
|
||||
let pat = self.project_state.project.pattern_at(bank, pattern);
|
||||
self.ui.modal = Modal::PatternProps {
|
||||
bank,
|
||||
pattern,
|
||||
field: PatternPropsField::default(),
|
||||
name: pat.name.clone().unwrap_or_default(),
|
||||
length: pat.length.to_string(),
|
||||
speed: pat.speed,
|
||||
quantization: pat.quantization,
|
||||
sync_mode: pat.sync_mode,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dispatch(&mut self, cmd: AppCommand, link: &LinkState, snapshot: &SequencerSnapshot) {
|
||||
match cmd {
|
||||
// Playback
|
||||
@@ -815,12 +858,15 @@ impl App {
|
||||
AppCommand::LinkPasteStep => self.link_paste_step(),
|
||||
AppCommand::HardenStep => self.harden_step(),
|
||||
|
||||
// Pattern playback
|
||||
AppCommand::QueuePatternChange(change) => {
|
||||
self.playback.queued_changes.push(change);
|
||||
// Pattern playback (staging)
|
||||
AppCommand::StagePatternToggle { bank, pattern } => {
|
||||
self.stage_pattern_toggle(bank, pattern, snapshot);
|
||||
}
|
||||
AppCommand::TogglePatternPlayback { bank, pattern } => {
|
||||
self.toggle_pattern_playback(bank, pattern, snapshot);
|
||||
AppCommand::CommitStagedChanges => {
|
||||
self.commit_staged_changes();
|
||||
}
|
||||
AppCommand::ClearStagedChanges => {
|
||||
self.clear_staged_changes();
|
||||
}
|
||||
|
||||
// Project
|
||||
@@ -859,6 +905,28 @@ impl App {
|
||||
}
|
||||
AppCommand::CloseModal => self.ui.modal = Modal::None,
|
||||
AppCommand::OpenPatternModal(field) => self.open_pattern_modal(field),
|
||||
AppCommand::OpenPatternPropsModal { bank, pattern } => {
|
||||
self.open_pattern_props_modal(bank, pattern);
|
||||
}
|
||||
AppCommand::SetPatternProps {
|
||||
bank,
|
||||
pattern,
|
||||
name,
|
||||
length,
|
||||
speed,
|
||||
quantization,
|
||||
sync_mode,
|
||||
} => {
|
||||
let pat = self.project_state.project.pattern_at_mut(bank, pattern);
|
||||
pat.name = name;
|
||||
if let Some(len) = length {
|
||||
pat.set_length(len);
|
||||
}
|
||||
pat.speed = speed;
|
||||
pat.quantization = quantization;
|
||||
pat.sync_mode = sync_mode;
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
}
|
||||
|
||||
// Page navigation
|
||||
AppCommand::PageLeft => self.page.left(),
|
||||
@@ -953,19 +1021,28 @@ impl App {
|
||||
AppCommand::PatternsTogglePlay => {
|
||||
let bank = self.patterns_nav.selected_bank();
|
||||
let pattern = self.patterns_nav.selected_pattern();
|
||||
self.toggle_pattern_playback(bank, pattern, snapshot);
|
||||
self.stage_pattern_toggle(bank, pattern, snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush_queued_changes(&mut self, cmd_tx: &Sender<SeqCommand>) {
|
||||
for change in self.playback.queued_changes.drain(..) {
|
||||
match change {
|
||||
for staged in self.playback.queued_changes.drain(..) {
|
||||
match staged.change {
|
||||
PatternChange::Start { bank, pattern } => {
|
||||
let _ = cmd_tx.send(SeqCommand::PatternStart { bank, pattern });
|
||||
let _ = cmd_tx.send(SeqCommand::PatternStart {
|
||||
bank,
|
||||
pattern,
|
||||
quantization: staged.quantization,
|
||||
sync_mode: staged.sync_mode,
|
||||
});
|
||||
}
|
||||
PatternChange::Stop { bank, pattern } => {
|
||||
let _ = cmd_tx.send(SeqCommand::PatternStop { bank, pattern });
|
||||
let _ = cmd_tx.send(SeqCommand::PatternStop {
|
||||
bank,
|
||||
pattern,
|
||||
quantization: staged.quantization,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -987,6 +1064,8 @@ impl App {
|
||||
source: s.source,
|
||||
})
|
||||
.collect(),
|
||||
quantization: pat.quantization,
|
||||
sync_mode: pat.sync_mode,
|
||||
};
|
||||
let _ = cmd_tx.send(SeqCommand::PatternUpdate {
|
||||
bank,
|
||||
|
||||
Reference in New Issue
Block a user