This commit is contained in:
@@ -15,14 +15,16 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn paste_pattern(&mut self, bank: usize, pattern: usize) {
|
||||
if let Some(src) = self.copied_patterns.as_ref().and_then(|v| v.first()) {
|
||||
let src = src.clone();
|
||||
clipboard::paste_pattern(&mut self.project_state.project, bank, pattern, &src);
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
if self.editor_ctx.bank == bank && self.editor_ctx.pattern == pattern {
|
||||
self.load_step_to_editor();
|
||||
if let Some(patterns) = self.copied_patterns.take() {
|
||||
if let Some(src) = patterns.first() {
|
||||
clipboard::paste_pattern(&mut self.project_state.project, bank, pattern, src);
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
if self.editor_ctx.bank == bank && self.editor_ctx.pattern == pattern {
|
||||
self.load_step_to_editor();
|
||||
}
|
||||
self.ui.flash("Pattern pasted", 150, FlashKind::Success);
|
||||
}
|
||||
self.ui.flash("Pattern pasted", 150, FlashKind::Success);
|
||||
self.copied_patterns = Some(patterns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +43,14 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn paste_patterns(&mut self, bank: usize, start: usize) {
|
||||
if let Some(sources) = self.copied_patterns.clone() {
|
||||
if let Some(sources) = self.copied_patterns.take() {
|
||||
let count = clipboard::paste_patterns(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
start,
|
||||
&sources,
|
||||
);
|
||||
self.copied_patterns = Some(sources);
|
||||
for i in 0..count {
|
||||
self.project_state.mark_dirty(bank, start + i);
|
||||
}
|
||||
@@ -111,17 +114,19 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn paste_bank(&mut self, bank: usize) {
|
||||
if let Some(src) = self.copied_banks.as_ref().and_then(|v| v.first()) {
|
||||
let src = src.clone();
|
||||
let pat_count =
|
||||
clipboard::paste_bank(&mut self.project_state.project, bank, &src);
|
||||
for pattern in 0..pat_count {
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
if let Some(banks) = self.copied_banks.take() {
|
||||
if let Some(src) = banks.first() {
|
||||
let pat_count =
|
||||
clipboard::paste_bank(&mut self.project_state.project, bank, src);
|
||||
for pattern in 0..pat_count {
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
}
|
||||
if self.editor_ctx.bank == bank {
|
||||
self.load_step_to_editor();
|
||||
}
|
||||
self.ui.flash("Bank pasted", 150, FlashKind::Success);
|
||||
}
|
||||
if self.editor_ctx.bank == bank {
|
||||
self.load_step_to_editor();
|
||||
}
|
||||
self.ui.flash("Bank pasted", 150, FlashKind::Success);
|
||||
self.copied_banks = Some(banks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,12 +144,13 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn paste_banks(&mut self, start: usize) {
|
||||
if let Some(sources) = self.copied_banks.clone() {
|
||||
if let Some(sources) = self.copied_banks.take() {
|
||||
let count = clipboard::paste_banks(
|
||||
&mut self.project_state.project,
|
||||
start,
|
||||
&sources,
|
||||
);
|
||||
self.copied_banks = Some(sources);
|
||||
for i in 0..count {
|
||||
let bank = start + i;
|
||||
for pattern in 0..model::MAX_PATTERNS {
|
||||
@@ -184,23 +190,24 @@ impl App {
|
||||
pub fn copy_steps(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
let indices = self.selected_steps();
|
||||
let (copied, scripts) = clipboard::copy_steps(
|
||||
let copied = clipboard::copy_steps(
|
||||
&self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
&indices,
|
||||
);
|
||||
let count = copied.steps.len();
|
||||
self.editor_ctx.copied_steps = Some(copied);
|
||||
if let Some(clip) = &mut self.clipboard {
|
||||
let _ = clip.set_text(scripts.join("\n"));
|
||||
let text: String = copied.steps.iter().map(|s| s.script.as_str()).collect::<Vec<_>>().join("\n");
|
||||
let _ = clip.set_text(text);
|
||||
}
|
||||
self.editor_ctx.copied_steps = Some(copied);
|
||||
self.ui
|
||||
.flash(&format!("Copied {count} steps"), 150, FlashKind::Info);
|
||||
}
|
||||
|
||||
pub fn paste_steps(&mut self, link: &crate::engine::LinkState) {
|
||||
let Some(copied) = self.editor_ctx.copied_steps.clone() else {
|
||||
let Some(copied) = self.editor_ctx.copied_steps.take() else {
|
||||
self.ui.set_status("Nothing copied".to_string());
|
||||
return;
|
||||
};
|
||||
@@ -213,6 +220,7 @@ impl App {
|
||||
cursor,
|
||||
&copied,
|
||||
);
|
||||
self.editor_ctx.copied_steps = Some(copied);
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
self.load_step_to_editor();
|
||||
for &target in &result.compile_targets {
|
||||
@@ -230,19 +238,21 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn link_paste_steps(&mut self) {
|
||||
let Some(copied) = self.editor_ctx.copied_steps.clone() else {
|
||||
let Some(copied) = self.editor_ctx.copied_steps.take() else {
|
||||
self.ui.set_status("Nothing copied".to_string());
|
||||
return;
|
||||
};
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
let cursor = self.editor_ctx.step;
|
||||
match clipboard::link_paste_steps(
|
||||
let result = clipboard::link_paste_steps(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
cursor,
|
||||
&copied,
|
||||
) {
|
||||
);
|
||||
self.editor_ctx.copied_steps = Some(copied);
|
||||
match result {
|
||||
None => {
|
||||
self.ui
|
||||
.set_status("Can only link within same pattern".to_string());
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
//! Routes `AppCommand` variants to the appropriate `App` methods.
|
||||
|
||||
use crate::commands::AppCommand;
|
||||
use crate::engine::{LinkState, SequencerSnapshot};
|
||||
use crate::model::bp_label;
|
||||
use crate::services::{dict_nav, euclidean, help_nav, pattern_editor};
|
||||
use crate::state::{undo::UndoEntry, FlashKind, Modal, StagedPropChange};
|
||||
|
||||
@@ -193,11 +196,8 @@ impl App {
|
||||
follow_up,
|
||||
},
|
||||
);
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} props staged",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
self.ui
|
||||
.set_status(format!("{} props staged", bp_label(bank, pattern)));
|
||||
}
|
||||
|
||||
// Page navigation
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! Application state: owns the project, editor context, and all UI/playback state.
|
||||
|
||||
mod clipboard;
|
||||
mod dispatch;
|
||||
mod editing;
|
||||
@@ -54,8 +56,8 @@ pub struct App {
|
||||
pub script_engine: ScriptEngine,
|
||||
pub variables: Variables,
|
||||
pub dict: Dictionary,
|
||||
#[allow(dead_code)]
|
||||
pub rng: Rng,
|
||||
// Held to keep the Arc alive (shared with ScriptEngine).
|
||||
pub _rng: Rng,
|
||||
pub live_keys: Arc<LiveKeyState>,
|
||||
pub clipboard: Option<arboard::Clipboard>,
|
||||
pub copied_patterns: Option<Vec<Pattern>>,
|
||||
@@ -108,7 +110,7 @@ impl App {
|
||||
metrics: Metrics::default(),
|
||||
variables,
|
||||
dict,
|
||||
rng,
|
||||
_rng: rng,
|
||||
live_keys,
|
||||
script_engine,
|
||||
clipboard: arboard::Clipboard::new().ok(),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::engine::{PatternChange, SequencerSnapshot};
|
||||
use crate::model::bp_label;
|
||||
use crate::state::StagedChange;
|
||||
|
||||
use super::App;
|
||||
@@ -20,29 +21,23 @@ impl App {
|
||||
if let Some(idx) = existing {
|
||||
self.playback.staged_changes.remove(idx);
|
||||
self.ui
|
||||
.set_status(format!("B{:02}:P{:02} unstaged", bank + 1, pattern + 1));
|
||||
.set_status(format!("{} unstaged", bp_label(bank, pattern)));
|
||||
} else if is_playing {
|
||||
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} staged to stop",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
self.ui
|
||||
.set_status(format!("{} staged to stop", bp_label(bank, pattern)));
|
||||
} else {
|
||||
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} staged to play",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
self.ui
|
||||
.set_status(format!("{} staged to play", bp_label(bank, pattern)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,15 +64,19 @@ impl App {
|
||||
let cursor = (self.editor_ctx.bank, self.editor_ctx.pattern, self.editor_ctx.step);
|
||||
let reverse_scope = match entry.scope {
|
||||
UndoScope::Pattern { bank, pattern, data } => {
|
||||
let current = self.project_state.project.pattern_at(bank, pattern).clone();
|
||||
*self.project_state.project.pattern_at_mut(bank, pattern) = data;
|
||||
let current = std::mem::replace(
|
||||
self.project_state.project.pattern_at_mut(bank, pattern),
|
||||
data,
|
||||
);
|
||||
self.project_state.mark_dirty(bank, pattern);
|
||||
UndoScope::Pattern { bank, pattern, data: current }
|
||||
}
|
||||
UndoScope::Bank { bank, data } => {
|
||||
let current = self.project_state.project.banks[bank].clone();
|
||||
let current = std::mem::replace(
|
||||
&mut self.project_state.project.banks[bank],
|
||||
data,
|
||||
);
|
||||
let pat_count = current.patterns.len();
|
||||
self.project_state.project.banks[bank] = data;
|
||||
for p in 0..pat_count {
|
||||
self.project_state.mark_dirty(bank, p);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user