Refactoring
This commit is contained in:
340
seq/src/app.rs
340
seq/src/app.rs
@@ -1,49 +1,43 @@
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::config::{MAX_BANKS, MAX_PATTERNS, MAX_SLOTS};
|
||||
use crate::commands::AppCommand;
|
||||
use crate::config::MAX_SLOTS;
|
||||
use crate::file;
|
||||
use crate::link::LinkState;
|
||||
use crate::model::{Pattern, Project};
|
||||
use crate::model::Pattern;
|
||||
use crate::page::Page;
|
||||
use crate::script::{Rng, ScriptEngine, StepContext, Variables};
|
||||
use crate::sequencer::{SequencerSnapshot, SlotChange};
|
||||
use crate::services::pattern_editor;
|
||||
use crate::state::{
|
||||
AudioSettings, EditorContext, Focus, Metrics, Modal, PatternField, PatternsViewLevel,
|
||||
PlaybackState, ProjectState, UiState,
|
||||
};
|
||||
use crate::views::doc_view;
|
||||
|
||||
pub struct App {
|
||||
pub playing: bool,
|
||||
pub project_state: ProjectState,
|
||||
pub ui: UiState,
|
||||
pub playback: PlaybackState,
|
||||
|
||||
pub project: Project,
|
||||
pub page: Page,
|
||||
pub editor_ctx: EditorContext,
|
||||
|
||||
pub patterns_view_level: PatternsViewLevel,
|
||||
pub patterns_cursor: usize,
|
||||
|
||||
pub queued_changes: Vec<SlotChange>,
|
||||
|
||||
pub metrics: Metrics,
|
||||
pub sample_pool_mb: f32,
|
||||
pub script_engine: ScriptEngine,
|
||||
pub variables: Variables,
|
||||
pub rng: Rng,
|
||||
pub file_path: Option<PathBuf>,
|
||||
pub status_message: Option<String>,
|
||||
pub flash_until: Option<Instant>,
|
||||
pub modal: Modal,
|
||||
pub clipboard: Option<arboard::Clipboard>,
|
||||
pub doc_topic: usize,
|
||||
pub doc_scroll: usize,
|
||||
|
||||
pub audio: AudioSettings,
|
||||
pub dirty_patterns: HashSet<(usize, usize)>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -53,32 +47,24 @@ impl App {
|
||||
let script_engine = ScriptEngine::new(Arc::clone(&variables), Arc::clone(&rng));
|
||||
|
||||
Self {
|
||||
playing: true,
|
||||
project_state: ProjectState::default(),
|
||||
ui: UiState::default(),
|
||||
playback: PlaybackState::default(),
|
||||
|
||||
project: Project::default(),
|
||||
page: Page::default(),
|
||||
editor_ctx: EditorContext::default(),
|
||||
|
||||
patterns_view_level: PatternsViewLevel::default(),
|
||||
patterns_cursor: 0,
|
||||
|
||||
queued_changes: Vec::new(),
|
||||
|
||||
metrics: Metrics::default(),
|
||||
sample_pool_mb: 0.0,
|
||||
variables,
|
||||
rng,
|
||||
script_engine,
|
||||
file_path: None,
|
||||
status_message: None,
|
||||
flash_until: None,
|
||||
modal: Modal::None,
|
||||
clipboard: arboard::Clipboard::new().ok(),
|
||||
doc_topic: 0,
|
||||
doc_scroll: 0,
|
||||
|
||||
audio: AudioSettings::default(),
|
||||
dirty_patterns: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,20 +72,12 @@ impl App {
|
||||
(self.editor_ctx.bank, self.editor_ctx.pattern)
|
||||
}
|
||||
|
||||
fn mark_current_dirty(&mut self) {
|
||||
self.dirty_patterns.insert(self.current_bank_pattern());
|
||||
}
|
||||
|
||||
pub fn mark_all_patterns_dirty(&mut self) {
|
||||
for bank in 0..MAX_BANKS {
|
||||
for pattern in 0..MAX_PATTERNS {
|
||||
self.dirty_patterns.insert((bank, pattern));
|
||||
}
|
||||
}
|
||||
self.project_state.mark_all_dirty();
|
||||
}
|
||||
|
||||
pub fn toggle_playing(&mut self) {
|
||||
self.playing = !self.playing;
|
||||
self.playback.toggle();
|
||||
}
|
||||
|
||||
pub fn tempo_up(&self, link: &LinkState) {
|
||||
@@ -128,7 +106,7 @@ impl App {
|
||||
|
||||
pub fn current_edit_pattern(&self) -> &Pattern {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
self.project.pattern_at(bank, pattern)
|
||||
self.project_state.project.pattern_at(bank, pattern)
|
||||
}
|
||||
|
||||
pub fn next_step(&mut self) {
|
||||
@@ -177,44 +155,53 @@ impl App {
|
||||
|
||||
pub fn toggle_step(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::toggle_step(&mut self.project, bank, pattern, self.editor_ctx.step);
|
||||
self.mark_current_dirty();
|
||||
let change = pattern_editor::toggle_step(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
self.editor_ctx.step,
|
||||
);
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
pub fn length_increase(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::increase_length(&mut self.project, bank, pattern);
|
||||
self.mark_current_dirty();
|
||||
let (change, _) =
|
||||
pattern_editor::increase_length(&mut self.project_state.project, bank, pattern);
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
pub fn length_decrease(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::decrease_length(&mut self.project, bank, pattern);
|
||||
let new_len = pattern_editor::get_length(&self.project, bank, pattern);
|
||||
let (change, new_len) =
|
||||
pattern_editor::decrease_length(&mut self.project_state.project, bank, pattern);
|
||||
if self.editor_ctx.step >= new_len {
|
||||
self.editor_ctx.step = new_len - 1;
|
||||
self.load_step_to_editor();
|
||||
}
|
||||
self.mark_current_dirty();
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
pub fn speed_increase(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::increase_speed(&mut self.project, bank, pattern);
|
||||
self.mark_current_dirty();
|
||||
let change = pattern_editor::increase_speed(&mut self.project_state.project, bank, pattern);
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
pub fn speed_decrease(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::decrease_speed(&mut self.project, bank, pattern);
|
||||
self.mark_current_dirty();
|
||||
let change = pattern_editor::decrease_speed(&mut self.project_state.project, bank, pattern);
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
fn load_step_to_editor(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
if let Some(script) =
|
||||
pattern_editor::get_step_script(&self.project, bank, pattern, self.editor_ctx.step)
|
||||
{
|
||||
if let Some(script) = pattern_editor::get_step_script(
|
||||
&self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
self.editor_ctx.step,
|
||||
) {
|
||||
let lines: Vec<String> = if script.is_empty() {
|
||||
vec![String::new()]
|
||||
} else {
|
||||
@@ -227,25 +214,27 @@ impl App {
|
||||
pub fn save_editor_to_step(&mut self) {
|
||||
let text = self.editor_ctx.text.lines().join("\n");
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::set_step_script(
|
||||
&mut self.project,
|
||||
let change = pattern_editor::set_step_script(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
self.editor_ctx.step,
|
||||
text,
|
||||
);
|
||||
self.mark_current_dirty();
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
pub fn compile_current_step(&mut self, link: &LinkState) {
|
||||
let step_idx = self.editor_ctx.step;
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
|
||||
let script = pattern_editor::get_step_script(&self.project, bank, pattern, step_idx)
|
||||
.unwrap_or_default();
|
||||
let script =
|
||||
pattern_editor::get_step_script(&self.project_state.project, bank, pattern, step_idx)
|
||||
.unwrap_or_default();
|
||||
|
||||
if script.trim().is_empty() {
|
||||
if let Some(step) = self
|
||||
.project_state
|
||||
.project
|
||||
.pattern_at_mut(bank, pattern)
|
||||
.step_mut(step_idx)
|
||||
@@ -268,24 +257,25 @@ impl App {
|
||||
match self.script_engine.evaluate(&script, &ctx) {
|
||||
Ok(cmd) => {
|
||||
if let Some(step) = self
|
||||
.project_state
|
||||
.project
|
||||
.pattern_at_mut(bank, pattern)
|
||||
.step_mut(step_idx)
|
||||
{
|
||||
step.command = Some(cmd);
|
||||
}
|
||||
self.status_message = Some("Script compiled".to_string());
|
||||
self.flash_until = Some(Instant::now() + std::time::Duration::from_millis(150));
|
||||
self.ui.flash("Script compiled", 150);
|
||||
}
|
||||
Err(e) => {
|
||||
if let Some(step) = self
|
||||
.project_state
|
||||
.project
|
||||
.pattern_at_mut(bank, pattern)
|
||||
.step_mut(step_idx)
|
||||
{
|
||||
step.command = None;
|
||||
}
|
||||
self.status_message = Some(format!("Script error: {e}"));
|
||||
self.ui.set_status(format!("Script error: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -295,11 +285,17 @@ impl App {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
|
||||
for step_idx in 0..pattern_len {
|
||||
let script = pattern_editor::get_step_script(&self.project, bank, pattern, step_idx)
|
||||
.unwrap_or_default();
|
||||
let script = pattern_editor::get_step_script(
|
||||
&self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
step_idx,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
if script.trim().is_empty() {
|
||||
if let Some(step) = self
|
||||
.project_state
|
||||
.project
|
||||
.pattern_at_mut(bank, pattern)
|
||||
.step_mut(step_idx)
|
||||
@@ -321,6 +317,7 @@ impl App {
|
||||
|
||||
if let Ok(cmd) = self.script_engine.evaluate(&script, &ctx) {
|
||||
if let Some(step) = self
|
||||
.project_state
|
||||
.project
|
||||
.pattern_at_mut(bank, pattern)
|
||||
.step_mut(step_idx)
|
||||
@@ -337,7 +334,7 @@ impl App {
|
||||
pattern: usize,
|
||||
snapshot: &SequencerSnapshot,
|
||||
) -> Option<bool> {
|
||||
self.queued_changes.iter().find_map(|c| match c {
|
||||
self.playback.queued_changes.iter().find_map(|c| match c {
|
||||
SlotChange::Add {
|
||||
slot: _,
|
||||
bank: b,
|
||||
@@ -369,7 +366,7 @@ impl App {
|
||||
}
|
||||
});
|
||||
|
||||
let pending = self.queued_changes.iter().position(|c| match c {
|
||||
let pending = self.playback.queued_changes.iter().position(|c| match c {
|
||||
SlotChange::Add {
|
||||
bank: b,
|
||||
pattern: p,
|
||||
@@ -382,16 +379,17 @@ impl App {
|
||||
});
|
||||
|
||||
if let Some(idx) = pending {
|
||||
self.queued_changes.remove(idx);
|
||||
self.status_message = Some(format!(
|
||||
self.playback.queued_changes.remove(idx);
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} change cancelled",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
} else if let Some(slot_idx) = playing_slot {
|
||||
self.queued_changes
|
||||
self.playback
|
||||
.queued_changes
|
||||
.push(SlotChange::Remove { slot: slot_idx });
|
||||
self.status_message = Some(format!(
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} queued to stop",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
@@ -399,18 +397,18 @@ impl App {
|
||||
} else {
|
||||
let free_slot = (0..MAX_SLOTS).find(|&i| !snapshot.slot_data[i].active);
|
||||
if let Some(slot_idx) = free_slot {
|
||||
self.queued_changes.push(SlotChange::Add {
|
||||
self.playback.queued_changes.push(SlotChange::Add {
|
||||
slot: slot_idx,
|
||||
bank,
|
||||
pattern,
|
||||
});
|
||||
self.status_message = Some(format!(
|
||||
self.ui.set_status(format!(
|
||||
"B{:02}:P{:02} queued to play",
|
||||
bank + 1,
|
||||
pattern + 1
|
||||
));
|
||||
} else {
|
||||
self.status_message = Some("All slots occupied".to_string());
|
||||
self.ui.set_status("All slots occupied".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,13 +428,13 @@ impl App {
|
||||
|
||||
pub fn save(&mut self, path: PathBuf) {
|
||||
self.save_editor_to_step();
|
||||
match file::save(&self.project, &path) {
|
||||
match file::save(&self.project_state.project, &path) {
|
||||
Ok(()) => {
|
||||
self.status_message = Some(format!("Saved: {}", path.display()));
|
||||
self.file_path = Some(path);
|
||||
self.ui.set_status(format!("Saved: {}", path.display()));
|
||||
self.project_state.file_path = Some(path);
|
||||
}
|
||||
Err(e) => {
|
||||
self.status_message = Some(format!("Save error: {e}"));
|
||||
self.ui.set_status(format!("Save error: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,39 +442,33 @@ impl App {
|
||||
pub fn load(&mut self, path: PathBuf, link: &LinkState) {
|
||||
match file::load(&path) {
|
||||
Ok(project) => {
|
||||
self.project = project;
|
||||
self.project_state.project = project;
|
||||
self.editor_ctx.step = 0;
|
||||
self.load_step_to_editor();
|
||||
self.compile_all_steps(link);
|
||||
self.mark_all_patterns_dirty();
|
||||
self.status_message = Some(format!("Loaded: {}", path.display()));
|
||||
self.file_path = Some(path);
|
||||
self.ui.set_status(format!("Loaded: {}", path.display()));
|
||||
self.project_state.file_path = Some(path);
|
||||
}
|
||||
Err(e) => {
|
||||
self.status_message = Some(format!("Load error: {e}"));
|
||||
self.ui.set_status(format!("Load error: {e}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_status(&mut self) {
|
||||
self.status_message = None;
|
||||
}
|
||||
|
||||
pub fn is_flashing(&self) -> bool {
|
||||
self.flash_until
|
||||
.map(|t| Instant::now() < t)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn copy_step(&mut self) {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
let script =
|
||||
pattern_editor::get_step_script(&self.project, bank, pattern, self.editor_ctx.step);
|
||||
let script = pattern_editor::get_step_script(
|
||||
&self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
self.editor_ctx.step,
|
||||
);
|
||||
|
||||
if let Some(script) = script {
|
||||
if let Some(clip) = &mut self.clipboard {
|
||||
if clip.set_text(&script).is_ok() {
|
||||
self.status_message = Some("Copied".to_string());
|
||||
self.ui.set_status("Copied".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,14 +482,14 @@ impl App {
|
||||
|
||||
if let Some(text) = text {
|
||||
let (bank, pattern) = self.current_bank_pattern();
|
||||
pattern_editor::set_step_script(
|
||||
&mut self.project,
|
||||
let change = pattern_editor::set_step_script(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
self.editor_ctx.step,
|
||||
text,
|
||||
);
|
||||
self.mark_current_dirty();
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
self.load_step_to_editor();
|
||||
self.compile_current_step(link);
|
||||
}
|
||||
@@ -508,9 +500,167 @@ impl App {
|
||||
PatternField::Length => self.current_edit_pattern().length.to_string(),
|
||||
PatternField::Speed => self.current_edit_pattern().speed.label().to_string(),
|
||||
};
|
||||
self.modal = Modal::SetPattern {
|
||||
self.ui.modal = Modal::SetPattern {
|
||||
field,
|
||||
input: current,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dispatch(&mut self, cmd: AppCommand, link: &LinkState, snapshot: &SequencerSnapshot) {
|
||||
match cmd {
|
||||
// Playback
|
||||
AppCommand::TogglePlaying => self.toggle_playing(),
|
||||
AppCommand::TempoUp => self.tempo_up(link),
|
||||
AppCommand::TempoDown => self.tempo_down(link),
|
||||
|
||||
// Navigation
|
||||
AppCommand::NextStep => self.next_step(),
|
||||
AppCommand::PrevStep => self.prev_step(),
|
||||
AppCommand::StepUp => self.step_up(),
|
||||
AppCommand::StepDown => self.step_down(),
|
||||
AppCommand::ToggleFocus => self.toggle_focus(link),
|
||||
AppCommand::SelectEditBank(bank) => self.select_edit_bank(bank),
|
||||
AppCommand::SelectEditPattern(pattern) => self.select_edit_pattern(pattern),
|
||||
|
||||
// Pattern editing
|
||||
AppCommand::ToggleStep => self.toggle_step(),
|
||||
AppCommand::LengthIncrease => self.length_increase(),
|
||||
AppCommand::LengthDecrease => self.length_decrease(),
|
||||
AppCommand::SpeedIncrease => self.speed_increase(),
|
||||
AppCommand::SpeedDecrease => self.speed_decrease(),
|
||||
AppCommand::SetLength {
|
||||
bank,
|
||||
pattern,
|
||||
length,
|
||||
} => {
|
||||
let (change, new_len) = pattern_editor::set_length(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
length,
|
||||
);
|
||||
if self.editor_ctx.bank == bank
|
||||
&& self.editor_ctx.pattern == pattern
|
||||
&& self.editor_ctx.step >= new_len
|
||||
{
|
||||
self.editor_ctx.step = new_len - 1;
|
||||
}
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
AppCommand::SetSpeed {
|
||||
bank,
|
||||
pattern,
|
||||
speed,
|
||||
} => {
|
||||
let change = pattern_editor::set_speed(
|
||||
&mut self.project_state.project,
|
||||
bank,
|
||||
pattern,
|
||||
speed,
|
||||
);
|
||||
self.project_state.mark_dirty(change.bank, change.pattern);
|
||||
}
|
||||
|
||||
// Script editing
|
||||
AppCommand::SaveEditorToStep => self.save_editor_to_step(),
|
||||
AppCommand::CompileCurrentStep => self.compile_current_step(link),
|
||||
AppCommand::CompileAllSteps => self.compile_all_steps(link),
|
||||
|
||||
// Clipboard
|
||||
AppCommand::CopyStep => self.copy_step(),
|
||||
AppCommand::PasteStep => self.paste_step(link),
|
||||
|
||||
// Pattern playback
|
||||
AppCommand::QueueSlotChange(change) => {
|
||||
self.playback.queued_changes.push(change);
|
||||
}
|
||||
AppCommand::TogglePatternPlayback { bank, pattern } => {
|
||||
self.toggle_pattern_playback(bank, pattern, snapshot);
|
||||
}
|
||||
|
||||
// Project
|
||||
AppCommand::RenameBank { bank, name } => {
|
||||
self.project_state.project.banks[bank].name = name;
|
||||
}
|
||||
AppCommand::RenamePattern {
|
||||
bank,
|
||||
pattern,
|
||||
name,
|
||||
} => {
|
||||
self.project_state.project.banks[bank].patterns[pattern].name = name;
|
||||
}
|
||||
AppCommand::Save(path) => self.save(path),
|
||||
AppCommand::Load(path) => self.load(path, link),
|
||||
|
||||
// UI
|
||||
AppCommand::SetStatus(msg) => self.ui.set_status(msg),
|
||||
AppCommand::ClearStatus => self.ui.clear_status(),
|
||||
AppCommand::Flash {
|
||||
message,
|
||||
duration_ms,
|
||||
} => self.ui.flash(&message, duration_ms),
|
||||
AppCommand::OpenModal(modal) => self.ui.modal = modal,
|
||||
AppCommand::CloseModal => self.ui.modal = Modal::None,
|
||||
AppCommand::OpenPatternModal(field) => self.open_pattern_modal(field),
|
||||
|
||||
// Page navigation
|
||||
AppCommand::PageLeft => self.page.left(),
|
||||
AppCommand::PageRight => self.page.right(),
|
||||
AppCommand::PageUp => self.page.up(),
|
||||
AppCommand::PageDown => self.page.down(),
|
||||
|
||||
// Doc navigation
|
||||
AppCommand::DocNextTopic => {
|
||||
self.ui.doc_topic = (self.ui.doc_topic + 1) % doc_view::topic_count();
|
||||
self.ui.doc_scroll = 0;
|
||||
}
|
||||
AppCommand::DocPrevTopic => {
|
||||
let count = doc_view::topic_count();
|
||||
self.ui.doc_topic = (self.ui.doc_topic + count - 1) % count;
|
||||
self.ui.doc_scroll = 0;
|
||||
}
|
||||
AppCommand::DocScrollDown(n) => {
|
||||
self.ui.doc_scroll = self.ui.doc_scroll.saturating_add(n);
|
||||
}
|
||||
AppCommand::DocScrollUp(n) => {
|
||||
self.ui.doc_scroll = self.ui.doc_scroll.saturating_sub(n);
|
||||
}
|
||||
|
||||
// Patterns view
|
||||
AppCommand::PatternsCursorLeft => {
|
||||
self.patterns_cursor = (self.patterns_cursor + 15) % 16;
|
||||
}
|
||||
AppCommand::PatternsCursorRight => {
|
||||
self.patterns_cursor = (self.patterns_cursor + 1) % 16;
|
||||
}
|
||||
AppCommand::PatternsCursorUp => {
|
||||
self.patterns_cursor = (self.patterns_cursor + 12) % 16;
|
||||
}
|
||||
AppCommand::PatternsCursorDown => {
|
||||
self.patterns_cursor = (self.patterns_cursor + 4) % 16;
|
||||
}
|
||||
AppCommand::PatternsEnter => match self.patterns_view_level {
|
||||
PatternsViewLevel::Banks => {
|
||||
let bank = self.patterns_cursor;
|
||||
self.patterns_view_level = PatternsViewLevel::Patterns { bank };
|
||||
self.patterns_cursor = 0;
|
||||
}
|
||||
PatternsViewLevel::Patterns { bank } => {
|
||||
let pattern = self.patterns_cursor;
|
||||
self.select_edit_bank(bank);
|
||||
self.select_edit_pattern(pattern);
|
||||
self.patterns_view_level = PatternsViewLevel::Banks;
|
||||
self.patterns_cursor = 0;
|
||||
self.page.down();
|
||||
}
|
||||
},
|
||||
AppCommand::PatternsBack => match self.patterns_view_level {
|
||||
PatternsViewLevel::Banks => self.page.down(),
|
||||
PatternsViewLevel::Patterns { .. } => {
|
||||
self.patterns_view_level = PatternsViewLevel::Banks;
|
||||
self.patterns_cursor = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user