Fixing color schemes
This commit is contained in:
@@ -18,7 +18,7 @@ use crate::engine::{LinkState, SequencerSnapshot};
|
||||
use crate::model::{SourceSpan, StepContext, Value};
|
||||
use crate::page::Page;
|
||||
use crate::state::{FlashKind, Modal, PanelFocus, PatternField, SidePanel, StackCache};
|
||||
use crate::theme::{browser, flash, header, hint, modal, search, status, table, ui};
|
||||
use crate::theme;
|
||||
use crate::views::highlight::{self, highlight_line, highlight_line_with_runtime};
|
||||
use crate::widgets::{
|
||||
ConfirmModal, ModalFrame, NavMinimap, NavTile, SampleBrowser, TextInputModal,
|
||||
@@ -132,16 +132,17 @@ fn adjust_spans_for_line(
|
||||
pub fn render(frame: &mut Frame, app: &App, link: &LinkState, snapshot: &SequencerSnapshot) {
|
||||
let term = frame.area();
|
||||
|
||||
let theme = theme::get();
|
||||
let bg_color = if app.ui.event_flash > 0.0 {
|
||||
let t = (app.ui.event_flash * app.ui.flash_brightness).min(1.0);
|
||||
let (base_r, base_g, base_b) = ui::BG_RGB;
|
||||
let (tgt_r, tgt_g, tgt_b) = flash::EVENT_RGB;
|
||||
let (base_r, base_g, base_b) = theme.ui.bg_rgb;
|
||||
let (tgt_r, tgt_g, tgt_b) = theme.flash.event_rgb;
|
||||
let r = base_r + ((tgt_r as f32 - base_r as f32) * t) as u8;
|
||||
let g = base_g + ((tgt_g as f32 - base_g as f32) * t) as u8;
|
||||
let b = base_b + ((tgt_b as f32 - base_b as f32) * t) as u8;
|
||||
Color::Rgb(r, g, b)
|
||||
} else {
|
||||
ui::BG
|
||||
theme.ui.bg
|
||||
};
|
||||
|
||||
let blank = " ".repeat(term.width as usize);
|
||||
@@ -259,6 +260,7 @@ fn render_header(
|
||||
) {
|
||||
use crate::model::PatternSpeed;
|
||||
|
||||
let theme = theme::get();
|
||||
let bank = &app.project_state.project.banks[app.editor_ctx.bank];
|
||||
let pattern = &bank.patterns[app.editor_ctx.pattern];
|
||||
|
||||
@@ -300,11 +302,11 @@ fn render_header(
|
||||
|
||||
// Transport block
|
||||
let (transport_bg, transport_text) = if app.playback.playing {
|
||||
(status::PLAYING_BG, " ▶ PLAYING ")
|
||||
(theme.status.playing_bg, " ▶ PLAYING ")
|
||||
} else {
|
||||
(status::STOPPED_BG, " ■ STOPPED ")
|
||||
(theme.status.stopped_bg, " ■ STOPPED ")
|
||||
};
|
||||
let transport_style = Style::new().bg(transport_bg).fg(ui::TEXT_PRIMARY);
|
||||
let transport_style = Style::new().bg(transport_bg).fg(theme.ui.text_primary);
|
||||
frame.render_widget(
|
||||
Paragraph::new(transport_text)
|
||||
.style(transport_style)
|
||||
@@ -314,8 +316,8 @@ fn render_header(
|
||||
|
||||
// Fill indicator
|
||||
let fill = app.live_keys.fill();
|
||||
let fill_fg = if fill { status::FILL_ON } else { status::FILL_OFF };
|
||||
let fill_style = Style::new().bg(status::FILL_BG).fg(fill_fg);
|
||||
let fill_fg = if fill { theme.status.fill_on } else { theme.status.fill_off };
|
||||
let fill_style = Style::new().bg(theme.status.fill_bg).fg(fill_fg);
|
||||
frame.render_widget(
|
||||
Paragraph::new(if fill { "F" } else { "·" })
|
||||
.style(fill_style)
|
||||
@@ -325,8 +327,8 @@ fn render_header(
|
||||
|
||||
// Tempo block
|
||||
let tempo_style = Style::new()
|
||||
.bg(header::TEMPO_BG)
|
||||
.fg(ui::TEXT_PRIMARY)
|
||||
.bg(theme.header.tempo_bg)
|
||||
.fg(theme.ui.text_primary)
|
||||
.add_modifier(Modifier::BOLD);
|
||||
frame.render_widget(
|
||||
Paragraph::new(format!(" {:.1} BPM ", link.tempo()))
|
||||
@@ -341,7 +343,7 @@ fn render_header(
|
||||
.as_deref()
|
||||
.map(|n| format!(" {n} "))
|
||||
.unwrap_or_else(|| format!(" Bank {:02} ", app.editor_ctx.bank + 1));
|
||||
let bank_style = Style::new().bg(header::BANK_BG).fg(ui::TEXT_PRIMARY);
|
||||
let bank_style = Style::new().bg(theme.header.bank_bg).fg(theme.ui.text_primary);
|
||||
frame.render_widget(
|
||||
Paragraph::new(bank_name)
|
||||
.style(bank_style)
|
||||
@@ -372,7 +374,7 @@ fn render_header(
|
||||
" {} · {} steps{}{}{} ",
|
||||
pattern_name, pattern.length, speed_info, page_info, iter_info
|
||||
);
|
||||
let pattern_style = Style::new().bg(header::PATTERN_BG).fg(ui::TEXT_PRIMARY);
|
||||
let pattern_style = Style::new().bg(theme.header.pattern_bg).fg(theme.ui.text_primary);
|
||||
frame.render_widget(
|
||||
Paragraph::new(pattern_text)
|
||||
.style(pattern_style)
|
||||
@@ -385,7 +387,7 @@ fn render_header(
|
||||
let peers = link.peers();
|
||||
let voices = app.metrics.active_voices;
|
||||
let stats_text = format!(" CPU {cpu_pct:.0}% V:{voices} L:{peers} ");
|
||||
let stats_style = Style::new().bg(header::STATS_BG).fg(header::STATS_FG);
|
||||
let stats_style = Style::new().bg(theme.header.stats_bg).fg(theme.header.stats_fg);
|
||||
frame.render_widget(
|
||||
Paragraph::new(stats_text)
|
||||
.style(stats_style)
|
||||
@@ -395,27 +397,30 @@ fn render_header(
|
||||
}
|
||||
|
||||
fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let block = Block::default().borders(Borders::ALL);
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::new().fg(theme.ui.border));
|
||||
let inner = block.inner(area);
|
||||
let available_width = inner.width as usize;
|
||||
|
||||
let page_indicator = match app.page {
|
||||
Page::Main => "[MAIN]",
|
||||
Page::Patterns => "[PATTERNS]",
|
||||
Page::Engine => "[ENGINE]",
|
||||
Page::Options => "[OPTIONS]",
|
||||
Page::Help => "[HELP]",
|
||||
Page::Dict => "[DICT]",
|
||||
Page::Main => " MAIN ",
|
||||
Page::Patterns => " PATTERNS ",
|
||||
Page::Engine => " ENGINE ",
|
||||
Page::Options => " OPTIONS ",
|
||||
Page::Help => " HELP ",
|
||||
Page::Dict => " DICT ",
|
||||
};
|
||||
|
||||
let content = if let Some(ref msg) = app.ui.status_message {
|
||||
Line::from(vec![
|
||||
Span::styled(
|
||||
page_indicator.to_string(),
|
||||
Style::new().fg(ui::TEXT_PRIMARY).add_modifier(Modifier::DIM),
|
||||
Style::new().bg(theme.view_badge.bg).fg(theme.view_badge.fg),
|
||||
),
|
||||
Span::raw(" "),
|
||||
Span::styled(msg.clone(), Style::new().fg(modal::CONFIRM)),
|
||||
Span::styled(msg.clone(), Style::new().fg(theme.modal.confirm)),
|
||||
])
|
||||
} else {
|
||||
let bindings: Vec<(&str, &str)> = match app.page {
|
||||
@@ -477,7 +482,7 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let mut spans = vec![
|
||||
Span::styled(
|
||||
page_indicator.to_string(),
|
||||
Style::new().fg(ui::TEXT_PRIMARY).add_modifier(Modifier::DIM),
|
||||
Style::new().bg(theme.view_badge.bg).fg(theme.view_badge.fg),
|
||||
),
|
||||
Span::raw(" ".repeat(base_gap + if extra > 0 { 1 } else { 0 })),
|
||||
];
|
||||
@@ -485,11 +490,11 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
for (i, (key, action)) in bindings.into_iter().enumerate() {
|
||||
spans.push(Span::styled(
|
||||
key.to_string(),
|
||||
Style::new().fg(hint::KEY),
|
||||
Style::new().fg(theme.hint.key),
|
||||
));
|
||||
spans.push(Span::styled(
|
||||
format!(":{action}"),
|
||||
Style::new().fg(hint::TEXT),
|
||||
format!(": {action}"),
|
||||
Style::new().fg(theme.hint.text),
|
||||
));
|
||||
|
||||
if i < n - 1 {
|
||||
@@ -506,6 +511,7 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
|
||||
}
|
||||
|
||||
fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term: Rect) {
|
||||
let theme = theme::get();
|
||||
match &app.ui.modal {
|
||||
Modal::None => {}
|
||||
Modal::ConfirmQuit { selected } => {
|
||||
@@ -539,8 +545,8 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
use crate::state::file_browser::FileBrowserMode;
|
||||
use crate::widgets::FileBrowserModal;
|
||||
let (title, border_color) = match state.mode {
|
||||
FileBrowserMode::Save => ("Save As", flash::SUCCESS_FG),
|
||||
FileBrowserMode::Load => ("Load From", browser::DIRECTORY),
|
||||
FileBrowserMode::Save => ("Save As", theme.flash.success_fg),
|
||||
FileBrowserMode::Load => ("Load From", theme.browser.directory),
|
||||
};
|
||||
let entries: Vec<(String, bool, bool)> = state
|
||||
.entries
|
||||
@@ -558,7 +564,7 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
Modal::RenameBank { bank, name } => {
|
||||
TextInputModal::new(&format!("Rename Bank {:02}", bank + 1), name)
|
||||
.width(40)
|
||||
.border_color(modal::RENAME)
|
||||
.border_color(theme.modal.rename)
|
||||
.render_centered(frame, term);
|
||||
}
|
||||
Modal::RenamePattern {
|
||||
@@ -571,13 +577,13 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
name,
|
||||
)
|
||||
.width(40)
|
||||
.border_color(modal::RENAME)
|
||||
.border_color(theme.modal.rename)
|
||||
.render_centered(frame, term);
|
||||
}
|
||||
Modal::RenameStep { step, name, .. } => {
|
||||
TextInputModal::new(&format!("Name Step {:02}", step + 1), name)
|
||||
.width(40)
|
||||
.border_color(modal::INPUT)
|
||||
.border_color(theme.modal.input)
|
||||
.render_centered(frame, term);
|
||||
}
|
||||
Modal::SetPattern { field, input } => {
|
||||
@@ -588,14 +594,14 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
TextInputModal::new(title, input)
|
||||
.hint(hint)
|
||||
.width(45)
|
||||
.border_color(modal::CONFIRM)
|
||||
.border_color(theme.modal.confirm)
|
||||
.render_centered(frame, term);
|
||||
}
|
||||
Modal::SetTempo(input) => {
|
||||
TextInputModal::new("Set Tempo (20-300 BPM)", input)
|
||||
.hint("Enter BPM")
|
||||
.width(30)
|
||||
.border_color(modal::RENAME)
|
||||
.border_color(theme.modal.rename)
|
||||
.render_centered(frame, term);
|
||||
}
|
||||
Modal::AddSamplePath(state) => {
|
||||
@@ -608,7 +614,7 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
FileBrowserModal::new("Add Sample Path", &state.input, &entries)
|
||||
.selected(state.selected)
|
||||
.scroll_offset(state.scroll_offset)
|
||||
.border_color(modal::RENAME)
|
||||
.border_color(theme.modal.rename)
|
||||
.width(60)
|
||||
.height(18)
|
||||
.render_centered(frame, term);
|
||||
@@ -633,14 +639,14 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
let inner = ModalFrame::new(&title)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.border_color(modal::PREVIEW)
|
||||
.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(ui::TEXT_DIM));
|
||||
.style(Style::new().fg(theme.ui.text_dim));
|
||||
let centered_area = Rect {
|
||||
y: inner.y + inner.height / 2,
|
||||
height: 1,
|
||||
@@ -695,10 +701,10 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
let flash_kind = app.ui.flash_kind();
|
||||
let border_color = match flash_kind {
|
||||
Some(FlashKind::Error) => flash::ERROR_FG,
|
||||
Some(FlashKind::Info) => ui::TEXT_PRIMARY,
|
||||
Some(FlashKind::Success) => flash::SUCCESS_FG,
|
||||
None => modal::EDITOR,
|
||||
Some(FlashKind::Error) => theme.flash.error_fg,
|
||||
Some(FlashKind::Info) => theme.ui.text_primary,
|
||||
Some(FlashKind::Success) => theme.flash.success_fg,
|
||||
None => theme.modal.editor,
|
||||
};
|
||||
|
||||
let title = if let Some(ref name) = step.and_then(|s| s.name.as_ref()) {
|
||||
@@ -765,9 +771,9 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
if let Some(sa) = search_area {
|
||||
let style = if app.editor_ctx.editor.search_active() {
|
||||
Style::default().fg(search::ACTIVE)
|
||||
Style::default().fg(theme.search.active)
|
||||
} else {
|
||||
Style::default().fg(search::INACTIVE)
|
||||
Style::default().fg(theme.search.inactive)
|
||||
};
|
||||
let cursor = if app.editor_ctx.editor.search_active() {
|
||||
"_"
|
||||
@@ -780,9 +786,9 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
if let Some(kind) = flash_kind {
|
||||
let bg = match kind {
|
||||
FlashKind::Error => flash::ERROR_BG,
|
||||
FlashKind::Info => flash::INFO_BG,
|
||||
FlashKind::Success => flash::SUCCESS_BG,
|
||||
FlashKind::Error => theme.flash.error_bg,
|
||||
FlashKind::Info => theme.flash.info_bg,
|
||||
FlashKind::Success => theme.flash.success_bg,
|
||||
};
|
||||
let flash_block = Block::default().style(Style::default().bg(bg));
|
||||
frame.render_widget(flash_block, editor_area);
|
||||
@@ -791,8 +797,8 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
.editor
|
||||
.render(frame, editor_area, &highlighter);
|
||||
|
||||
let dim = Style::default().fg(hint::TEXT);
|
||||
let key = Style::default().fg(hint::KEY);
|
||||
let dim = Style::default().fg(theme.hint.text);
|
||||
let key = Style::default().fg(theme.hint.key);
|
||||
|
||||
if app.editor_ctx.editor.search_active() {
|
||||
let hint = Line::from(vec![
|
||||
@@ -860,7 +866,7 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
let block = Block::bordered()
|
||||
.title(format!(" Pattern B{:02}:P{:02} ", bank + 1, pattern + 1))
|
||||
.border_style(Style::default().fg(modal::INPUT));
|
||||
.border_style(Style::default().fg(theme.modal.input));
|
||||
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(Clear, area);
|
||||
@@ -895,14 +901,14 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
let (label_style, value_style) = if *selected {
|
||||
(
|
||||
Style::default()
|
||||
.fg(hint::KEY)
|
||||
.fg(theme.hint.key)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
Style::default().fg(ui::TEXT_PRIMARY).bg(ui::SURFACE),
|
||||
Style::default().fg(theme.ui.text_primary).bg(theme.ui.surface),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
Style::default().fg(ui::TEXT_MUTED),
|
||||
Style::default().fg(ui::TEXT_PRIMARY),
|
||||
Style::default().fg(theme.ui.text_muted),
|
||||
Style::default().fg(theme.ui.text_primary),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -918,14 +924,14 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
|
||||
let hint_area = Rect::new(inner.x, inner.y + inner.height - 1, inner.width, 1);
|
||||
let hint_line = Line::from(vec![
|
||||
Span::styled("↑↓", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" nav ", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("←→", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" change ", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("Enter", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" save ", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("Esc", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" cancel", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("↑↓", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" nav ", Style::default().fg(theme.hint.text)),
|
||||
Span::styled("←→", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" change ", Style::default().fg(theme.hint.text)),
|
||||
Span::styled("Enter", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" save ", Style::default().fg(theme.hint.text)),
|
||||
Span::styled("Esc", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" cancel", Style::default().fg(theme.hint.text)),
|
||||
]);
|
||||
frame.render_widget(Paragraph::new(hint_line), hint_area);
|
||||
}
|
||||
@@ -937,7 +943,7 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
let inner = ModalFrame::new(&title)
|
||||
.width(width)
|
||||
.height(height)
|
||||
.border_color(modal::EDITOR)
|
||||
.border_color(theme.modal.editor)
|
||||
.render_centered(frame, term);
|
||||
|
||||
let bindings = super::keybindings::bindings_for(app.page);
|
||||
@@ -949,11 +955,11 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
.skip(*scroll)
|
||||
.take(visible_rows)
|
||||
.map(|(i, (key, name, desc))| {
|
||||
let bg = if i % 2 == 0 { table::ROW_EVEN } else { table::ROW_ODD };
|
||||
let bg = if i % 2 == 0 { theme.table.row_even } else { theme.table.row_odd };
|
||||
Row::new(vec![
|
||||
Cell::from(*key).style(Style::default().fg(modal::CONFIRM)),
|
||||
Cell::from(*name).style(Style::default().fg(modal::INPUT)),
|
||||
Cell::from(*desc).style(Style::default().fg(ui::TEXT_PRIMARY)),
|
||||
Cell::from(*key).style(Style::default().fg(theme.modal.confirm)),
|
||||
Cell::from(*name).style(Style::default().fg(theme.modal.input)),
|
||||
Cell::from(*desc).style(Style::default().fg(theme.ui.text_primary)),
|
||||
])
|
||||
.style(Style::default().bg(bg))
|
||||
})
|
||||
@@ -984,12 +990,12 @@ fn render_modal(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, term
|
||||
height: 1,
|
||||
};
|
||||
let keybind_hint = Line::from(vec![
|
||||
Span::styled("↑↓", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" scroll ", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("PgUp/Dn", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" page ", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("Esc/?", Style::default().fg(hint::KEY)),
|
||||
Span::styled(" close", Style::default().fg(hint::TEXT)),
|
||||
Span::styled("↑↓", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" scroll ", Style::default().fg(theme.hint.text)),
|
||||
Span::styled("PgUp/Dn", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" page ", Style::default().fg(theme.hint.text)),
|
||||
Span::styled("Esc/?", Style::default().fg(theme.hint.key)),
|
||||
Span::styled(" close", Style::default().fg(theme.hint.text)),
|
||||
]);
|
||||
frame.render_widget(Paragraph::new(keybind_hint).alignment(Alignment::Right), hint_area);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user