Feat: UI / UX fixes

This commit is contained in:
2026-02-26 21:17:53 +01:00
parent f618f47811
commit 6b56655661
20 changed files with 268 additions and 169 deletions

View File

@@ -201,6 +201,17 @@ pub fn render(
}
let modal_area = render_modal(frame, app, snapshot, term);
if app.ui.nav_indicator_visible() {
let nav_area = render_nav_indicator(frame, app, term);
let mut fx = app.ui.nav_fx.borrow_mut();
if let Some(effect) = fx.as_mut() {
effect.process(elapsed, frame.buffer_mut(), nav_area);
if !effect.running() {
*fx = None;
}
}
}
if app.ui.show_minimap() {
let tiles: Vec<NavTile> = Page::ALL
.iter()
@@ -234,6 +245,57 @@ pub fn render(
}
}
fn render_nav_indicator(frame: &mut Frame, app: &App, term: Rect) -> Rect {
let theme = theme::get();
let bank = &app.project_state.project.banks[app.editor_ctx.bank];
let pattern = &bank.patterns[app.editor_ctx.pattern];
let bank_num = format!("{:02}", app.editor_ctx.bank + 1);
let pattern_num = format!("{:02}", app.editor_ctx.pattern + 1);
let bank_name = bank.name.as_deref().unwrap_or("");
let pattern_name = pattern.name.as_deref().unwrap_or("");
let inner = ModalFrame::new("")
.width(34)
.height(5)
.border_color(theme.modal.border_accent)
.render_centered(frame, term);
let bank_style = Style::new().fg(theme.header.bank_fg).bold();
let pattern_style = Style::new().fg(theme.header.pattern_fg).bold();
let dim = Style::new().fg(theme.ui.text_dim);
let divider = Style::new().fg(theme.ui.border);
let line1 = Line::from(vec![
Span::styled(" BANK ", bank_style),
Span::styled("", divider),
Span::styled(" PATTERN ", pattern_style),
]);
let line2 = Line::from(vec![
Span::styled(format!(" {bank_num} "), bank_style),
Span::styled(format!("{bank_name:<10}"), dim),
Span::styled("", divider),
Span::styled(format!(" {pattern_num} "), pattern_style),
Span::styled(format!("{pattern_name:<11}"), dim),
]);
frame.render_widget(
Paragraph::new(line1),
Rect::new(inner.x, inner.y, inner.width, 1),
);
frame.render_widget(
Paragraph::new(line2),
Rect::new(inner.x, inner.y + 1, inner.width, 1),
);
Rect::new(
inner.x.saturating_sub(1),
inner.y.saturating_sub(1),
inner.width + 2,
inner.height + 2,
)
}
fn header_height(_width: u16) -> u16 {
3
}
@@ -660,10 +722,6 @@ fn render_modal(
.height(18)
.render_centered(frame, term)
}
Modal::Preview => {
let user_words: HashSet<String> = app.dict.lock().keys().cloned().collect();
render_modal_preview(frame, app, snapshot, &user_words, term)
}
Modal::Editor => {
let user_words: HashSet<String> = app.dict.lock().keys().cloned().collect();
render_modal_editor(frame, app, snapshot, &user_words, term)
@@ -878,64 +936,6 @@ fn render_modal(
))
}
fn render_modal_preview(
frame: &mut Frame,
app: &App,
snapshot: &SequencerSnapshot,
user_words: &HashSet<String>,
term: Rect,
) -> Rect {
let theme = theme::get();
let width = (term.width * 80 / 100).max(40);
let height = (term.height * 80 / 100).max(10);
let pattern = app.current_edit_pattern();
let step_idx = app.editor_ctx.step;
let step = pattern.step(step_idx);
let source_idx = step.and_then(|s| s.source);
let step_name = step.and_then(|s| s.name.as_ref());
let title = match (source_idx, step_name) {
(Some(src), Some(name)) => {
format!("Step {:02}: {}{:02}", step_idx + 1, name, src + 1)
}
(None, Some(name)) => format!("Step {:02}: {}", step_idx + 1, name),
(Some(src), None) => format!("Step {:02}{:02}", step_idx + 1, src + 1),
(None, None) => format!("Step {:02}", step_idx + 1),
};
let inner = ModalFrame::new(&title)
.width(width)
.height(height)
.border_color(theme.modal.preview)
.render_centered(frame, term);
let script = pattern.resolve_script(step_idx).unwrap_or("");
if script.is_empty() {
let empty = Paragraph::new("(empty)")
.alignment(Alignment::Center)
.style(Style::new().fg(theme.ui.text_dim));
let centered_area = Rect {
y: inner.y + inner.height / 2,
height: 1,
..inner
};
frame.render_widget(empty, centered_area);
} else {
let trace = if app.ui.runtime_highlight && app.playback.playing {
let source = pattern.resolve_source(step_idx);
snapshot.get_trace(app.editor_ctx.bank, app.editor_ctx.pattern, source)
} else {
None
};
let lines = highlight_script_lines(script, trace, user_words, usize::MAX);
frame.render_widget(Paragraph::new(lines), inner);
}
inner
}
fn render_modal_editor(
frame: &mut Frame,
app: &App,