Euclidean + hue rotation
Some checks failed
Deploy Website / deploy (push) Has been cancelled

This commit is contained in:
2026-02-02 13:25:27 +01:00
parent c396c39b6b
commit 4396147a8b
21 changed files with 1338 additions and 53 deletions

View File

@@ -11,8 +11,8 @@ use crate::engine::{AudioCommand, LinkState, SeqCommand, SequencerSnapshot};
use crate::model::PatternSpeed;
use crate::page::Page;
use crate::state::{
CyclicEnum, DeviceKind, EngineSection, Modal, OptionsFocus, PanelFocus, PatternField,
PatternPropsField, SampleBrowserState, SettingKind, SidePanel,
CyclicEnum, DeviceKind, EngineSection, EuclideanField, Modal, OptionsFocus, PanelFocus,
PatternField, PatternPropsField, SampleBrowserState, SettingKind, SidePanel,
};
pub enum InputResult {
@@ -641,6 +641,79 @@ fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
_ => {}
}
}
Modal::EuclideanDistribution {
bank,
pattern,
source_step,
field,
pulses,
steps,
rotation,
} => {
let (bank_val, pattern_val, source_step_val) = (*bank, *pattern, *source_step);
match key.code {
KeyCode::Up => *field = field.prev(),
KeyCode::Down | KeyCode::Tab => *field = field.next(),
KeyCode::Left => {
let target = match field {
EuclideanField::Pulses => pulses,
EuclideanField::Steps => steps,
EuclideanField::Rotation => rotation,
};
if let Ok(val) = target.parse::<usize>() {
*target = val.saturating_sub(1).to_string();
}
}
KeyCode::Right => {
let target = match field {
EuclideanField::Pulses => pulses,
EuclideanField::Steps => steps,
EuclideanField::Rotation => rotation,
};
if let Ok(val) = target.parse::<usize>() {
*target = (val + 1).min(128).to_string();
}
}
KeyCode::Char(c) if c.is_ascii_digit() => match field {
EuclideanField::Pulses => pulses.push(c),
EuclideanField::Steps => steps.push(c),
EuclideanField::Rotation => rotation.push(c),
},
KeyCode::Backspace => match field {
EuclideanField::Pulses => {
pulses.pop();
}
EuclideanField::Steps => {
steps.pop();
}
EuclideanField::Rotation => {
rotation.pop();
}
},
KeyCode::Enter => {
let pulses_val: usize = pulses.parse().unwrap_or(0);
let steps_val: usize = steps.parse().unwrap_or(0);
let rotation_val: usize = rotation.parse().unwrap_or(0);
if pulses_val > 0 && steps_val > 0 && pulses_val <= steps_val {
ctx.dispatch(AppCommand::ApplyEuclideanDistribution {
bank: bank_val,
pattern: pattern_val,
source_step: source_step_val,
pulses: pulses_val,
steps: steps_val,
rotation: rotation_val,
});
ctx.dispatch(AppCommand::CloseModal);
} else {
ctx.dispatch(AppCommand::SetStatus(
"Invalid: pulses must be > 0 and <= steps".to_string(),
));
}
}
KeyCode::Esc => ctx.dispatch(AppCommand::CloseModal),
_ => {}
}
}
Modal::None => unreachable!(),
}
InputResult::Continue
@@ -962,6 +1035,25 @@ fn handle_main_page(ctx: &mut InputContext, key: KeyEvent, ctrl: bool) -> InputR
KeyCode::Char('?') => {
ctx.dispatch(AppCommand::OpenModal(Modal::KeybindingsHelp { scroll: 0 }));
}
KeyCode::Char('e') | KeyCode::Char('E') => {
let (bank, pattern, step) = (
ctx.app.editor_ctx.bank,
ctx.app.editor_ctx.pattern,
ctx.app.editor_ctx.step,
);
let pattern_len = ctx.app.current_edit_pattern().length;
let default_steps = pattern_len.min(32);
let default_pulses = (default_steps / 2).max(1).min(default_steps);
ctx.dispatch(AppCommand::OpenModal(Modal::EuclideanDistribution {
bank,
pattern,
source_step: step,
field: EuclideanField::Pulses,
pulses: default_pulses.to_string(),
steps: default_steps.to_string(),
rotation: "0".to_string(),
}));
}
_ => {}
}
InputResult::Continue
@@ -1292,6 +1384,11 @@ fn handle_options_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
};
ctx.dispatch(AppCommand::SetColorScheme(new_scheme));
}
OptionsFocus::HueRotation => {
let delta = if key.code == KeyCode::Left { -1.0 } else { 1.0 };
let new_rotation = (ctx.app.ui.hue_rotation + delta).rem_euclid(360.0);
ctx.dispatch(AppCommand::SetHueRotation(new_rotation));
}
OptionsFocus::RefreshRate => ctx.dispatch(AppCommand::ToggleRefreshRate),
OptionsFocus::RuntimeHighlight => {
ctx.dispatch(AppCommand::ToggleRuntimeHighlight);