Feat: more mouse support

This commit is contained in:
2026-02-28 02:26:33 +01:00
parent 25a5c77344
commit 0a186f774c
4 changed files with 59 additions and 10 deletions

4
Cargo.lock generated
View File

@@ -1809,8 +1809,8 @@ dependencies = [
[[package]] [[package]]
name = "doux" name = "doux"
version = "0.0.4" version = "0.0.5"
source = "git+https://github.com/sova-org/doux#ba475601a448f36d4755eb1fdcaa629987485892" source = "git+https://github.com/sova-org/doux#886702b4fe937d26ed681a2f6d7626d26d6890d0"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"clap", "clap",

View File

@@ -394,6 +394,7 @@ impl eframe::App for CagireDesktop {
self.app.flush_queued_changes(&sequencer.cmd_tx); self.app.flush_queued_changes(&sequencer.cmd_tx);
self.app.flush_dirty_patterns(&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() { while let Ok(midi_cmd) = self.midi_rx.try_recv() {
match midi_cmd { match midi_cmd {

View File

@@ -1070,7 +1070,7 @@ impl SequencerState {
} }
let script_frontier = if self.script_frontier < 0.0 { let script_frontier = if self.script_frontier < 0.0 {
frontier.max(0.0) frontier
} else { } else {
self.script_frontier self.script_frontier
}; };

View File

@@ -6,8 +6,8 @@ use ratatui::layout::{Constraint, Layout, Rect};
use crate::commands::AppCommand; use crate::commands::AppCommand;
use crate::page::Page; use crate::page::Page;
use crate::state::{ use crate::state::{
DeviceKind, DictFocus, EngineSection, HelpFocus, MinimapMode, Modal, OptionsFocus, DeviceKind, DictFocus, EditorTarget, EngineSection, HelpFocus, MinimapMode, Modal,
PatternsColumn, SettingKind, OptionsFocus, PatternsColumn, SettingKind,
}; };
use crate::views::{dict_view, engine_view, help_view, main_view, patterns_view, script_view}; 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) { fn editor_modal_rect(term: Rect) -> Rect {
// Reconstruct editor area (mirrors render_modal_editor / ModalFrame::render_centered)
let width = (term.width * 80 / 100).max(40); let width = (term.width * 80 / 100).max(40);
let height = (term.height * 60 / 100).max(10); let height = (term.height * 60 / 100).max(10);
let modal_w = width.min(term.width.saturating_sub(4)); let modal_w = width.min(term.width.saturating_sub(4));
let modal_h = height.min(term.height.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 mx = term.x + (term.width.saturating_sub(modal_w)) / 2;
let my = term.y + (term.height.saturating_sub(modal_h)) / 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 // inner = area inside 1-cell border
let inner_x = mx + 1; let inner_x = mx + 1;
let inner_y = my + 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; 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) { if !matches!(ctx.app.ui.modal, Modal::None) {
return; 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) { fn handle_modal_click(ctx: &mut InputContext, col: u16, row: u16, term: Rect) {
match &ctx.app.ui.modal { match &ctx.app.ui.modal {
Modal::Editor => { Modal::Editor => {
let modal_area = editor_modal_rect(term);
if contains(modal_area, col, row) {
handle_editor_mouse(ctx, col, row, term, false); 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 { .. } => { Modal::Confirm { .. } => {
handle_confirm_click(ctx, col, row, term); handle_confirm_click(ctx, col, row, term);
} }
Modal::KeybindingsHelp { .. } => { Modal::KeybindingsHelp { .. } => {
// Click outside keybindings help to dismiss
let padded = padded(term); let padded = padded(term);
let width = (padded.width * 80 / 100).clamp(60, 100); let width = (padded.width * 80 / 100).clamp(60, 100);
let height = (padded.height * 80 / 100).max(15); 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);
}
} }
} }
} }