Feat: UI / UX fixes
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user