refactor: enhance search field focus functionality and input handling

This commit is contained in:
2026-01-28 00:28:08 +03:00
parent 6df826f210
commit 03df631690
4 changed files with 103 additions and 101 deletions
+7 -2
View File
@@ -356,12 +356,17 @@ impl SoundpadGui {
fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) { fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) {
ui.vertical(|ui| { ui.vertical(|ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {
let search_field = ui.add_sized( let search_field_response = ui.add_sized(
[ui.available_width(), 22.0], [ui.available_width(), 22.0],
TextEdit::singleline(&mut self.app_state.search_query).hint_text("Search..."), TextEdit::singleline(&mut self.app_state.search_query).hint_text("Search..."),
); );
self.app_state.search_field_id = Some(search_field.id); if self.app_state.force_focus_search {
search_field_response.request_focus();
self.app_state.force_focus_search = false;
}
self.app_state.search_field_id = Some(search_field_response.id);
}); });
ui.separator(); ui.separator();
+93 -89
View File
@@ -1,122 +1,126 @@
use crate::gui::SoundpadGui; use crate::gui::SoundpadGui;
use egui::{Context, Key}; use egui::{Context, Id, Key, Modifiers};
use std::path::PathBuf; use std::path::PathBuf;
impl SoundpadGui { impl SoundpadGui {
fn key_pressed(&self, ctx: &Context, key: Key) -> bool {
ctx.input(|i| i.key_pressed(key))
}
fn modifiers(&self, ctx: &Context) -> Modifiers {
ctx.input(|i| i.modifiers)
}
pub fn handle_input(&mut self, ctx: &Context) { pub fn handle_input(&mut self, ctx: &Context) {
if ctx.memory(|reader| { reader.focused() }.is_some()) { let modifiers = self.modifiers(ctx);
return;
// Close app on espace
if self.key_pressed(ctx, Key::Escape) {
std::process::exit(0);
} }
ctx.input(|i| { // Open/close settings
// Close app on espace if self.key_pressed(ctx, Key::I) {
if i.key_pressed(Key::Escape) { self.app_state.show_settings = !self.app_state.show_settings;
std::process::exit(0); }
if self.key_pressed(ctx, Key::Enter) && self.app_state.selected_file.is_some() {
let path = &self.app_state.selected_file.clone().unwrap();
if modifiers.ctrl {
self.play_file(path, true);
} else if modifiers.shift
&& let Some(last_track) = self.audio_player_state.tracks.last()
{
self.stop(Some(last_track.id));
self.play_file(path, true);
} else {
self.play_file(path, false);
}
}
if !self.app_state.show_settings {
// Pause / resume audio on space
if self.key_pressed(ctx, Key::Space) {
self.play_toggle();
} }
// Open/close settings // Stop all audio tracks on backspace
if i.key_pressed(Key::I) { if self.key_pressed(ctx, Key::Backspace) {
self.app_state.show_settings = !self.app_state.show_settings; self.stop(None);
} }
if i.key_pressed(Key::Enter) && self.app_state.selected_file.is_some() { // Focus search field
let path = &self.app_state.selected_file.clone().unwrap(); if self.key_pressed(ctx, Key::Slash) {
if i.modifiers.ctrl { self.app_state.force_focus_search = true;
self.play_file(path, true);
} else if i.modifiers.shift
&& let Some(last_track) = self.audio_player_state.tracks.last()
{
self.stop(Some(last_track.id));
self.play_file(path, true);
} else {
self.play_file(path, false);
}
} }
if !self.app_state.show_settings { // Iterate through dirs if there are some
// Pause / resume audio on space if modifiers.ctrl {
if i.key_pressed(Key::Space) { let arrow_up_pressed = self.key_pressed(ctx, Key::ArrowUp);
self.play_toggle(); let arrow_down_pressed = self.key_pressed(ctx, Key::ArrowDown);
}
// Stop all audio tracks on backspace if arrow_up_pressed || arrow_down_pressed {
if i.key_pressed(Key::Backspace) { if modifiers.shift && !self.app_state.dirs.is_empty() {
self.stop(None); let mut dirs: Vec<PathBuf> = self.app_state.dirs.iter().cloned().collect();
} dirs.sort();
// Focus search field let current_dir_index: i8;
if i.key_pressed(Key::Slash) && self.app_state.search_field_id.is_some() { if let Some(current_dir) = &self.app_state.current_dir {
self.app_state.force_focus_id = self.app_state.search_field_id; if let Some(index) = dirs.iter().position(|x| x == current_dir) {
} current_dir_index = index as i8;
// Iterate through dirs if there are some
if i.modifiers.ctrl {
let arrow_up_pressed = i.key_pressed(Key::ArrowUp);
let arrow_down_pressed = i.key_pressed(Key::ArrowDown);
if arrow_up_pressed || arrow_down_pressed {
if i.modifiers.shift && !self.app_state.dirs.is_empty() {
let mut dirs: Vec<PathBuf> =
self.app_state.dirs.iter().cloned().collect();
dirs.sort();
let current_dir_index: i8;
if let Some(current_dir) = &self.app_state.current_dir {
if let Some(index) = dirs.iter().position(|x| x == current_dir) {
current_dir_index = index as i8;
} else {
current_dir_index = -1;
}
} else { } else {
current_dir_index = -1; current_dir_index = -1;
} }
} else {
current_dir_index = -1;
}
let mut new_dir_index: i8; let mut new_dir_index: i8;
new_dir_index = current_dir_index - arrow_up_pressed as i8 new_dir_index =
+ arrow_down_pressed as i8; current_dir_index - arrow_up_pressed as i8 + arrow_down_pressed as i8;
if new_dir_index < 0 { if new_dir_index < 0 {
new_dir_index = (dirs.len() - 1) as i8; new_dir_index = (dirs.len() - 1) as i8;
} else if new_dir_index >= dirs.len() as i8 { } else if new_dir_index >= dirs.len() as i8 {
new_dir_index = 0; new_dir_index = 0;
} }
self.open_dir(&dirs[new_dir_index as usize]); self.open_dir(&dirs[new_dir_index as usize]);
} else if self.app_state.current_dir.is_some() { } else if self.app_state.current_dir.is_some() {
let mut files: Vec<PathBuf> = let mut files: Vec<PathBuf> =
self.app_state.files.iter().cloned().collect(); self.app_state.files.iter().cloned().collect();
files.sort(); files.sort();
let current_files_index: i64; let current_files_index: i64;
if let Some(selected_file) = &self.app_state.selected_file { if let Some(selected_file) = &self.app_state.selected_file {
if let Some(index) = files.iter().position(|x| x == selected_file) { if let Some(index) = files.iter().position(|x| x == selected_file) {
current_files_index = index as i64; current_files_index = index as i64;
} else {
current_files_index = -1;
}
} else { } else {
current_files_index = -1; current_files_index = -1;
} }
} else {
let mut new_files_index: i64; current_files_index = -1;
new_files_index = current_files_index - arrow_up_pressed as i64
+ arrow_down_pressed as i64;
if new_files_index < 0 {
new_files_index = (files.len() - 1) as i64;
} else if new_files_index >= files.len() as i64 {
new_files_index = 0;
}
self.app_state.selected_file =
Some(files[new_files_index as usize].clone());
} }
let mut new_files_index: i64;
new_files_index = current_files_index - arrow_up_pressed as i64
+ arrow_down_pressed as i64;
if new_files_index < 0 {
new_files_index = (files.len() - 1) as i64;
} else if new_files_index >= files.len() as i64 {
new_files_index = 0;
}
self.app_state.selected_file =
Some(files[new_files_index as usize].clone());
} }
} }
} }
}); }
// });
} }
} }
-7
View File
@@ -86,13 +86,6 @@ impl App for SoundpadGui {
} }
self.draw(ui).ok(); self.draw(ui).ok();
if let Some(force_focus_id) = self.app_state.force_focus_id {
ui.memory_mut(|reder| {
reder.request_focus(force_focus_id);
});
self.app_state.force_focus_id = None;
}
}); });
ctx.request_repaint_after_secs(1.0 / 60.0); ctx.request_repaint_after_secs(1.0 / 60.0);
+3 -3
View File
@@ -28,9 +28,12 @@ pub struct AppState {
pub show_settings: bool, pub show_settings: bool,
pub volume_dragged: bool, pub volume_dragged: bool,
pub force_focus_search: bool,
pub volume_slider_value: f32, pub volume_slider_value: f32,
pub search_field_id: Option<Id>,
pub ignore_volume_update_until: Option<Instant>, pub ignore_volume_update_until: Option<Instant>,
pub current_dir: Option<PathBuf>, pub current_dir: Option<PathBuf>,
@@ -38,9 +41,6 @@ pub struct AppState {
pub selected_file: Option<PathBuf>, pub selected_file: Option<PathBuf>,
pub files: HashSet<PathBuf>, pub files: HashSet<PathBuf>,
pub search_field_id: Option<Id>,
pub force_focus_id: Option<Id>,
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]