Compare commits

...

2 Commits

Author SHA1 Message Date
Tarasov Aleksandr 78960cdc10 Refactor draw_files and draw_tree_node to improve maintainability and readability (#108)
- Extracted search field rendering to `draw_files_search_field`
- Extracted list rendering to `draw_files_list`
- Split `draw_tree_node` file and directory branch logic to `draw_tree_node_file` and `draw_tree_node_dir`

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-17 17:07:32 +03:00
Tarasov Aleksandr 0439cf815e perf: eliminate redundant PathBuf clone in GUI directory list (#110)
This commit optimizes the GUI render loop in `src/gui/draw.rs` during the rendering of the drag and drop directory list. Previously, `self.app_state.dirs.clone()` was cloning the entire vector of `PathBuf`s on every frame, which caused unnecessary allocations.

Now, `std::mem::take` temporarily removes the list of directories from `app_state.dirs` inside `show_vec`, and items are passed by reference rather than being cloned (`let path = item;` instead of `item.clone()`). Finally, the original list is restored into `app_state.dirs`. To ensure the state doesn't mutate or invalidate when `self.open_dir(&path)` is clicked, this logic has been deferred to run after the `app_state` vector is restored.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2026-05-17 17:07:04 +03:00
+43 -12
View File
@@ -673,10 +673,11 @@ impl SoundpadGui {
ScrollArea::vertical().id_salt(0).show(ui, |ui| {
ui.set_min_width(area_size.x);
let mut dirs = self.app_state.dirs.clone();
let mut dirs = std::mem::take(&mut self.app_state.dirs);
let mut dir_to_open = None;
dnd(ui, "dnd_directories").show_vec(&mut dirs, |ui, item, handle, _state| {
let path = item.clone();
let path = item;
ui.horizontal(|ui| {
handle.ui(ui, |ui| {
ui.label(ICON_DRAG_INDICATOR.codepoint);
@@ -688,7 +689,7 @@ impl SoundpadGui {
let mut dir_button_text = RichText::new(name.clone());
if let Some(current_dir) = &self.app_state.current_dir
&& current_dir.eq(&path)
&& current_dir.eq(&*path)
{
dir_button_text = dir_button_text.color(Color32::WHITE);
}
@@ -698,7 +699,7 @@ impl SoundpadGui {
let dir_button_response = ui.add(dir_button);
if dir_button_response.clicked() {
self.open_dir(&path);
dir_to_open = Some(path.clone());
}
let delete_dir_button = Button::new(ICON_DELETE).frame(false);
@@ -718,7 +719,7 @@ impl SoundpadGui {
))
.clicked()
{
self.open_dir(&path);
dir_to_open = Some(path.clone());
}
if ui
@@ -750,6 +751,10 @@ impl SoundpadGui {
});
self.app_state.dirs = dirs;
if let Some(path) = dir_to_open {
self.open_dir(&path);
}
ui.horizontal(|ui| {
let add_dirs_button = Button::new(ICON_ADD).frame(false);
let add_dirs_button_response = ui.add_sized([18.0, 18.0], add_dirs_button);
@@ -769,8 +774,7 @@ impl SoundpadGui {
});
}
fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) {
ui.vertical(|ui| {
fn draw_files_search_field(&mut self, ui: &mut Ui) {
ui.horizontal(|ui| {
let search_field_response = ui.add_sized(
[ui.available_width(), 22.0],
@@ -785,9 +789,9 @@ impl SoundpadGui {
self.app_state.search_field_id = Some(search_field_response.id);
});
}
ui.separator();
fn draw_files_list(&mut self, ui: &mut Ui, area_size: Vec2) {
ScrollArea::vertical().id_salt(1).show(ui, |ui| {
ui.set_min_width(area_size.x);
ui.set_min_height(area_size.y);
@@ -820,17 +824,23 @@ impl SoundpadGui {
}
});
});
}
fn draw_files(&mut self, ui: &mut Ui, area_size: Vec2) {
ui.vertical(|ui| {
self.draw_files_search_field(ui);
ui.separator();
self.draw_files_list(ui, area_size);
});
}
fn draw_tree_node(
fn draw_tree_node_dir(
ui: &mut Ui,
path: std::path::PathBuf,
app_state: &mut AppState,
audio_player_state: &AudioPlayerState,
actions: &mut Vec<FileAction>,
) {
if path.is_dir() {
let dir_name = path
.file_name()
.unwrap_or_default()
@@ -891,7 +901,15 @@ impl SoundpadGui {
Self::draw_tree_node(ui, child, app_state, audio_player_state, actions);
}
});
} else {
}
fn draw_tree_node_file(
ui: &mut Ui,
path: std::path::PathBuf,
app_state: &mut AppState,
audio_player_state: &AudioPlayerState,
actions: &mut Vec<FileAction>,
) {
let file_name = path
.file_name()
.unwrap_or_default()
@@ -1012,6 +1030,19 @@ impl SoundpadGui {
});
});
}
fn draw_tree_node(
ui: &mut Ui,
path: std::path::PathBuf,
app_state: &mut AppState,
audio_player_state: &AudioPlayerState,
actions: &mut Vec<FileAction>,
) {
if path.is_dir() {
Self::draw_tree_node_dir(ui, path, app_state, audio_player_state, actions);
} else {
Self::draw_tree_node_file(ui, path, app_state, audio_player_state, actions);
}
}
fn draw_footer(&mut self, ui: &mut Ui) {