From 569aa3bb414d5b8e523e8f486539eac1fbbca1ac Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 6 Oct 2026 00:01:18 -0400 Subject: [PATCH] Groups: create dialog with members and edit/mix options; Groups list context menu Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/dialogs.rs | 28 +++++++++++++++++++++++----- crates/ui-egui/src/panels.rs | 30 +++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 8259fe36..d8aa99f9 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -18,7 +18,7 @@ pub enum Dialog { Number { cmd: String, title: String, key: String, value: f64, suffix: String }, Fades { shape: String }, StripSilence { threshold: f64, min_ms: f64, pre_ms: f64, post_ms: f64 }, - Group { name: String }, + Group { name: String, edit: bool, mix: bool, members: Vec<(u64, String, bool)> }, Session { frame_rate: String, bit_depth: String }, } @@ -85,7 +85,11 @@ impl Dialogs { } "edit.fades_create" => Dialog::Fades { shape: "equal power".into() }, "edit.strip_silence" => Dialog::StripSilence { threshold: -48.0, min_ms: 50.0, pre_ms: 5.0, post_ms: 20.0 }, - "track.group" => Dialog::Group { name: format!("Group {}", e.session().groups.len() + 1) }, + "track.group" => { + let s = e.session(); + let members = s.tracks.iter().map(|t| (t.id.0, t.name.clone(), s.edit.selected_tracks.contains(&t.id))).collect(); + Dialog::Group { name: format!("Group {}", s.groups.len() + 1), edit: true, mix: true, members } + } "setup.session" => Dialog::Session { frame_rate: e.session().frame_rate.label().into(), bit_depth: "24".into() }, _ => { return false; @@ -286,10 +290,24 @@ pub fn show(app: &mut SoundApp, ctx: &egui::Context) { )); } } - Dialog::Group { name } => { - ui.text_edit_singleline(name); + Dialog::Group { name, edit, mix, members } => { + ui.horizontal(|ui| { + ui.label("Name"); + ui.text_edit_singleline(name); + }); + ui.horizontal(|ui| { + ui.checkbox(edit, "Edit group"); + ui.checkbox(mix, "Mix group"); + }); + ui.label("Tracks"); + egui::ScrollArea::vertical().max_height(180.0).show(ui, |ui| { + for (_, n, on) in members.iter_mut() { + ui.checkbox(on, n.as_str()); + } + }); if buttons(ui, "OK", enter) { - action = Some(("track.group".into(), json!({"name": name}))); + let ids: Vec = members.iter().filter(|m| m.2).map(|m| m.0).collect(); + action = Some(("track.group".into(), json!({"name": name, "edit": edit, "mix": mix, "tracks": ids}))); } } Dialog::Session { frame_rate, bit_depth } => { diff --git a/crates/ui-egui/src/panels.rs b/crates/ui-egui/src/panels.rs index 07cf1375..d64bde36 100644 --- a/crates/ui-egui/src/panels.rs +++ b/crates/ui-egui/src/panels.rs @@ -53,6 +53,16 @@ pub fn tracks_and_groups(app: &mut SoundApp, ui: &mut Ui) { egui::ScrollArea::vertical().id_salt("groups_scroll").auto_shrink([false, false]).show(ui, |ui| { let (r, _) = ui.allocate_exact_size(vec2(ui.available_width(), 17.0), Sense::hover()); ui.painter().text(pos2(r.min.x + 30.0, r.center().y), Align2::LEFT_CENTER, "", regular(11.5).clone(), t.text); + let all = ui.interact(r, ui.id().with("group_all"), Sense::click()); + if all.double_clicked() { + let _ = app.run("edit.select_all", json!({})); + } + all.context_menu(|ui| { + if ui.button("New Group…").clicked() { + let _ = app.dialogs.open_for_command(&app.engine, "track.group"); + ui.close(); + } + }); for (id, letter, name, active, color) in groups { let (r, resp) = ui.allocate_exact_size(vec2(ui.available_width(), 17.0), Sense::click()); if active { @@ -69,11 +79,25 @@ pub fn tracks_and_groups(app: &mut SoundApp, ui: &mut Ui) { if resp.clicked() { let _ = app.run("track.group_toggle", json!({"group": id})); } + let members: Vec = + app.engine.session().groups.iter().find(|g| g.id.0 == id).map(|g| g.members.iter().map(|m| m.0).collect()).unwrap_or_default(); if resp.double_clicked() { - let members: Vec = - app.engine.session().groups.iter().find(|g| g.id.0 == id).map(|g| g.members.iter().map(|m| m.0).collect()).unwrap_or_default(); - let _ = app.run("edit.select", json!({"tracks": members})); + let _ = app.run("edit.select", json!({"tracks": members, "exact": true})); } + resp.context_menu(|ui| { + if ui.button("Select Tracks in Group").clicked() { + let _ = app.run("edit.select", json!({"tracks": members, "exact": true})); + ui.close(); + } + if ui.button(if active { "Disable" } else { "Enable" }).clicked() { + let _ = app.run("track.group_toggle", json!({"group": id})); + ui.close(); + } + if ui.button("Delete Group").clicked() { + let _ = app.run("track.ungroup", json!({"group": id})); + ui.close(); + } + }); } }); }