mirror of
https://github.com/storytold/soundcraft.git
synced 2026-11-14 14:22:10 +00:00
Merge pull request #1291 from ljkx/new-send-opens-send-window
A new send opens its Send window, so its fader is on screen right away
This commit is contained in:
2 files changed
+119
-5
No files matched your search
@@ -388,8 +388,17 @@ fn send_route_menu(app: &mut SoundApp, ui: &Ui, field: &egui::Response, id: Trac
|
||||
},
|
||||
);
|
||||
let Some((picked, footer)) = shown else { return };
|
||||
if let Some(bus) = picked {
|
||||
let _ = app.run("mix.send", json!({"track": id.0, "slot": slot, "bus": bus}));
|
||||
// As in Pro Tools, a new send opens its Send window (moving it from any other send), so its
|
||||
// fader is on screen right away. A send that only changes destination leaves the window alone.
|
||||
let show_new_send = |app: &mut SoundApp| {
|
||||
if !has_send {
|
||||
app.ui.send_window = Some((id, slot));
|
||||
}
|
||||
};
|
||||
if let Some(bus) = picked
|
||||
&& app.run("mix.send", json!({"track": id.0, "slot": slot, "bus": bus})).is_ok()
|
||||
{
|
||||
show_new_send(app);
|
||||
}
|
||||
match footer {
|
||||
Some(SendFooter::NewBus) => {
|
||||
@@ -399,8 +408,10 @@ fn send_route_menu(app: &mut SoundApp, ui: &Ui, field: &egui::Response, id: Trac
|
||||
{
|
||||
n += 1;
|
||||
}
|
||||
if app.run("mix.new_bus", json!({"name": format!("Bus {n}")})).is_ok() {
|
||||
let _ = app.run("mix.send", json!({"track": id.0, "slot": slot, "bus": format!("Bus {n}")}));
|
||||
if app.run("mix.new_bus", json!({"name": format!("Bus {n}")})).is_ok()
|
||||
&& app.run("mix.send", json!({"track": id.0, "slot": slot, "bus": format!("Bus {n}")})).is_ok()
|
||||
{
|
||||
show_new_send(app);
|
||||
}
|
||||
}
|
||||
Some(SendFooter::RemoveSend) => {
|
||||
@@ -464,4 +475,79 @@ mod tests {
|
||||
assert_eq!(field(&h), search, "the search field stays put");
|
||||
assert!((footer(&h).top() - full.top()).abs() < 1.0, "cleared, the footer is back under the full list: {:?} vs {full:?}", footer(&h));
|
||||
}
|
||||
|
||||
/// Kick's send A slot in a test harness, with buses "Aux" and "Other"; with `existing_send`, the
|
||||
/// slot already sends to "Other".
|
||||
fn kick_send_harness(existing_send: bool) -> (Harness<'static, (SoundApp, TrackId)>, TrackId) {
|
||||
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
|
||||
app.run("mix.new_bus", json!({"name": "Aux"})).unwrap();
|
||||
app.run("mix.new_bus", json!({"name": "Other"})).unwrap();
|
||||
let kick = app.engine.session().track_by_name("Kick").unwrap().id;
|
||||
if existing_send {
|
||||
app.run("mix.send", json!({"track": kick.0, "slot": 0, "bus": "Other"})).unwrap();
|
||||
}
|
||||
let mut ready = false;
|
||||
let h = Harness::builder().with_size(vec2(600.0, 800.0)).build_ui_state(
|
||||
move |ui, (app, kick): &mut (SoundApp, TrackId)| {
|
||||
if !ready {
|
||||
crate::fonts::install(ui.ctx(), true);
|
||||
crate::theme::apply(ui.ctx(), false);
|
||||
ready = true;
|
||||
return;
|
||||
}
|
||||
let track = app.engine.session().track(*kick).cloned().unwrap();
|
||||
let r = Rect::from_min_size(ui.max_rect().min + vec2(20.0, 20.0), vec2(120.0, 24.0));
|
||||
send_slot(app, ui, &track, 0, r);
|
||||
},
|
||||
(app, kick),
|
||||
);
|
||||
(h, kick)
|
||||
}
|
||||
|
||||
/// Creating a send opens its Send window, so the new send's fader is on screen right away (#1269).
|
||||
#[test]
|
||||
fn creating_a_send_opens_its_send_window() {
|
||||
let _palette = crate::theme::lock_test_palette();
|
||||
let (mut h, kick) = kick_send_harness(false);
|
||||
h.run();
|
||||
h.get_by_label("Send A for Kick").click();
|
||||
h.run();
|
||||
h.get_by_label("Aux").click();
|
||||
h.run();
|
||||
let (app, _) = h.state();
|
||||
let send = app.engine.session().track(kick).and_then(|t| t.mixer.sends.first().cloned().flatten());
|
||||
assert!(send.is_some(), "the send was created");
|
||||
assert_eq!(app.ui.send_window, Some((kick, 0)), "the new send's window is open");
|
||||
}
|
||||
|
||||
/// So does a send made with "new bus...".
|
||||
#[test]
|
||||
fn a_send_to_a_new_bus_opens_its_send_window() {
|
||||
let _palette = crate::theme::lock_test_palette();
|
||||
let (mut h, kick) = kick_send_harness(false);
|
||||
h.run();
|
||||
h.get_by_label("Send A for Kick").click();
|
||||
h.run();
|
||||
h.get_by_label("new bus...").click();
|
||||
h.run();
|
||||
let (app, _) = h.state();
|
||||
assert!(app.engine.session().track(kick).and_then(|t| t.mixer.sends.first().cloned().flatten()).is_some(), "the send was created");
|
||||
assert_eq!(app.ui.send_window, Some((kick, 0)), "the new send's window is open");
|
||||
}
|
||||
|
||||
/// Moving an existing send to another bus keeps the Send window as it was.
|
||||
#[test]
|
||||
fn changing_a_sends_destination_leaves_the_send_window_alone() {
|
||||
let _palette = crate::theme::lock_test_palette();
|
||||
let (mut h, kick) = kick_send_harness(true);
|
||||
h.run();
|
||||
h.get_by_label("Send A for Kick").click();
|
||||
h.run();
|
||||
h.get_by_label("Aux").click();
|
||||
h.run();
|
||||
let (app, _) = h.state();
|
||||
let target = app.engine.session().track(kick).and_then(|t| t.mixer.sends.first().cloned().flatten()).map(|s| route_name(app, &s.target));
|
||||
assert_eq!(target.as_deref(), Some("Aux"), "the send moved");
|
||||
assert_eq!(app.ui.send_window, None, "no window opened");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
//! A send's level opens its Send window, as in Pro Tools: a fader with Alt-click for 0 dB, moved to
|
||||
//! another send by clicking that send's level, closed by clicking the same one again.
|
||||
//! another send by clicking that send's level, closed by clicking the same one again. Creating a send
|
||||
//! opens it too.
|
||||
|
||||
use egui::{Event, Modifiers, PointerButton, Pos2, vec2};
|
||||
use egui_kittest::Harness;
|
||||
@@ -75,6 +76,33 @@ fn a_sends_level_opens_its_send_window() {
|
||||
assert!(h.query_by_label_contains("Vox · Send").is_none());
|
||||
}
|
||||
|
||||
/// Creating a send opens its Send window, so the new send's fader is on screen right away (#1269). The
|
||||
/// window moves there from the send it was showing, and undoing the new send closes it.
|
||||
#[test]
|
||||
fn a_new_send_shows_its_fader_at_once() {
|
||||
let (mut h, vox) = harness();
|
||||
h.get_by_label("Send A level for Vox").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.query_by_label_contains("Vox · Send A").is_some());
|
||||
|
||||
h.get_by_label("Send C for Vox").click();
|
||||
h.run_steps(3);
|
||||
// Send A's own "Verb" label is on screen too, so pick the menu's button.
|
||||
h.get_by_role_and_label(egui::accesskit::Role::Button, "Verb").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().engine.session().tracks[0].mixer.sends[2].is_some(), "send C was created");
|
||||
assert_eq!(h.state().ui.send_window, Some((vox, 2)));
|
||||
assert!(h.query_by_label_contains("Vox · Send C").is_some(), "the window shows the new send");
|
||||
assert!(h.query_by_label_contains("Vox · Send A").is_none(), "and no longer send A");
|
||||
assert!(h.query_by_label("Send level").is_some(), "the new send's fader is on screen");
|
||||
|
||||
h.state_mut().engine.execute("edit.undo", &json!({})).unwrap();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().engine.session().tracks[0].mixer.sends[2].is_none(), "the send was undone");
|
||||
assert_eq!(h.state().ui.send_window, None, "undoing the send closes its window");
|
||||
assert!(h.query_by_label_contains("Vox · Send").is_none());
|
||||
}
|
||||
|
||||
/// Escape first closes a send menu or cancels level typing, then a further Escape closes the send window.
|
||||
#[test]
|
||||
fn escape_closes_the_send_window_after_menus_and_typing() {
|
||||
|
||||
Reference in new issue
Block a user