1use ratatui::layout::Rect;
4use ratatui::style::{Color, Modifier, Style};
5use ratatui::widgets::{Block, Borders, List, ListItem};
6use ratatui::Frame;
7
8use super::app::AppState;
9use crate::audio::engine::EngineHandle;
10
11pub fn render(f: &mut Frame, area: Rect, engine: &EngineHandle, app: &AppState) {
12 let tracks = engine.tracks.lock();
13 let items: Vec<ListItem> = tracks
14 .iter()
15 .enumerate()
16 .map(|(i, t)| {
17 let snap = t.params.snapshot();
18 let marker = if i == app.selected_track { "▶" } else { " " };
19 let status = if snap.muted { "·" } else { "●" };
20 let gain_bar = bar(snap.gain * (if snap.muted { 0.0 } else { 1.0 }), 8);
21 let label = t.kind.label();
25 let line = format!(
26 "{marker} {status} {label:<10} {bar} {f:>5.0}Hz",
27 bar = gain_bar,
28 f = snap.freq,
29 );
30 let style = if i == app.selected_track {
31 Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)
32 } else if snap.muted {
33 Style::default().fg(Color::DarkGray)
34 } else {
35 Style::default().fg(Color::White)
36 };
37 ListItem::new(line).style(style)
38 })
39 .collect();
40
41 let list = List::new(items).block(
42 Block::default()
43 .borders(Borders::ALL)
44 .title(" tracks ")
45 .title_style(Style::default().add_modifier(Modifier::BOLD)),
46 );
47 f.render_widget(list, area);
48}
49
50fn bar(v: f32, width: usize) -> String {
51 let filled = (v.clamp(0.0, 1.0) * width as f32).round() as usize;
52 let empty = width.saturating_sub(filled);
53 format!("[{}{}]", "█".repeat(filled), "·".repeat(empty))
54}