mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-14 14:26:46 -04:00
Merge pull request #300 from grovebit/bounce-browse
Bounce Mix: Browse for the file, and start in the session folder
This commit is contained in:
3 files changed
+82
-4
No files matched your search
@@ -168,9 +168,15 @@ fn services() -> Services {
|
||||
};
|
||||
d.pick_file().map(|p| p.to_string_lossy().into_owned())
|
||||
})),
|
||||
pick_save: Some(Box::new(|_purpose: &str, default: &str| {
|
||||
pick_save: Some(Box::new(|purpose: &str, default: &str| {
|
||||
let path = std::path::Path::new(default);
|
||||
let mut d = rfd::FileDialog::new().add_filter("SoundCraft Session", &["scraft"]);
|
||||
let mut d = match purpose {
|
||||
"file.bounce_mix" => rfd::FileDialog::new().add_filter("Audio", &["wav", "aif", "aiff", "flac"]),
|
||||
_ => rfd::FileDialog::new().add_filter("SoundCraft Session", &["scraft"]),
|
||||
};
|
||||
if let Some(dir) = path.parent().filter(|dir| dir.is_dir()) {
|
||||
d = d.set_directory(dir);
|
||||
}
|
||||
if let Some(n) = path.file_name().and_then(|n| n.to_str()) {
|
||||
d = d.set_file_name(n);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,13 @@ impl Dialogs {
|
||||
}
|
||||
"session.new" => Dialog::NewSession { name: "Untitled".into(), sample_rate: 48_000, demo: false },
|
||||
"file.bounce_mix" => {
|
||||
Dialog::Bounce { path: format!("{home}/{name} Bounce.wav"), format: "wav".into(), bit_depth: "24".into(), normalize: false }
|
||||
let dir = e
|
||||
.path
|
||||
.as_deref()
|
||||
.and_then(|p| std::path::Path::new(p).parent())
|
||||
.filter(|d| !d.as_os_str().is_empty())
|
||||
.map_or(home.clone(), |d| d.display().to_string());
|
||||
Dialog::Bounce { path: format!("{dir}/{name} Bounce.wav"), format: "wav".into(), bit_depth: "24".into(), normalize: false }
|
||||
}
|
||||
"file.import_audio" => Dialog::PathPrompt { cmd: id.into(), title: "Import Audio".into(), path: home, key: "path".into() },
|
||||
"file.import_midi" => Dialog::PathPrompt { cmd: id.into(), title: "Import MIDI".into(), path: home, key: "path".into() },
|
||||
@@ -346,7 +352,19 @@ pub fn show(app: &mut SoundApp, ctx: &egui::Context) {
|
||||
Dialog::Bounce { path, format, bit_depth, normalize } => {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("File");
|
||||
ui.add(egui::TextEdit::singleline(path).desired_width(360.0));
|
||||
ui.add(egui::TextEdit::singleline(path).desired_width(420.0));
|
||||
if let Some(pick) = &app.services.pick_save
|
||||
&& ui.button("Browse…").clicked()
|
||||
&& let Some(p) = pick("file.bounce_mix", path)
|
||||
{
|
||||
*path = p;
|
||||
match std::path::Path::new(path.as_str()).extension().map(|x| x.to_string_lossy().to_lowercase()).as_deref() {
|
||||
Some("wav") => *format = "wav".into(),
|
||||
Some("aif" | "aiff") => *format = "aiff".into(),
|
||||
Some("flac") => *format = "flac".into(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
egui::ComboBox::from_label("Format").selected_text(format.to_uppercase()).show_ui(ui, |ui| {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//! Bounce Mix starts in the session's folder and has a Browse button for the file (#186).
|
||||
use egui::vec2;
|
||||
use egui_kittest::{Harness, kittest::Queryable};
|
||||
use soundcraft_ui_egui::{Services, SoundApp, dialogs::Dialog};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn bounce_starts_in_the_session_folder_and_browse_picks_the_file_and_format() {
|
||||
let asked = Rc::new(RefCell::new(Vec::new()));
|
||||
let log = Rc::clone(&asked);
|
||||
let pick_save: Box<dyn Fn(&str, &str) -> Option<String>> = Box::new(move |purpose, default| {
|
||||
log.borrow_mut().push((purpose.to_string(), default.to_string()));
|
||||
Some("/Mixes/Final Mix.FLAC".into())
|
||||
});
|
||||
let mut engine = soundcraft_engine::demo::demo_engine();
|
||||
engine.path = Some("/Songs/Midnight Groove/Midnight Groove.scraft".into());
|
||||
let mut app = SoundApp::new(engine, None, Services { pick_save: Some(pick_save), ..Default::default() });
|
||||
assert!(app.dialogs.open_for_command(&app.engine, "file.bounce_mix"));
|
||||
let mut h = Harness::builder().with_size(vec2(1600.0, 1000.0)).build_ui_state(
|
||||
|ui, app: &mut SoundApp| {
|
||||
app.logic(&ui.ctx().clone());
|
||||
app.ui(ui);
|
||||
},
|
||||
app,
|
||||
);
|
||||
h.run_steps(3);
|
||||
h.get_by_label("Browse…").click();
|
||||
h.run_steps(3);
|
||||
let default = "/Songs/Midnight Groove/Midnight Groove Bounce.wav".to_string();
|
||||
assert_eq!(*asked.borrow(), vec![("file.bounce_mix".to_string(), default)]);
|
||||
match &h.state().dialogs.open {
|
||||
Some(Dialog::Bounce { path, format, .. }) => assert_eq!((path.as_str(), format.as_str()), ("/Mixes/Final Mix.FLAC", "flac")),
|
||||
other => panic!("{other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bounce_of_a_session_with_a_relative_path_starts_in_the_default_folder() {
|
||||
let mut engine = soundcraft_engine::demo::demo_engine();
|
||||
engine.path = Some("Midnight Groove.scraft".into());
|
||||
let name = engine.session().name.clone();
|
||||
let mut app = SoundApp::new(engine, None, Services::default());
|
||||
assert!(app.dialogs.open_for_command(&app.engine, "file.bounce_mix"));
|
||||
let mut fresh = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
||||
assert!(fresh.dialogs.open_for_command(&fresh.engine, "file.bounce_mix"));
|
||||
match (&app.dialogs.open, &fresh.dialogs.open) {
|
||||
(Some(Dialog::Bounce { path, .. }), Some(Dialog::Bounce { path: unsaved, .. })) => {
|
||||
assert_ne!(path.as_str(), format!("/{name} Bounce.wav"));
|
||||
assert_eq!(path, unsaved, "the same folder as a session never saved");
|
||||
}
|
||||
other => panic!("{other:?}"),
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user