chain word and better save/load UI

This commit is contained in:
2026-01-23 23:36:23 +01:00
parent a1ddb4a170
commit f75ea4bb97
20 changed files with 775 additions and 132 deletions

View File

@@ -190,31 +190,32 @@ fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
_ => {}
}
}
Modal::SaveAs(path) => match key.code {
Modal::FileBrowser(state) => match key.code {
KeyCode::Enter => {
let save_path = PathBuf::from(path.as_str());
ctx.dispatch(AppCommand::CloseModal);
ctx.dispatch(AppCommand::Save(save_path));
use crate::state::file_browser::FileBrowserMode;
let mode = state.mode.clone();
if let Some(path) = state.confirm() {
ctx.dispatch(AppCommand::CloseModal);
match mode {
FileBrowserMode::Save => ctx.dispatch(AppCommand::Save(path)),
FileBrowserMode::Load => {
ctx.dispatch(AppCommand::Load(path));
load_project_samples(ctx);
}
}
}
}
KeyCode::Esc => ctx.dispatch(AppCommand::CloseModal),
KeyCode::Backspace => {
path.pop();
KeyCode::Tab => state.autocomplete(),
KeyCode::Left => state.go_up(),
KeyCode::Right => state.enter_selected(),
KeyCode::Up => state.select_prev(12),
KeyCode::Down => state.select_next(12),
KeyCode::Backspace => state.backspace(),
KeyCode::Char(c) => {
state.input.push(c);
state.refresh_entries();
}
KeyCode::Char(c) => path.push(c),
_ => {}
},
Modal::LoadFrom(path) => match key.code {
KeyCode::Enter => {
let load_path = PathBuf::from(path.as_str());
ctx.dispatch(AppCommand::CloseModal);
ctx.dispatch(AppCommand::Load(load_path));
load_project_samples(ctx);
}
KeyCode::Esc => ctx.dispatch(AppCommand::CloseModal),
KeyCode::Backspace => {
path.pop();
}
KeyCode::Char(c) => path.push(c),
_ => {}
},
Modal::RenameBank { bank, name } => match key.code {
@@ -438,13 +439,23 @@ fn handle_main_page(ctx: &mut InputContext, key: KeyEvent, ctrl: bool) -> InputR
KeyCode::Enter => ctx.dispatch(AppCommand::OpenModal(Modal::Editor)),
KeyCode::Char('t') => ctx.dispatch(AppCommand::ToggleStep),
KeyCode::Char('s') => {
ctx.dispatch(AppCommand::OpenModal(Modal::SaveAs(String::new())));
use crate::state::file_browser::FileBrowserState;
let initial = ctx
.app
.project_state
.file_path
.as_ref()
.map(|p| p.display().to_string())
.unwrap_or_default();
let state = FileBrowserState::new_save(initial);
ctx.dispatch(AppCommand::OpenModal(Modal::FileBrowser(state)));
}
KeyCode::Char('c') if ctrl => ctx.dispatch(AppCommand::CopyStep),
KeyCode::Char('v') if ctrl => ctx.dispatch(AppCommand::PasteStep),
KeyCode::Char('b') if ctrl => ctx.dispatch(AppCommand::LinkPasteStep),
KeyCode::Char('h') if ctrl => ctx.dispatch(AppCommand::HardenStep),
KeyCode::Char('l') => {
use crate::state::file_browser::FileBrowserState;
let default_dir = ctx
.app
.project_state
@@ -459,7 +470,8 @@ fn handle_main_page(ctx: &mut InputContext, key: KeyEvent, ctrl: bool) -> InputR
s
})
.unwrap_or_default();
ctx.dispatch(AppCommand::OpenModal(Modal::LoadFrom(default_dir)));
let state = FileBrowserState::new_load(default_dir);
ctx.dispatch(AppCommand::OpenModal(Modal::FileBrowser(state)));
}
KeyCode::Char('+') | KeyCode::Char('=') => ctx.dispatch(AppCommand::TempoUp),
KeyCode::Char('-') => ctx.dispatch(AppCommand::TempoDown),
@@ -589,12 +601,62 @@ fn handle_audio_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
selected: false,
}));
}
KeyCode::Up | KeyCode::Char('k') => ctx.app.audio.prev_focus(),
KeyCode::Down | KeyCode::Char('j') => ctx.app.audio.next_focus(),
KeyCode::Tab => ctx.app.audio.next_focus(),
KeyCode::BackTab => ctx.app.audio.prev_focus(),
KeyCode::Up => match ctx.app.audio.focus {
AudioFocus::OutputDevice => ctx.app.audio.output_list.move_up(),
AudioFocus::InputDevice => ctx.app.audio.input_list.move_up(),
_ => {}
},
KeyCode::Down => match ctx.app.audio.focus {
AudioFocus::OutputDevice => {
let count = ctx.app.audio.output_devices.len();
ctx.app.audio.output_list.move_down(count);
}
AudioFocus::InputDevice => {
let count = ctx.app.audio.input_devices.len();
ctx.app.audio.input_list.move_down(count);
}
_ => {}
},
KeyCode::PageUp => match ctx.app.audio.focus {
AudioFocus::OutputDevice => ctx.app.audio.output_list.page_up(),
AudioFocus::InputDevice => ctx.app.audio.input_list.page_up(),
_ => {}
},
KeyCode::PageDown => match ctx.app.audio.focus {
AudioFocus::OutputDevice => {
let count = ctx.app.audio.output_devices.len();
ctx.app.audio.output_list.page_down(count);
}
AudioFocus::InputDevice => {
let count = ctx.app.audio.input_devices.len();
ctx.app.audio.input_list.page_down(count);
}
_ => {}
},
KeyCode::Enter => match ctx.app.audio.focus {
AudioFocus::OutputDevice => {
let cursor = ctx.app.audio.output_list.cursor;
if cursor < ctx.app.audio.output_devices.len() {
ctx.app.audio.config.output_device =
Some(ctx.app.audio.output_devices[cursor].name.clone());
ctx.app.save_settings(ctx.link);
}
}
AudioFocus::InputDevice => {
let cursor = ctx.app.audio.input_list.cursor;
if cursor < ctx.app.audio.input_devices.len() {
ctx.app.audio.config.input_device =
Some(ctx.app.audio.input_devices[cursor].name.clone());
ctx.app.save_settings(ctx.link);
}
}
_ => {}
},
KeyCode::Left => {
match ctx.app.audio.focus {
AudioFocus::OutputDevice => ctx.app.audio.prev_output_device(),
AudioFocus::InputDevice => ctx.app.audio.prev_input_device(),
AudioFocus::OutputDevice | AudioFocus::InputDevice => {}
AudioFocus::Channels => ctx.app.audio.adjust_channels(-1),
AudioFocus::BufferSize => ctx.app.audio.adjust_buffer_size(-64),
AudioFocus::RefreshRate => ctx.app.audio.toggle_refresh_rate(),
@@ -614,14 +676,16 @@ fn handle_audio_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
.set_start_stop_sync_enabled(!ctx.link.is_start_stop_sync_enabled()),
AudioFocus::Quantum => ctx.link.set_quantum(ctx.link.quantum() - 1.0),
}
if ctx.app.audio.focus != AudioFocus::SamplePaths {
if !matches!(
ctx.app.audio.focus,
AudioFocus::SamplePaths | AudioFocus::OutputDevice | AudioFocus::InputDevice
) {
ctx.app.save_settings(ctx.link);
}
}
KeyCode::Right => {
match ctx.app.audio.focus {
AudioFocus::OutputDevice => ctx.app.audio.next_output_device(),
AudioFocus::InputDevice => ctx.app.audio.next_input_device(),
AudioFocus::OutputDevice | AudioFocus::InputDevice => {}
AudioFocus::Channels => ctx.app.audio.adjust_channels(1),
AudioFocus::BufferSize => ctx.app.audio.adjust_buffer_size(64),
AudioFocus::RefreshRate => ctx.app.audio.toggle_refresh_rate(),
@@ -641,7 +705,10 @@ fn handle_audio_page(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
.set_start_stop_sync_enabled(!ctx.link.is_start_stop_sync_enabled()),
AudioFocus::Quantum => ctx.link.set_quantum(ctx.link.quantum() + 1.0),
}
if ctx.app.audio.focus != AudioFocus::SamplePaths {
if !matches!(
ctx.app.audio.focus,
AudioFocus::SamplePaths | AudioFocus::OutputDevice | AudioFocus::InputDevice
) {
ctx.app.save_settings(ctx.link);
}
}