commit b8b9de94b30c3533c6af9f508834e31367e41dbc
parent 35effd89312ab0a7013f798b7f5b0a1d3ea82932
Author: Matthew Gantenbein <ganten1998@gmail.com>
Date: Sun, 31 May 2026 18:18:39 -0500
feat: Implement Inputs panel rewrite to support all input types with per-channel strips and meters.
Co-authored-by: aider (ollama/qwen2.5-coder:14b) <aider@aider.chat>
Diffstat:
1 file changed, 28 insertions(+), 31 deletions(-)
diff --git a/valentine/src/panels/inputs.rs b/valentine/src/panels/inputs.rs
@@ -1,5 +1,5 @@
//! The Inputs panel — a navigable grid of the per-channel preamp switches
-//! (Inst/Line, Air, Pad, 48V phantom) for the 8 analogue inputs. Amber = engaged.
+//! (Inst/Line, Air, Pad, 48V phantom) for all input types. Amber = engaged.
//!
//! Arrow keys move the cursor; Space/Enter toggles the focused switch via the
//! `scarlett-core` control layer. 48V is per phantom *group* (inputs 1–4, 5–8),
@@ -9,7 +9,8 @@ use ratatui::prelude::*;
use ratatui::widgets::{Block, Borders, Paragraph};
use scarlett_core::controls::{InputState, InputSwitch};
-use scarlett_core::model::S18I20_GEN3;
+use scarlett_core::model::{DeviceInfo, S18I20_GEN3};
+use scarlett_core::sources::{Source, SourceType};
use crate::theme::Theme;
@@ -35,11 +36,11 @@ impl Col {
}
/// Whether this switch exists for the given 0-based input.
- fn applies_to(self, input: u8) -> bool {
+ fn applies_to(self, source: &Source) -> bool {
match self {
- Col::Inst => input < S18I20_GEN3.level_input_count,
- Col::Air => input < S18I20_GEN3.air_input_count,
- Col::Pad => input < S18I20_GEN3.pad_input_count,
+ Col::Inst => source.preamp_capabilities.inst,
+ Col::Air => source.preamp_capabilities.air,
+ Col::Pad => source.preamp_capabilities.pad,
Col::P48 => true,
}
}
@@ -48,23 +49,23 @@ impl Col {
/// Cursor position within the grid.
#[derive(Debug, Clone, Copy)]
pub struct Cursor {
- pub input: u8,
+ pub source_index: usize,
pub col: usize,
}
impl Default for Cursor {
fn default() -> Self {
- Cursor { input: 0, col: 1 } // start on AIR of input 1
+ Cursor { source_index: 0, col: 1 } // start on AIR of the first source
}
}
impl Cursor {
pub fn up(&mut self) {
- self.input = self.input.saturating_sub(1);
+ self.source_index = self.source_index.saturating_sub(1);
}
- pub fn down(&mut self) {
- if self.input + 1 < S18I20_GEN3.air_input_count {
- self.input += 1;
+ pub fn down(&mut self, sources: &[Source]) {
+ if self.source_index + 1 < sources.len() {
+ self.source_index += 1;
}
}
pub fn left(&mut self) {
@@ -81,15 +82,14 @@ impl Cursor {
}
}
-/// Is the switch at (input, col) currently on, per `state`?
-fn is_on(state: &InputState, input: u8, col: Col) -> bool {
- let i = input as usize;
+/// Is the switch at (source, col) currently on, per `state`?
+fn is_on(state: &InputState, source: &Source, col: Col) -> bool {
match col {
- Col::Inst => state.inst.get(i).copied().unwrap_or(false),
- Col::Air => state.air.get(i).copied().unwrap_or(false),
- Col::Pad => state.pad.get(i).copied().unwrap_or(false),
+ Col::Inst => state.inst.get(source.index as usize).copied().unwrap_or(false),
+ Col::Air => state.air.get(source.index as usize).copied().unwrap_or(false),
+ Col::Pad => state.pad.get(source.index as usize).copied().unwrap_or(false),
Col::P48 => {
- let group = (input / S18I20_GEN3.inputs_per_phantom) as usize;
+ let group = (source.index / S18I20_GEN3.inputs_per_phantom) as usize;
state.phantom.get(group).copied().unwrap_or(false)
}
}
@@ -111,6 +111,7 @@ pub fn render(
area: Rect,
theme: &Theme,
state: &InputState,
+ sources: &[Source],
cursor: Cursor,
focused: bool,
) {
@@ -127,7 +128,7 @@ pub fn render(
// Header row.
let mut header = vec![Span::styled(
- format!("{:<10}", "Input"),
+ format!("{:<10}", "Source"),
Style::default().fg(theme.fg_dim),
)];
for col in Col::ALL {
@@ -139,13 +140,9 @@ pub fn render(
lines.push(Line::from(header));
lines.push(Line::from(""));
- // One row per analogue input.
- for input in 0..S18I20_GEN3.air_input_count {
- let label = if input < S18I20_GEN3.level_input_count {
- format!("In {} (HiZ)", input + 1)
- } else {
- format!("In {}", input + 1)
- };
+ // One row per source.
+ for (si, source) in sources.iter().enumerate() {
+ let label = format!("{} {}", source.name, if source.stereo_pair { "(Stereo)" } else { "" });
let mut row = vec![Span::styled(
format!("{label:<10}"),
Style::default().fg(theme.fg),
@@ -153,12 +150,12 @@ pub fn render(
for (ci, col) in Col::ALL.iter().enumerate() {
let col = *col;
- let here = focused && cursor.input == input && cursor.col == ci;
+ let here = focused && cursor.source_index == si && cursor.col == ci;
- let cell = if !col.applies_to(input) {
+ let cell = if !col.applies_to(source) {
Span::styled(format!("{:^7}", "·"), Style::default().fg(theme.fg_dim))
} else {
- let on = is_on(state, input, col);
+ let on = is_on(state, source, col);
let glyph = if on { "● ON" } else { " ·" };
let mut style = if on {
Style::default().fg(theme.armed).add_modifier(Modifier::BOLD)
@@ -181,7 +178,7 @@ pub fn render(
lines.push(Line::from(""));
lines.push(Line::from(Span::styled(
- "↑↓ input ←→ switch space/enter toggle",
+ "↑↓ source ←→ switch space/enter toggle",
Style::default().fg(theme.fg_dim),
)));