diff --git a/Cargo.lock b/Cargo.lock index 31c6659..94b70a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1809,8 +1809,8 @@ dependencies = [ [[package]] name = "doux" -version = "0.0.4" -source = "git+https://github.com/sova-org/doux#ba475601a448f36d4755eb1fdcaa629987485892" +version = "0.0.5" +source = "git+https://github.com/sova-org/doux#886702b4fe937d26ed681a2f6d7626d26d6890d0" dependencies = [ "arc-swap", "clap", diff --git a/src/bin/desktop/main.rs b/src/bin/desktop/main.rs index 12035eb..cf7e648 100644 --- a/src/bin/desktop/main.rs +++ b/src/bin/desktop/main.rs @@ -394,6 +394,7 @@ impl eframe::App for CagireDesktop { self.app.flush_queued_changes(&sequencer.cmd_tx); self.app.flush_dirty_patterns(&sequencer.cmd_tx); + self.app.flush_dirty_script(&sequencer.cmd_tx); while let Ok(midi_cmd) = self.midi_rx.try_recv() { match midi_cmd { diff --git a/src/engine/sequencer.rs b/src/engine/sequencer.rs index ddd6a77..58acf25 100644 --- a/src/engine/sequencer.rs +++ b/src/engine/sequencer.rs @@ -1070,7 +1070,7 @@ impl SequencerState { } let script_frontier = if self.script_frontier < 0.0 { - frontier.max(0.0) + frontier } else { self.script_frontier }; diff --git a/src/input/mouse.rs b/src/input/mouse.rs index 657ab62..a95b7c3 100644 --- a/src/input/mouse.rs +++ b/src/input/mouse.rs @@ -6,8 +6,8 @@ use ratatui::layout::{Constraint, Layout, Rect}; use crate::commands::AppCommand; use crate::page::Page; use crate::state::{ - DeviceKind, DictFocus, EngineSection, HelpFocus, MinimapMode, Modal, OptionsFocus, - PatternsColumn, SettingKind, + DeviceKind, DictFocus, EditorTarget, EngineSection, HelpFocus, MinimapMode, Modal, + OptionsFocus, PatternsColumn, SettingKind, }; use crate::views::{dict_view, engine_view, help_view, main_view, patterns_view, script_view}; @@ -94,14 +94,22 @@ fn handle_editor_drag(ctx: &mut InputContext, col: u16, row: u16, term: Rect) { } } -fn handle_editor_mouse(ctx: &mut InputContext, col: u16, row: u16, term: Rect, dragging: bool) { - // Reconstruct editor area (mirrors render_modal_editor / ModalFrame::render_centered) +fn editor_modal_rect(term: Rect) -> Rect { let width = (term.width * 80 / 100).max(40); let height = (term.height * 60 / 100).max(10); let modal_w = width.min(term.width.saturating_sub(4)); let modal_h = height.min(term.height.saturating_sub(4)); let mx = term.x + (term.width.saturating_sub(modal_w)) / 2; let my = term.y + (term.height.saturating_sub(modal_h)) / 2; + Rect::new(mx, my, modal_w, modal_h) +} + +fn handle_editor_mouse(ctx: &mut InputContext, col: u16, row: u16, term: Rect, dragging: bool) { + let modal = editor_modal_rect(term); + let mx = modal.x; + let my = modal.y; + let modal_w = modal.width; + let modal_h = modal.height; // inner = area inside 1-cell border let inner_x = mx + 1; let inner_y = my + 1; @@ -180,6 +188,18 @@ fn handle_scroll(ctx: &mut InputContext, col: u16, row: u16, term: Rect, up: boo return; } + if matches!(ctx.app.ui.modal, Modal::Editor) { + use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; + let code = if up { KeyCode::Up } else { KeyCode::Down }; + for _ in 0..3 { + ctx.app + .editor_ctx + .editor + .input(KeyEvent::new(code, KeyModifiers::empty())); + } + return; + } + if !matches!(ctx.app.ui.modal, Modal::None) { return; } @@ -1057,13 +1077,28 @@ fn handle_engine_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect, k fn handle_modal_click(ctx: &mut InputContext, col: u16, row: u16, term: Rect) { match &ctx.app.ui.modal { Modal::Editor => { - handle_editor_mouse(ctx, col, row, term, false); + let modal_area = editor_modal_rect(term); + if contains(modal_area, col, row) { + handle_editor_mouse(ctx, col, row, term, false); + } else { + match ctx.app.editor_ctx.target { + EditorTarget::Step => { + ctx.dispatch(AppCommand::SaveEditorToStep); + ctx.dispatch(AppCommand::CompileCurrentStep); + } + EditorTarget::Prelude => { + ctx.dispatch(AppCommand::SavePrelude); + ctx.dispatch(AppCommand::EvaluatePrelude); + ctx.dispatch(AppCommand::ClosePreludeEditor); + } + } + ctx.dispatch(AppCommand::CloseModal); + } } Modal::Confirm { .. } => { handle_confirm_click(ctx, col, row, term); } Modal::KeybindingsHelp { .. } => { - // Click outside keybindings help to dismiss let padded = padded(term); let width = (padded.width * 80 / 100).clamp(60, 100); let height = (padded.height * 80 / 100).max(15); @@ -1073,7 +1108,20 @@ fn handle_modal_click(ctx: &mut InputContext, col: u16, row: u16, term: Rect) { } } _ => { - // For other modals, don't dismiss on click (they have their own input) + let (w, h) = match &ctx.app.ui.modal { + Modal::PatternProps { .. } => (50, 18), + Modal::EuclideanDistribution { .. } => (50, 11), + Modal::Onboarding { .. } => (57, 20), + Modal::FileBrowser(_) | Modal::AddSamplePath(_) => (60, 18), + Modal::Rename { .. } => (40, 5), + Modal::SetPattern { .. } | Modal::SetScript { .. } => (45, 5), + Modal::SetTempo(_) | Modal::JumpToStep(_) => (30, 5), + _ => return, + }; + let modal_area = centered_rect(term, w, h); + if !contains(modal_area, col, row) { + ctx.dispatch(AppCommand::CloseModal); + } } } }