Feat: refactoring codebase

This commit is contained in:
2026-02-16 16:00:57 +01:00
parent c749ed6f85
commit b60703aa16
49 changed files with 1852 additions and 1853 deletions

192
src/app/mod.rs Normal file
View File

@@ -0,0 +1,192 @@
mod clipboard;
mod dispatch;
mod editing;
mod navigation;
mod persistence;
mod scripting;
mod sequencer;
mod staging;
mod undo;
use arc_swap::ArcSwap;
use parking_lot::Mutex;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::collections::HashMap;
use std::sync::{Arc, LazyLock};
use cagire_ratatui::CompletionCandidate;
use crate::engine::LinkState;
use crate::midi::MidiState;
use crate::model::{self, Bank, Dictionary, Pattern, Rng, ScriptEngine, Variables};
use crate::page::Page;
use crate::state::{
undo::UndoHistory, AudioSettings, EditorContext, LiveKeyState, Metrics, Modal, MuteState,
OptionsState, PanelState, PatternField, PatternPropsField, PatternsNav, PlaybackState,
ProjectState, UiState,
};
const STEPS_PER_PAGE: usize = 32;
static COMPLETION_CANDIDATES: LazyLock<Vec<CompletionCandidate>> = LazyLock::new(|| {
model::WORDS
.iter()
.map(|w| CompletionCandidate {
name: w.name.to_string(),
signature: w.stack.to_string(),
description: w.desc.to_string(),
example: w.example.to_string(),
})
.collect()
});
pub struct App {
pub project_state: ProjectState,
pub ui: UiState,
pub playback: PlaybackState,
pub mute: MuteState,
pub page: Page,
pub editor_ctx: EditorContext,
pub patterns_nav: PatternsNav,
pub metrics: Metrics,
pub script_engine: ScriptEngine,
pub variables: Variables,
pub dict: Dictionary,
#[allow(dead_code)]
pub rng: Rng,
pub live_keys: Arc<LiveKeyState>,
pub clipboard: Option<arboard::Clipboard>,
pub copied_patterns: Option<Vec<Pattern>>,
pub copied_banks: Option<Vec<Bank>>,
pub undo: UndoHistory,
pub audio: AudioSettings,
pub options: OptionsState,
pub panel: PanelState,
pub midi: MidiState,
}
impl Default for App {
fn default() -> Self {
Self::new()
}
}
impl App {
pub fn new() -> Self {
let variables = Arc::new(ArcSwap::from_pointee(HashMap::new()));
let dict = Arc::new(Mutex::new(HashMap::new()));
let rng = Arc::new(Mutex::new(StdRng::seed_from_u64(0)));
let script_engine =
ScriptEngine::new(Arc::clone(&variables), Arc::clone(&dict), Arc::clone(&rng));
let live_keys = Arc::new(LiveKeyState::new());
Self {
project_state: ProjectState::default(),
ui: UiState::default(),
playback: PlaybackState::default(),
mute: MuteState::default(),
page: Page::default(),
editor_ctx: EditorContext::default(),
patterns_nav: PatternsNav::default(),
metrics: Metrics::default(),
variables,
dict,
rng,
live_keys,
script_engine,
clipboard: arboard::Clipboard::new().ok(),
copied_patterns: None,
copied_banks: None,
undo: UndoHistory::default(),
audio: AudioSettings::default(),
options: OptionsState::default(),
panel: PanelState::default(),
midi: MidiState::new(),
}
}
fn current_bank_pattern(&self) -> (usize, usize) {
(self.editor_ctx.bank, self.editor_ctx.pattern)
}
fn selected_steps(&self) -> Vec<usize> {
match self.editor_ctx.selection_range() {
Some(range) => range.collect(),
None => vec![self.editor_ctx.step],
}
}
pub fn mark_all_patterns_dirty(&mut self) {
self.project_state.mark_all_dirty();
}
pub fn toggle_playing(&mut self, link: &LinkState) {
let was_playing = self.playback.playing;
self.playback.toggle();
if !was_playing && self.playback.playing {
self.evaluate_prelude(link);
}
}
pub fn tempo_up(&self, link: &LinkState) {
let current = link.tempo();
link.set_tempo((current + 1.0).min(300.0));
}
pub fn tempo_down(&self, link: &LinkState) {
let current = link.tempo();
link.set_tempo((current - 1.0).max(20.0));
}
pub fn current_edit_pattern(&self) -> &Pattern {
let (bank, pattern) = self.current_bank_pattern();
self.project_state.project.pattern_at(bank, pattern)
}
pub fn open_pattern_modal(&mut self, field: PatternField) {
let current = match field {
PatternField::Length => self.current_edit_pattern().length.to_string(),
PatternField::Speed => self.current_edit_pattern().speed.label().to_string(),
};
self.ui.modal = Modal::SetPattern {
field,
input: current,
};
}
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 maybe_show_onboarding(&mut self) {
if self.ui.modal != Modal::None {
return;
}
let name = self.page.name();
if self.ui.onboarding_dismissed.iter().any(|d| d == name) {
return;
}
self.ui.modal = Modal::Onboarding { page: 0 };
}
}