diff --git a/src/mouse.rs b/src/mouse.rs index 6504dc3..67b44d4 100644 --- a/src/mouse.rs +++ b/src/mouse.rs @@ -415,8 +415,7 @@ fn hit_test_synth_knobs(col: u16, row: u16, knobs_area: Rect) -> Option Option 0 { - let rel_x = (col - row_groups[2].x) as usize; - let idx = (rel_x / col_width).min(3); - return match idx { - 0 => Some(SynthControlField::LfoWaveform), - 1 => Some(SynthControlField::LfoDivision), - 2 => Some(SynthControlField::LfoDepth), - _ => Some(SynthControlField::LfoDest), - }; - } - return Some(SynthControlField::LfoWaveform); - } + let cols = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(50), // AMP + Constraint::Percentage(50), // LFO + ]) + .split(row_groups[2]); - // ── Row group 3: AMP ───────────────────────────────────────────────── - if hit_test_area(col, row, row_groups[3]) { - let amp_w = row_groups[3].width.min(40); - let amp_body = Rect::new( - row_groups[3].x, - row_groups[3].y + 1, - amp_w, - row_groups[3].height.saturating_sub(1), - ); - if hit_test_area(col, row, amp_body) { - let col_width = amp_w as usize / 4; + if hit_test_area(col, row, cols[0]) { + // AMP: skip header row + let amp_body = Rect::new( + cols[0].x, + cols[0].y + 1, + cols[0].width, + cols[0].height.saturating_sub(1), + ); + if hit_test_area(col, row, amp_body) { + let col_width = cols[0].width as usize / 4; + if col_width > 0 { + let rel_x = (col - amp_body.x) as usize; + let idx = (rel_x / col_width).min(3); + return match idx { + 0 => Some(SynthControlField::Volume), + 1 => Some(SynthControlField::SendReverb), + 2 => Some(SynthControlField::SendDelay), + _ => Some(SynthControlField::Volume), // Sat not a synth field + }; + } + } + return Some(SynthControlField::Volume); + } else if hit_test_area(col, row, cols[1]) { + // LFO + let col_width = cols[1].width as usize / 4; if col_width > 0 { - let rel_x = (col - amp_body.x) as usize; - let idx = (rel_x / col_width).min(2); + let rel_x = (col - cols[1].x) as usize; + let idx = (rel_x / col_width).min(3); return match idx { - 0 => Some(SynthControlField::Volume), - 1 => Some(SynthControlField::SendReverb), - _ => Some(SynthControlField::SendDelay), + 0 => Some(SynthControlField::LfoWaveform), + 1 => Some(SynthControlField::LfoDivision), + 2 => Some(SynthControlField::LfoDepth), + _ => Some(SynthControlField::LfoDest), }; } + return Some(SynthControlField::LfoWaveform); } - return Some(SynthControlField::Volume); } None diff --git a/src/ui/layout.rs b/src/ui/layout.rs index 2b7cd78..c601651 100644 --- a/src/ui/layout.rs +++ b/src/ui/layout.rs @@ -17,8 +17,8 @@ pub const KNOBS_HEIGHT: u16 = 9; /// Alias used by the new dual-synth layout. pub const DRUM_KNOBS_HEIGHT: u16 = KNOBS_HEIGHT; -/// Height of the synth knobs panel (OSC 8 + ENV/FILT 8 + LFO 3 + AMP 7 + 2 border = 30). -pub const SYNTH_KNOBS_HEIGHT: u16 = 30; +/// Height of the synth knobs panel (OSC 8 + ENV/FILT 8 + AMP+LFO 7 + 2 border = 25). +pub const SYNTH_KNOBS_HEIGHT: u16 = 25; /// Height of the synth step row (2 border + header + spacer + step row + spacer = 6). pub const SYNTH_GRID_HEIGHT: u16 = 6; diff --git a/src/ui/synth_knobs.rs b/src/ui/synth_knobs.rs index 97b2f65..0212621 100644 --- a/src/ui/synth_knobs.rs +++ b/src/ui/synth_knobs.rs @@ -98,14 +98,13 @@ pub fn render_synth_knobs(f: &mut Frame, area: Rect, app: &App, synth_id: SynthI let params = &pattern.params; let sel = ui.ctrl_field; - // Split inner into 4 row groups: OSC (8), ENV+FILT (8), LFO (3), AMP (remaining) + // Split inner into 3 row groups: OSC (8), ENV+FILT (8), AMP+LFO (remaining) let row_groups = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(8), // Row group 1: OSC1 + OSC2 Constraint::Length(8), // Row group 2: ENV1 + ENV2 + FILT - Constraint::Length(3), // Row group 3: LFO - Constraint::Min(7), // Row group 4: AMP + Constraint::Min(7), // Row group 3: AMP (left) + LFO (right) ]) .split(inner); @@ -204,30 +203,35 @@ pub fn render_synth_knobs(f: &mut Frame, area: Rect, app: &App, synth_id: SynthI render_adsr_bars(f, filt_split[1], params, FILT_ENV_ADSR, sel, focused); } - // ── Row group 3: LFO ──────────────────────────────────────────────── + // ── Row group 3: AMP (left) + LFO (right) ───────────────────────── { - render_section_header(f, row_groups[2], "LFO"); - let lfo_body = Rect::new( - row_groups[2].x, - row_groups[2].y + 1, - row_groups[2].width, - row_groups[2].height.saturating_sub(1), - ); - render_lfo_row(f, lfo_body, params, sel, focused); - } - - // ── Row group 4: AMP ──────────────────────────────────────────────── - { - render_section_header(f, row_groups[3], "AMP"); + let cols = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(50), // AMP + Constraint::Percentage(50), // LFO + ]) + .split(row_groups[2]); + // AMP section + render_section_header(f, cols[0], "AMP"); let amp_body = Rect::new( - row_groups[3].x, - row_groups[3].y + 1, - row_groups[3].width.min(40), - row_groups[3].height.saturating_sub(1), + cols[0].x, + cols[0].y + 1, + cols[0].width, + cols[0].height.saturating_sub(1), ); - render_amp_group(f, amp_body, params, app.effect_params.synth_saturator_drive, sel, focused); + + // LFO section + render_section_header(f, cols[1], "LFO"); + let lfo_body = Rect::new( + cols[1].x, + cols[1].y + 1, + cols[1].width, + cols[1].height.saturating_sub(1), + ); + render_lfo_row(f, lfo_body, params, sel, focused); } }