This commit is contained in:
2026-01-23 01:18:40 +01:00
parent 1aad52eed1
commit 10e2812e4c
5 changed files with 157 additions and 91 deletions

View File

@@ -1,12 +1,10 @@
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::Line;
use ratatui::widgets::Paragraph;
use ratatui::Frame;
use crate::app::App;
use crate::engine::SequencerSnapshot;
use crate::views::highlight::{highlight_line, highlight_line_with_runtime};
use crate::widgets::{Orientation, Scope, VuMeter};
pub fn render(frame: &mut Frame, app: &mut App, snapshot: &SequencerSnapshot, area: Rect) {
@@ -17,19 +15,19 @@ pub fn render(frame: &mut Frame, app: &mut App, snapshot: &SequencerSnapshot, ar
])
.areas(area);
let [scope_area, sequencer_area, preview_area] = Layout::vertical([
Constraint::Length(8),
let [scope_area, sequencer_area] = Layout::vertical([
Constraint::Length(14),
Constraint::Fill(1),
Constraint::Length(2),
])
.areas(left_area);
render_scope(frame, app, scope_area);
render_sequencer(frame, app, snapshot, sequencer_area);
render_step_preview(frame, app, snapshot, preview_area);
render_vu_meter(frame, app, vu_area);
}
const STEPS_PER_PAGE: usize = 32;
fn render_sequencer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area: Rect) {
if area.width < 50 {
let msg = Paragraph::new("Terminal too narrow")
@@ -41,8 +39,12 @@ fn render_sequencer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot,
let pattern = app.current_edit_pattern();
let length = pattern.length;
let num_rows = length.div_ceil(8);
let steps_per_row = length.div_ceil(num_rows);
let page = app.editor_ctx.step / STEPS_PER_PAGE;
let page_start = page * STEPS_PER_PAGE;
let steps_on_page = (page_start + STEPS_PER_PAGE).min(length) - page_start;
let num_rows = steps_on_page.div_ceil(8);
let steps_per_row = steps_on_page.div_ceil(num_rows);
let spacing = num_rows.saturating_sub(1) as u16;
let row_height = area.height.saturating_sub(spacing) / num_rows as u16;
@@ -61,7 +63,7 @@ fn render_sequencer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot,
for row_idx in 0..num_rows {
let row_area = rows[row_idx * 2];
let start_step = row_idx * steps_per_row;
let end_step = (start_step + steps_per_row).min(length);
let end_step = (start_step + steps_per_row).min(steps_on_page);
let cols_in_row = end_step - start_step;
let col_constraints: Vec<Constraint> = (0..cols_in_row * 2 - 1)
@@ -78,12 +80,13 @@ fn render_sequencer(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot,
let cols = Layout::horizontal(col_constraints).split(row_area);
for col_idx in 0..cols_in_row {
let step_idx = start_step + col_idx;
let step_idx = page_start + start_step + col_idx;
if step_idx < length {
render_tile(frame, cols[col_idx * 2], app, snapshot, step_idx);
}
}
}
}
fn render_tile(
@@ -168,54 +171,3 @@ fn render_vu_meter(frame: &mut Frame, app: &App, area: Rect) {
frame.render_widget(vu, area);
}
fn render_step_preview(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area: Rect) {
let pattern = app.current_edit_pattern();
let step_idx = app.editor_ctx.step;
let step = pattern.step(step_idx);
let [title_area, content_area] =
Layout::vertical([Constraint::Length(1), Constraint::Length(1)]).areas(area);
let is_linked = step.map(|s| s.source.is_some()).unwrap_or(false);
let source_idx = step.and_then(|s| s.source);
let title = if let Some(src) = source_idx {
format!(" Step {:02}{:02} ", step_idx + 1, src + 1)
} else {
format!(" Step {:02} ", step_idx + 1)
};
let title_color = if is_linked {
Color::Rgb(180, 140, 220)
} else {
Color::Rgb(120, 125, 135)
};
let title_p = Paragraph::new(title).style(Style::new().fg(title_color));
frame.render_widget(title_p, title_area);
let script = pattern.resolve_script(step_idx).unwrap_or("");
if script.is_empty() {
let empty = Paragraph::new(" (empty)").style(Style::new().fg(Color::Rgb(80, 85, 95)));
frame.render_widget(empty, content_area);
return;
}
let runtime_spans = if app.ui.runtime_highlight && app.playback.playing {
snapshot.get_trace(app.editor_ctx.bank, app.editor_ctx.pattern, step_idx)
} else {
None
};
let spans: Vec<_> = if let Some(traces) = runtime_spans {
highlight_line_with_runtime(script, traces)
} else {
highlight_line(script)
}
.into_iter()
.map(|(style, text)| ratatui::text::Span::styled(text, style))
.collect();
let mut line_spans = vec![ratatui::text::Span::raw(" ")];
line_spans.extend(spans);
let line = Line::from(line_spans);
let paragraph = Paragraph::new(line);
frame.render_widget(paragraph, content_area);
}