This commit is contained in:
@@ -6,8 +6,8 @@ use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use crate::commands::AppCommand;
|
||||
use crate::page::Page;
|
||||
use crate::state::{
|
||||
DeviceKind, DictFocus, EditorTarget, EngineSection, HelpFocus, MinimapMode, Modal,
|
||||
OptionsFocus, PatternsColumn, SettingKind,
|
||||
DictFocus, EditorTarget, HelpFocus, MinimapMode, Modal,
|
||||
OptionsFocus, PatternsColumn,
|
||||
};
|
||||
use crate::views::{dict_view, engine_view, help_view, main_view, patterns_view, script_view};
|
||||
|
||||
@@ -288,31 +288,10 @@ fn handle_scroll(ctx: &mut InputContext, col: u16, row: u16, term: Rect, up: boo
|
||||
}
|
||||
}
|
||||
Page::Engine => {
|
||||
let [left_col, _, _] = engine_view::layout(body);
|
||||
if contains(left_col, col, row) {
|
||||
match ctx.app.audio.section {
|
||||
EngineSection::Devices => {
|
||||
if ctx.app.audio.device_kind == DeviceKind::Input {
|
||||
if up {
|
||||
ctx.dispatch(AppCommand::AudioInputListUp);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::AudioInputListDown(1));
|
||||
}
|
||||
} else if up {
|
||||
ctx.dispatch(AppCommand::AudioOutputListUp);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::AudioOutputListDown(1));
|
||||
}
|
||||
}
|
||||
EngineSection::Settings => {
|
||||
if up {
|
||||
ctx.dispatch(AppCommand::AudioSettingPrev);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::AudioSettingNext);
|
||||
}
|
||||
}
|
||||
EngineSection::Samples => {}
|
||||
}
|
||||
if up {
|
||||
ctx.dispatch(AppCommand::AudioPrevSection);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::AudioNextSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -944,132 +923,24 @@ fn handle_script_editor_mouse(
|
||||
ctx.app.script_editor.editor.move_cursor_to(text_row, text_col);
|
||||
}
|
||||
|
||||
fn handle_engine_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect, kind: ClickKind) {
|
||||
let [left_col, _, right_col] = engine_view::layout(area);
|
||||
|
||||
// Viz panel clicks (right column)
|
||||
if contains(right_col, col, row) {
|
||||
let [scope_area, _, lissajous_area, _, spectrum_area] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(right_col);
|
||||
|
||||
if contains(scope_area, col, row) {
|
||||
if kind == ClickKind::Double {
|
||||
ctx.dispatch(AppCommand::FlipScopeOrientation);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::CycleScopeMode);
|
||||
}
|
||||
} else if contains(lissajous_area, col, row) {
|
||||
ctx.dispatch(AppCommand::ToggleLissajousTrails);
|
||||
} else if contains(spectrum_area, col, row) {
|
||||
if kind == ClickKind::Double {
|
||||
ctx.dispatch(AppCommand::ToggleSpectrumPeaks);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::CycleSpectrumMode);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
fn handle_engine_click(ctx: &mut InputContext, col: u16, row: u16, area: Rect, _kind: ClickKind) {
|
||||
// In narrow mode the whole area is a single column, in wide mode it's a 55/45 split.
|
||||
// Either way, left-column clicks cycle through sections; right column is monitoring (non-interactive).
|
||||
let is_narrow = area.width < 100;
|
||||
let left_col = if is_narrow {
|
||||
area
|
||||
} else {
|
||||
let [left, _, _] = engine_view::layout(area);
|
||||
left
|
||||
};
|
||||
|
||||
if !contains(left_col, col, row) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replicate engine_view render_settings_section layout
|
||||
let inner = Rect {
|
||||
x: left_col.x + 1,
|
||||
y: left_col.y + 1,
|
||||
width: left_col.width.saturating_sub(2),
|
||||
height: left_col.height.saturating_sub(2),
|
||||
};
|
||||
let padded = Rect {
|
||||
x: inner.x + 1,
|
||||
y: inner.y + 1,
|
||||
width: inner.width.saturating_sub(2),
|
||||
height: inner.height.saturating_sub(1),
|
||||
};
|
||||
|
||||
if row < padded.y || row >= padded.y + padded.height {
|
||||
return;
|
||||
}
|
||||
|
||||
let devices_lines = engine_view::devices_section_height(ctx.app) as usize;
|
||||
let settings_lines: usize = 8;
|
||||
let samples_lines: usize = 6;
|
||||
let total_lines = devices_lines + 1 + settings_lines + 1 + samples_lines;
|
||||
let max_visible = padded.height as usize;
|
||||
|
||||
let (focus_start, focus_height) = match ctx.app.audio.section {
|
||||
EngineSection::Devices => (0, devices_lines),
|
||||
EngineSection::Settings => (devices_lines + 1, settings_lines),
|
||||
EngineSection::Samples => (devices_lines + 1 + settings_lines + 1, samples_lines),
|
||||
};
|
||||
|
||||
let scroll_offset = if total_lines <= max_visible {
|
||||
0
|
||||
} else {
|
||||
let focus_end = focus_start + focus_height;
|
||||
if focus_end <= max_visible {
|
||||
0
|
||||
} else {
|
||||
focus_start.min(total_lines.saturating_sub(max_visible))
|
||||
}
|
||||
};
|
||||
|
||||
let relative_y = (row - padded.y) as usize;
|
||||
let abs_line = scroll_offset + relative_y;
|
||||
|
||||
let devices_end = devices_lines;
|
||||
let settings_start = devices_lines + 1;
|
||||
let settings_end = settings_start + settings_lines;
|
||||
let samples_start = settings_end + 1;
|
||||
|
||||
if abs_line < devices_end {
|
||||
ctx.dispatch(AppCommand::AudioSetSection(EngineSection::Devices));
|
||||
// Determine output vs input sub-column
|
||||
let [output_col, _sep, input_col] = Layout::horizontal([
|
||||
Constraint::Percentage(48),
|
||||
Constraint::Length(3),
|
||||
Constraint::Percentage(48),
|
||||
])
|
||||
.areas(padded);
|
||||
if contains(input_col, col, row) {
|
||||
ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Input));
|
||||
} else if contains(output_col, col, row) {
|
||||
ctx.dispatch(AppCommand::SetDeviceKind(DeviceKind::Output));
|
||||
}
|
||||
} else if abs_line >= settings_start && abs_line < settings_end {
|
||||
ctx.dispatch(AppCommand::AudioSetSection(EngineSection::Settings));
|
||||
// Settings section: 2 header lines + 6 table rows
|
||||
// Rows 0-3 are adjustable (Channels, Buffer, Voices, Nudge)
|
||||
let row_in_section = abs_line - settings_start;
|
||||
if row_in_section >= 2 {
|
||||
let table_row = row_in_section - 2;
|
||||
let setting = match table_row {
|
||||
0 => Some(SettingKind::Channels),
|
||||
1 => Some(SettingKind::BufferSize),
|
||||
2 => Some(SettingKind::Polyphony),
|
||||
3 => Some(SettingKind::Nudge),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(kind) = setting {
|
||||
ctx.app.audio.setting_kind = kind;
|
||||
// Table columns: [Length(14), Fill(1)] — value starts at padded.x + 14
|
||||
let value_x = padded.x + 14;
|
||||
if col >= value_x {
|
||||
let right = col >= value_x + 4;
|
||||
super::engine_page::cycle_engine_setting(ctx, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if abs_line >= samples_start {
|
||||
ctx.dispatch(AppCommand::AudioSetSection(EngineSection::Samples));
|
||||
}
|
||||
// Simple: cycle section on click. The complex per-line hit-testing is fragile
|
||||
// given the scrollable layout. Tab/keyboard is the primary navigation.
|
||||
ctx.dispatch(AppCommand::AudioNextSection);
|
||||
}
|
||||
|
||||
// --- Modal ---
|
||||
|
||||
Reference in New Issue
Block a user