Feat: lissajous
This commit is contained in:
@@ -9,7 +9,8 @@ use crate::app::App;
|
||||
use crate::state::{DeviceKind, EngineSection, SettingKind};
|
||||
use crate::theme;
|
||||
use crate::widgets::{
|
||||
render_scroll_indicators, render_section_header, IndicatorAlign, Orientation, Scope, Spectrum,
|
||||
render_scroll_indicators, render_section_header, IndicatorAlign, Lissajous, Orientation, Scope,
|
||||
Spectrum,
|
||||
};
|
||||
|
||||
pub fn layout(area: Rect) -> [Rect; 3] {
|
||||
@@ -148,14 +149,17 @@ fn render_settings_section(frame: &mut Frame, app: &App, area: Rect) {
|
||||
}
|
||||
|
||||
fn render_visualizers(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let [scope_area, _, spectrum_area] = Layout::vertical([
|
||||
Constraint::Percentage(50),
|
||||
let [scope_area, _, lissajous_area, _gap, spectrum_area] = Layout::vertical([
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(1),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
|
||||
render_scope(frame, app, scope_area);
|
||||
render_lissajous(frame, app, lissajous_area);
|
||||
render_spectrum(frame, app, spectrum_area);
|
||||
}
|
||||
|
||||
@@ -175,6 +179,21 @@ fn render_scope(frame: &mut Frame, app: &App, area: Rect) {
|
||||
frame.render_widget(scope, inner);
|
||||
}
|
||||
|
||||
fn render_lissajous(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(" Lissajous ")
|
||||
.border_style(Style::new().fg(theme.engine.border_green));
|
||||
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let lissajous = Lissajous::new(&app.metrics.scope, &app.metrics.scope_right)
|
||||
.color(theme.meter.low);
|
||||
frame.render_widget(lissajous, inner);
|
||||
}
|
||||
|
||||
fn render_spectrum(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::engine::SequencerSnapshot;
|
||||
use crate::state::MainLayout;
|
||||
use crate::theme;
|
||||
use crate::views::render::highlight_script_lines;
|
||||
use crate::widgets::{Orientation, Scope, Spectrum, VuMeter};
|
||||
use crate::widgets::{Lissajous, Orientation, Scope, Spectrum, VuMeter};
|
||||
|
||||
pub fn layout(area: Rect) -> [Rect; 3] {
|
||||
Layout::horizontal([
|
||||
@@ -31,6 +31,7 @@ pub fn render(frame: &mut Frame, app: &App, snapshot: &SequencerSnapshot, area:
|
||||
} else {
|
||||
let has_viz = app.audio.config.show_scope
|
||||
|| app.audio.config.show_spectrum
|
||||
|| app.audio.config.show_lissajous
|
||||
|| app.audio.config.show_preview;
|
||||
let (viz_area, sequencer_area) =
|
||||
viz_seq_split(main_area, app.audio.config.layout, has_viz);
|
||||
@@ -49,7 +50,9 @@ fn render_top_layout(
|
||||
snapshot: &SequencerSnapshot,
|
||||
main_area: Rect,
|
||||
) {
|
||||
let has_audio_viz = app.audio.config.show_scope || app.audio.config.show_spectrum;
|
||||
let has_audio_viz = app.audio.config.show_scope
|
||||
|| app.audio.config.show_spectrum
|
||||
|| app.audio.config.show_lissajous;
|
||||
let has_preview = app.audio.config.show_preview;
|
||||
|
||||
let mut constraints = Vec::new();
|
||||
@@ -85,16 +88,23 @@ fn render_top_layout(
|
||||
}
|
||||
|
||||
fn render_audio_viz(frame: &mut Frame, app: &App, area: Rect) {
|
||||
match (app.audio.config.show_scope, app.audio.config.show_spectrum) {
|
||||
(true, true) => {
|
||||
let [scope_area, spectrum_area] =
|
||||
Layout::horizontal([Constraint::Fill(1), Constraint::Fill(1)]).areas(area);
|
||||
render_scope(frame, app, scope_area, Orientation::Horizontal);
|
||||
render_spectrum(frame, app, spectrum_area);
|
||||
let mut panels: Vec<VizPanel> = Vec::new();
|
||||
if app.audio.config.show_scope { panels.push(VizPanel::Scope); }
|
||||
if app.audio.config.show_spectrum { panels.push(VizPanel::Spectrum); }
|
||||
if app.audio.config.show_lissajous { panels.push(VizPanel::Lissajous); }
|
||||
|
||||
if panels.is_empty() { return; }
|
||||
|
||||
let constraints: Vec<Constraint> = panels.iter().map(|_| Constraint::Fill(1)).collect();
|
||||
let areas: Vec<Rect> = Layout::horizontal(&constraints).split(area).to_vec();
|
||||
|
||||
for (panel, panel_area) in panels.iter().zip(areas.iter()) {
|
||||
match panel {
|
||||
VizPanel::Scope => render_scope(frame, app, *panel_area, Orientation::Horizontal),
|
||||
VizPanel::Spectrum => render_spectrum(frame, app, *panel_area),
|
||||
VizPanel::Lissajous => render_lissajous(frame, app, *panel_area),
|
||||
VizPanel::Preview => {}
|
||||
}
|
||||
(true, false) => render_scope(frame, app, area, Orientation::Horizontal),
|
||||
(false, true) => render_spectrum(frame, app, area),
|
||||
(false, false) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +114,9 @@ fn preview_height(has_audio_viz: bool) -> u16 {
|
||||
|
||||
pub fn sequencer_rect(app: &App, main_area: Rect) -> Rect {
|
||||
if matches!(app.audio.config.layout, MainLayout::Top) {
|
||||
let has_audio_viz = app.audio.config.show_scope || app.audio.config.show_spectrum;
|
||||
let has_audio_viz = app.audio.config.show_scope
|
||||
|| app.audio.config.show_spectrum
|
||||
|| app.audio.config.show_lissajous;
|
||||
let has_preview = app.audio.config.show_preview;
|
||||
|
||||
let mut constraints = Vec::new();
|
||||
@@ -121,6 +133,7 @@ pub fn sequencer_rect(app: &App, main_area: Rect) -> Rect {
|
||||
} else {
|
||||
let has_viz = app.audio.config.show_scope
|
||||
|| app.audio.config.show_spectrum
|
||||
|| app.audio.config.show_lissajous
|
||||
|| app.audio.config.show_preview;
|
||||
let (_, seq_area) = viz_seq_split(main_area, app.audio.config.layout, has_viz);
|
||||
seq_area
|
||||
@@ -130,6 +143,7 @@ pub fn sequencer_rect(app: &App, main_area: Rect) -> Rect {
|
||||
enum VizPanel {
|
||||
Scope,
|
||||
Spectrum,
|
||||
Lissajous,
|
||||
Preview,
|
||||
}
|
||||
|
||||
@@ -142,11 +156,13 @@ fn render_viz_area(
|
||||
let is_vertical_layout = matches!(app.audio.config.layout, MainLayout::Left | MainLayout::Right);
|
||||
let show_scope = app.audio.config.show_scope;
|
||||
let show_spectrum = app.audio.config.show_spectrum;
|
||||
let show_lissajous = app.audio.config.show_lissajous;
|
||||
let show_preview = app.audio.config.show_preview;
|
||||
|
||||
let mut panels = Vec::new();
|
||||
if show_scope { panels.push(VizPanel::Scope); }
|
||||
if show_spectrum { panels.push(VizPanel::Spectrum); }
|
||||
if show_lissajous { panels.push(VizPanel::Lissajous); }
|
||||
if show_preview { panels.push(VizPanel::Preview); }
|
||||
|
||||
let constraints: Vec<Constraint> = panels.iter().map(|_| Constraint::Fill(1)).collect();
|
||||
@@ -173,6 +189,7 @@ fn render_viz_area(
|
||||
match panel {
|
||||
VizPanel::Scope => render_scope(frame, app, *panel_area, orientation),
|
||||
VizPanel::Spectrum => render_spectrum(frame, app, *panel_area),
|
||||
VizPanel::Lissajous => render_lissajous(frame, app, *panel_area),
|
||||
VizPanel::Preview => {
|
||||
let user_words = user_words_once.as_ref().unwrap();
|
||||
let has_prelude = !app.project_state.project.prelude.trim().is_empty();
|
||||
@@ -491,6 +508,19 @@ fn render_spectrum(frame: &mut Frame, app: &App, area: Rect) {
|
||||
frame.render_widget(spectrum, inner);
|
||||
}
|
||||
|
||||
fn render_lissajous(frame: &mut Frame, app: &App, area: Rect) {
|
||||
let theme = theme::get();
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::new().fg(theme.ui.border));
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let lissajous = Lissajous::new(&app.metrics.scope, &app.metrics.scope_right)
|
||||
.color(theme.meter.low);
|
||||
frame.render_widget(lissajous, inner);
|
||||
}
|
||||
|
||||
fn render_script_preview(
|
||||
frame: &mut Frame,
|
||||
app: &App,
|
||||
|
||||
@@ -78,6 +78,16 @@ pub fn render(frame: &mut Frame, app: &App, link: &LinkState, area: Rect) {
|
||||
focus == OptionsFocus::ShowSpectrum,
|
||||
&theme,
|
||||
),
|
||||
render_option_line(
|
||||
"Show lissajous",
|
||||
if app.audio.config.show_lissajous {
|
||||
"On"
|
||||
} else {
|
||||
"Off"
|
||||
},
|
||||
focus == OptionsFocus::ShowLissajous,
|
||||
&theme,
|
||||
),
|
||||
render_option_line(
|
||||
"Completion",
|
||||
if app.ui.show_completion { "On" } else { "Off" },
|
||||
@@ -346,6 +356,7 @@ fn option_description(focus: OptionsFocus) -> Option<&'static str> {
|
||||
OptionsFocus::RuntimeHighlight => Some("Highlight executed code spans during playback"),
|
||||
OptionsFocus::ShowScope => Some("Oscilloscope on the engine page"),
|
||||
OptionsFocus::ShowSpectrum => Some("Spectrum analyzer on the engine page"),
|
||||
OptionsFocus::ShowLissajous => Some("XY stereo phase scope (left vs right)"),
|
||||
OptionsFocus::ShowCompletion => Some("Word completion popup in the editor"),
|
||||
OptionsFocus::ShowPreview => Some("Step script preview on the sequencer grid"),
|
||||
OptionsFocus::PerformanceMode => Some("Hide header and footer bars"),
|
||||
|
||||
Reference in New Issue
Block a user