Feat: more mouse support
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user