seq continues
This commit is contained in:
194
seq/src/views/patterns_view.rs
Normal file
194
seq/src/views/patterns_view.rs
Normal file
@@ -0,0 +1,194 @@
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Paragraph};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::{App, PatternsViewLevel};
|
||||
|
||||
pub fn render(frame: &mut Frame, app: &App, area: Rect) {
|
||||
match app.patterns_view_level {
|
||||
PatternsViewLevel::Banks => render_banks(frame, app, area),
|
||||
PatternsViewLevel::Patterns { bank } => render_patterns(frame, app, area, bank),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_banks(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::new().fg(Color::Rgb(100, 160, 180)))
|
||||
.title("Banks");
|
||||
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
if inner.width < 50 {
|
||||
let msg = Paragraph::new("Terminal too narrow")
|
||||
.alignment(Alignment::Center)
|
||||
.style(Style::new().fg(Color::Rgb(120, 125, 135)));
|
||||
frame.render_widget(msg, inner);
|
||||
return;
|
||||
}
|
||||
|
||||
let banks_with_playback: Vec<usize> = app
|
||||
.slot_data
|
||||
.iter()
|
||||
.filter(|(active, _, _)| *active)
|
||||
.map(|(_, bank, _)| *bank)
|
||||
.collect();
|
||||
|
||||
let bank_names: Vec<Option<&str>> = app
|
||||
.project
|
||||
.banks
|
||||
.iter()
|
||||
.map(|b| b.name.as_deref())
|
||||
.collect();
|
||||
|
||||
render_grid(frame, inner, app.patterns_cursor, app.edit_bank, &banks_with_playback, &bank_names);
|
||||
}
|
||||
|
||||
fn render_patterns(frame: &mut Frame, app: &App, area: Rect, bank: usize) {
|
||||
let bank_name = app.project.banks[bank].name.as_deref();
|
||||
let title_text = match bank_name {
|
||||
Some(name) => format!("{name} › Patterns"),
|
||||
None => format!("Bank {:02} › Patterns", bank + 1),
|
||||
};
|
||||
let title = Line::from(vec![
|
||||
Span::raw(title_text),
|
||||
Span::styled(" [Esc]←", Style::new().fg(Color::Rgb(120, 125, 135))),
|
||||
]);
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::new().fg(Color::Rgb(100, 160, 180)))
|
||||
.title(title);
|
||||
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
if inner.width < 50 {
|
||||
let msg = Paragraph::new("Terminal too narrow")
|
||||
.alignment(Alignment::Center)
|
||||
.style(Style::new().fg(Color::Rgb(120, 125, 135)));
|
||||
frame.render_widget(msg, inner);
|
||||
return;
|
||||
}
|
||||
|
||||
let playing_patterns: Vec<usize> = app
|
||||
.slot_data
|
||||
.iter()
|
||||
.filter(|(active, b, _)| *active && *b == bank)
|
||||
.map(|(_, _, pattern)| *pattern)
|
||||
.collect();
|
||||
|
||||
let edit_pattern = if app.edit_bank == bank {
|
||||
app.edit_pattern
|
||||
} else {
|
||||
usize::MAX
|
||||
};
|
||||
|
||||
let pattern_names: Vec<Option<&str>> = app.project.banks[bank]
|
||||
.patterns
|
||||
.iter()
|
||||
.map(|p| p.name.as_deref())
|
||||
.collect();
|
||||
|
||||
render_pattern_grid(frame, app, inner, bank, app.patterns_cursor, edit_pattern, &playing_patterns, &pattern_names);
|
||||
}
|
||||
|
||||
fn render_grid(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
cursor: usize,
|
||||
edit_pos: usize,
|
||||
playing_positions: &[usize],
|
||||
names: &[Option<&str>],
|
||||
) {
|
||||
let rows = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.split(area);
|
||||
|
||||
for row in 0..4 {
|
||||
let cols = Layout::horizontal(vec![Constraint::Fill(1); 4]).split(rows[row]);
|
||||
for col in 0..4 {
|
||||
let idx = row * 4 + col;
|
||||
let is_cursor = idx == cursor;
|
||||
let is_edit = idx == edit_pos;
|
||||
let is_playing = playing_positions.contains(&idx);
|
||||
|
||||
let (bg, fg) = match (is_cursor, is_edit, is_playing) {
|
||||
(true, _, _) => (Color::Cyan, Color::Black),
|
||||
(false, true, _) => (Color::Rgb(45, 106, 95), Color::White),
|
||||
(false, false, true) => (Color::Rgb(45, 80, 45), Color::Green),
|
||||
(false, false, false) => (Color::Rgb(45, 48, 55), Color::Rgb(120, 125, 135)),
|
||||
};
|
||||
|
||||
let label = names.get(idx).and_then(|n| *n).unwrap_or_else(|| "");
|
||||
let label = if label.is_empty() {
|
||||
format!("{:02}", idx + 1)
|
||||
} else {
|
||||
label.to_string()
|
||||
};
|
||||
let tile = Paragraph::new(label)
|
||||
.alignment(Alignment::Center)
|
||||
.style(Style::new().bg(bg).fg(fg).add_modifier(Modifier::BOLD));
|
||||
|
||||
frame.render_widget(tile, cols[col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_pattern_grid(
|
||||
frame: &mut Frame,
|
||||
app: &App,
|
||||
area: Rect,
|
||||
bank: usize,
|
||||
cursor: usize,
|
||||
edit_pos: usize,
|
||||
playing_positions: &[usize],
|
||||
names: &[Option<&str>],
|
||||
) {
|
||||
let rows = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.split(area);
|
||||
|
||||
for row in 0..4 {
|
||||
let cols = Layout::horizontal(vec![Constraint::Fill(1); 4]).split(rows[row]);
|
||||
for col in 0..4 {
|
||||
let idx = row * 4 + col;
|
||||
let is_cursor = idx == cursor;
|
||||
let is_edit = idx == edit_pos;
|
||||
let is_playing = playing_positions.contains(&idx);
|
||||
let queued = app.is_pattern_queued(bank, idx);
|
||||
|
||||
let (bg, fg, prefix) = match (is_cursor, is_playing, queued) {
|
||||
(true, _, _) => (Color::Cyan, Color::Black, ""),
|
||||
(false, true, Some(false)) => (Color::Rgb(120, 90, 30), Color::Yellow, "×"),
|
||||
(false, true, _) => (Color::Rgb(45, 80, 45), Color::Green, "▶"),
|
||||
(false, false, Some(true)) => (Color::Rgb(80, 80, 45), Color::Yellow, "?"),
|
||||
(false, false, _) if is_edit => (Color::Rgb(45, 106, 95), Color::White, ""),
|
||||
(false, false, _) => (Color::Rgb(45, 48, 55), Color::Rgb(120, 125, 135), ""),
|
||||
};
|
||||
|
||||
let name = names.get(idx).and_then(|n| *n).unwrap_or("");
|
||||
let label = if name.is_empty() {
|
||||
format!("{}{:02}", prefix, idx + 1)
|
||||
} else {
|
||||
format!("{}{}", prefix, name)
|
||||
};
|
||||
let tile = Paragraph::new(label)
|
||||
.alignment(Alignment::Center)
|
||||
.style(Style::new().bg(bg).fg(fg).add_modifier(Modifier::BOLD));
|
||||
|
||||
frame.render_widget(tile, cols[col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user