Feat: UI/UX fixes + removing clones from places
This commit is contained in:
@@ -79,9 +79,6 @@ pub(super) fn handle_main_page(ctx: &mut InputContext, key: KeyEvent, ctrl: bool
|
||||
let current = format!("{:.1}", ctx.link.tempo());
|
||||
ctx.dispatch(AppCommand::OpenModal(Modal::SetTempo(current)));
|
||||
}
|
||||
KeyCode::Char(':') => {
|
||||
ctx.dispatch(AppCommand::OpenModal(Modal::JumpToStep(String::new())));
|
||||
}
|
||||
KeyCode::Char('<') | KeyCode::Char(',') => ctx.dispatch(AppCommand::LengthDecrease),
|
||||
KeyCode::Char('>') | KeyCode::Char('.') => ctx.dispatch(AppCommand::LengthIncrease),
|
||||
KeyCode::Char('[') => ctx.dispatch(AppCommand::SpeedDecrease),
|
||||
|
||||
@@ -179,6 +179,19 @@ fn handle_normal_input(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
|
||||
return InputResult::Continue;
|
||||
}
|
||||
|
||||
if key.code == KeyCode::Char(':') {
|
||||
let in_search = ctx.app.ui.dict_search_active || ctx.app.ui.help_search_active;
|
||||
let in_script = ctx.app.page == Page::Script && ctx.app.script_editor.focused;
|
||||
if !in_search && !in_script {
|
||||
ctx.dispatch(AppCommand::OpenModal(Modal::CommandPalette {
|
||||
input: String::new(),
|
||||
cursor: 0,
|
||||
scroll: 0,
|
||||
}));
|
||||
return InputResult::Continue;
|
||||
}
|
||||
}
|
||||
|
||||
match ctx.app.page {
|
||||
Page::Main => main_page::handle_main_page(ctx, key, ctrl),
|
||||
Page::Patterns => patterns_page::handle_patterns_page(ctx, key),
|
||||
|
||||
@@ -10,6 +10,49 @@ use crate::state::{
|
||||
};
|
||||
|
||||
pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
|
||||
// Handle CommandPalette before the main match to avoid borrow conflicts
|
||||
// (Enter needs &App for palette_entries while the match borrows &mut modal)
|
||||
if let Modal::CommandPalette { input, cursor, scroll } = &mut ctx.app.ui.modal {
|
||||
match key.code {
|
||||
KeyCode::Esc => ctx.dispatch(AppCommand::CloseModal),
|
||||
KeyCode::Char(c) => {
|
||||
input.push(c);
|
||||
*cursor = 0;
|
||||
*scroll = 0;
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
input.pop();
|
||||
*cursor = 0;
|
||||
*scroll = 0;
|
||||
}
|
||||
KeyCode::Up if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
*cursor = cursor.saturating_sub(5);
|
||||
}
|
||||
KeyCode::Down if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
*cursor += 5;
|
||||
}
|
||||
KeyCode::Up => {
|
||||
*cursor = cursor.saturating_sub(1);
|
||||
}
|
||||
KeyCode::Down => {
|
||||
*cursor += 1;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
*cursor = cursor.saturating_sub(10);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
*cursor += 10;
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
let query = input.clone();
|
||||
let cursor_val = *cursor;
|
||||
handle_palette_enter(ctx, &query, cursor_val);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return InputResult::Continue;
|
||||
}
|
||||
|
||||
match &mut ctx.app.ui.modal {
|
||||
Modal::Confirm { action, selected } => {
|
||||
let confirmed = *selected;
|
||||
@@ -179,22 +222,6 @@ pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> Input
|
||||
KeyCode::Char(c) => input.push(c),
|
||||
_ => {}
|
||||
},
|
||||
Modal::JumpToStep(input) => match key.code {
|
||||
KeyCode::Enter => {
|
||||
if let Ok(step) = input.parse::<usize>() {
|
||||
if step > 0 {
|
||||
ctx.dispatch(AppCommand::GoToStep(step - 1));
|
||||
}
|
||||
}
|
||||
ctx.dispatch(AppCommand::CloseModal);
|
||||
}
|
||||
KeyCode::Esc => ctx.dispatch(AppCommand::CloseModal),
|
||||
KeyCode::Backspace => {
|
||||
input.pop();
|
||||
}
|
||||
KeyCode::Char(c) if c.is_ascii_digit() => input.push(c),
|
||||
_ => {}
|
||||
},
|
||||
Modal::SetTempo(input) => match key.code {
|
||||
KeyCode::Enter => {
|
||||
if let Ok(tempo) = input.parse::<f64>() {
|
||||
@@ -514,7 +541,7 @@ pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> Input
|
||||
}
|
||||
}
|
||||
Modal::KeybindingsHelp { scroll } => {
|
||||
let bindings_count = crate::views::keybindings::bindings_for(ctx.app.page, ctx.app.plugin_mode).len();
|
||||
let bindings_count = crate::model::palette::bindings_for(ctx.app.page, ctx.app.plugin_mode).len();
|
||||
match key.code {
|
||||
KeyCode::Esc | KeyCode::Char('?') => ctx.dispatch(AppCommand::CloseModal),
|
||||
KeyCode::Up | KeyCode::Char('k') => {
|
||||
@@ -636,6 +663,7 @@ pub(super) fn handle_modal_input(ctx: &mut InputContext, key: KeyEvent) -> Input
|
||||
_ => ctx.dispatch(AppCommand::CloseModal),
|
||||
}
|
||||
}
|
||||
Modal::CommandPalette { .. } => unreachable!(),
|
||||
Modal::None => unreachable!(),
|
||||
}
|
||||
InputResult::Continue
|
||||
@@ -670,6 +698,97 @@ fn execute_confirm(ctx: &mut InputContext, action: &ConfirmAction) -> InputResul
|
||||
InputResult::Continue
|
||||
}
|
||||
|
||||
fn handle_palette_enter(ctx: &mut InputContext, query: &str, cursor: usize) {
|
||||
let page = ctx.app.page;
|
||||
let plugin_mode = ctx.app.plugin_mode;
|
||||
|
||||
// Numeric input on Main page → jump to step
|
||||
if page == crate::page::Page::Main
|
||||
&& !query.is_empty()
|
||||
&& query.chars().all(|c| c.is_ascii_digit())
|
||||
{
|
||||
if let Ok(step) = query.parse::<usize>() {
|
||||
if step > 0 {
|
||||
ctx.dispatch(AppCommand::GoToStep(step - 1));
|
||||
}
|
||||
}
|
||||
ctx.dispatch(AppCommand::CloseModal);
|
||||
return;
|
||||
}
|
||||
|
||||
let entries = crate::model::palette::palette_entries(query, plugin_mode, ctx.app);
|
||||
if let Some(entry) = entries.get(cursor) {
|
||||
ctx.dispatch(AppCommand::CloseModal);
|
||||
execute_palette_entry(ctx, entry);
|
||||
} else {
|
||||
ctx.dispatch(AppCommand::CloseModal);
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_palette_entry(
|
||||
ctx: &mut InputContext,
|
||||
entry: &crate::model::palette::CommandEntry,
|
||||
) {
|
||||
use crate::model::palette::PaletteAction;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
match &entry.action {
|
||||
Some(PaletteAction::Resolve(f)) => {
|
||||
if let Some(cmd) = f(ctx.app) {
|
||||
ctx.dispatch(cmd);
|
||||
}
|
||||
}
|
||||
Some(PaletteAction::Save) => super::open_save(ctx),
|
||||
Some(PaletteAction::Load) => super::open_load(ctx),
|
||||
Some(PaletteAction::TogglePlaying) => {
|
||||
ctx.dispatch(AppCommand::TogglePlaying);
|
||||
ctx.playing
|
||||
.store(ctx.app.playback.playing, Ordering::Relaxed);
|
||||
}
|
||||
Some(PaletteAction::MuteToggle) => {
|
||||
let (bank, pattern) = (ctx.app.editor_ctx.bank, ctx.app.editor_ctx.pattern);
|
||||
ctx.app.playback.toggle_mute(bank, pattern);
|
||||
ctx.app.send_mute_state(ctx.seq_cmd_tx);
|
||||
}
|
||||
Some(PaletteAction::SoloToggle) => {
|
||||
let (bank, pattern) = (ctx.app.editor_ctx.bank, ctx.app.editor_ctx.pattern);
|
||||
ctx.app.playback.toggle_solo(bank, pattern);
|
||||
ctx.app.send_mute_state(ctx.seq_cmd_tx);
|
||||
}
|
||||
Some(PaletteAction::ClearMutes) => {
|
||||
ctx.dispatch(AppCommand::ClearMutes);
|
||||
ctx.app.send_mute_state(ctx.seq_cmd_tx);
|
||||
}
|
||||
Some(PaletteAction::ClearSolos) => {
|
||||
ctx.dispatch(AppCommand::ClearSolos);
|
||||
ctx.app.send_mute_state(ctx.seq_cmd_tx);
|
||||
}
|
||||
Some(PaletteAction::Hush) => {
|
||||
let _ = ctx
|
||||
.audio_tx
|
||||
.load()
|
||||
.send(crate::engine::AudioCommand::Hush);
|
||||
}
|
||||
Some(PaletteAction::Panic) => {
|
||||
let _ = ctx
|
||||
.audio_tx
|
||||
.load()
|
||||
.send(crate::engine::AudioCommand::Panic);
|
||||
let _ = ctx.seq_cmd_tx.send(SeqCommand::StopAll);
|
||||
}
|
||||
Some(PaletteAction::TestTone) => {
|
||||
let _ = ctx
|
||||
.audio_tx
|
||||
.load()
|
||||
.send(crate::engine::AudioCommand::Evaluate {
|
||||
cmd: "/sound/sine/dur/0.5/decay/0.2".into(),
|
||||
time: None,
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn rename_command(target: &RenameTarget, name: Option<String>) -> AppCommand {
|
||||
match target {
|
||||
RenameTarget::Bank { bank } => AppCommand::RenameBank { bank: *bank, name },
|
||||
|
||||
@@ -986,7 +986,8 @@ fn handle_modal_click(ctx: &mut InputContext, col: u16, row: u16, term: Rect) {
|
||||
Modal::FileBrowser(_) | Modal::AddSamplePath(_) => (60, 18),
|
||||
Modal::Rename { .. } => (40, 5),
|
||||
Modal::SetPattern { .. } | Modal::SetScript { .. } => (45, 5),
|
||||
Modal::SetTempo(_) | Modal::JumpToStep(_) => (30, 5),
|
||||
Modal::SetTempo(_) => (30, 5),
|
||||
Modal::CommandPalette { .. } => (55, 20),
|
||||
_ => return,
|
||||
};
|
||||
let modal_area = centered_rect(term, w, h);
|
||||
|
||||
Reference in New Issue
Block a user