From ea531b723f06a9cfda60072774eec2f1b85f39eb Mon Sep 17 00:00:00 2001 From: Limestudio90 Date: Mon, 12 Oct 2026 18:47:18 +0200 Subject: [PATCH 1/3] Mix in a separate window: Edit and Mix on screen at once Window > Mix in Separate Window (window.mix_separate, kept with the UI preferences) shows the Mix window in its own native window through an egui immediate viewport, so Edit and Mix can be seen at once, e.g. one per monitor. The main window then keeps Edit; Window > Mix and Cmd/Ctrl+= bring the Mix window to the front; closing it puts Mix back into the main window. Backends without multiple windows show it as a floating egui window. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/lib.rs | 13 ++++++++++++- crates/ui-egui/src/menus.rs | 28 ++++++++++++++++++++++++++-- crates/ui-egui/src/mix_window.rs | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index e0e2f2b..716adf1 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -88,6 +88,9 @@ pub struct UiState { pub show_workspace: bool, pub show_configurations: bool, pub show_playback_engine: bool, + /// The Mix window lives in its own native window (Window › Mix in Separate Window); the main + /// window then always shows Edit. + pub mix_separate: bool, pub show_io_setup: bool, pub show_shortcuts: bool, pub show_clip_effects: bool, @@ -149,6 +152,7 @@ impl Default for UiState { show_workspace: false, show_configurations: false, show_playback_engine: false, + mix_separate: false, show_io_setup: false, show_shortcuts: false, show_clip_effects: false, @@ -253,6 +257,8 @@ pub struct SoundApp { pub ops: ops_windows::OpsState, pub extra: extra_windows::ExtraState, pub palette: palette::PaletteState, + /// Bring the separate Mix window to the front on the next frame. + pub(crate) focus_mix: bool, pub synthetic: Vec, synthetic_grace: u32, control_rx: Option>, @@ -322,6 +328,7 @@ impl SoundApp { ops: ops_windows::OpsState::default(), extra: extra_windows::ExtraState::default(), palette: palette::PaletteState::default(), + focus_mix: false, synthetic: Vec::new(), synthetic_grace: 0, control_rx: None, @@ -929,10 +936,14 @@ impl SoundApp { if !self.native_menu_bar { menus::menu_bar(self, ui); } - match self.ui.window { + // With the Mix window in its own native window, the main window keeps Edit. + match if self.ui.mix_separate { MainWindow::Edit } else { self.ui.window } { MainWindow::Edit => edit_window::show(self, ui), MainWindow::Mix => mix_window::show(self, ui), } + if self.ui.mix_separate { + mix_window::show_separate(self, &ctx); + } panels::floating(self, &ctx); windows::show(self, &ctx); video_window::show(self, &ctx); diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 3c20019..61d5052 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -12,6 +12,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, Option<&str>)] = &[ ("window.mix", "Mix", "Window > Mix", Some("Cmd+=")), ("window.edit", "Edit", "Window > Edit", Some("Cmd+=")), ("window.toggle_mix_edit", "Toggle Mix/Edit", "", Some("Cmd+=")), + ("window.mix_separate", "Mix in Separate Window", "", None), ("window.transport", "Transport", "Window > Transport", Some("Cmd+1")), ("window.big_counter", "Big Counter", "Window > Big Counter", Some("Cmd+3")), ("window.memory_locations", "Memory Locations", "Window > Memory Locations", Some("Cmd+5")), @@ -243,13 +244,25 @@ pub fn menu_bar(app: &mut SoundApp, ui: &mut egui::Ui) { ui.separator(); ui.label(egui::RichText::new("Processes selected clips offline").small().color(t.text_dim)); } + if root.label == "Window" { + ui.separator(); + let mut separate = app.ui.mix_separate; + if ui + .checkbox(&mut separate, "Mix in Separate Window") + .on_hover_text("Show Edit and Mix at once, e.g. one per monitor") + .changed() + { + let _ = run_ui_command(app, "window.mix_separate", &json!({"value": separate})); + ui.close(); + } + } }); } let title = format!( "{}{} — {}", app.engine.session().name, if app.engine.is_dirty() { " *" } else { "" }, - if app.ui.window == MainWindow::Edit { "Edit" } else { "Mix" } + if app.ui.window == MainWindow::Edit || app.ui.mix_separate { "Edit" } else { "Mix" } ); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { ui.label(egui::RichText::new(title).color(t.text_dim)); @@ -473,14 +486,25 @@ pub fn run_ui_command(app: &mut SoundApp, id: &str, p: &Value) -> Option { app.ui.window = MainWindow::Mix; + app.focus_mix = app.ui.mix_separate; json!({"window": "mix"}) } + "window.mix_separate" => { + let v = toggle(&mut app.ui.mix_separate); + app.focus_mix = app.ui.mix_separate; + v + } "window.edit" => { app.ui.window = MainWindow::Edit; json!({"window": "edit"}) } "window.toggle_mix_edit" => { - app.ui.window = if app.ui.window == MainWindow::Edit { MainWindow::Mix } else { MainWindow::Edit }; + if app.ui.mix_separate { + // Both are on screen: bring the Mix window forward instead. + app.focus_mix = true; + } else { + app.ui.window = if app.ui.window == MainWindow::Edit { MainWindow::Mix } else { MainWindow::Edit }; + } json!({"window": app.ui.window}) } "window.transport" => toggle(&mut app.ui.show_transport), diff --git a/crates/ui-egui/src/mix_window.rs b/crates/ui-egui/src/mix_window.rs index 01bb21a..135dcd2 100644 --- a/crates/ui-egui/src/mix_window.rs +++ b/crates/ui-egui/src/mix_window.rs @@ -19,6 +19,25 @@ pub fn show(app: &mut SoundApp, ui: &mut Ui) { crate::docking::show(app, ui, crate::MainWindow::Mix); } +/// The Mix window in its own native window (Window › Mix in Separate Window), so Edit and Mix can +/// be seen at once, e.g. one per monitor. Closing that window brings Mix back into the main one. +/// Backends without multiple windows show it as a floating egui window instead. +pub fn show_separate(app: &mut SoundApp, ctx: &egui::Context) { + let title = format!("{} — Mix", app.engine.session().name); + let builder = egui::ViewportBuilder::default().with_title(title).with_inner_size([1100.0, 720.0]).with_min_inner_size([480.0, 320.0]); + ctx.show_viewport_immediate(egui::ViewportId::from_hash_of("soundcraft.mix"), builder, |ui, _class| { + ui.set_style(ui.ctx().global_style()); + if std::mem::take(&mut app.focus_mix) { + ui.ctx().send_viewport_cmd(egui::ViewportCommand::Focus); + } + show(app, ui); + if ui.ctx().input(|i| i.viewport().close_requested()) { + app.ui.mix_separate = false; + app.ui.window = crate::MainWindow::Mix; + } + }); +} + pub(crate) fn content(app: &mut SoundApp, ui: &mut Ui) { let ids: Vec = app.engine.session().tracks.iter().filter(|x| !x.hidden && x.kind != TrackKind::Video).map(|x| x.id).collect(); // Per-channel peaks for multichannel meters (read once per frame). From 6d910609e1f68dc9923d40160b954077f7ccfb49 Mon Sep 17 00:00:00 2001 From: Limestudio90 Date: Mon, 12 Oct 2026 18:58:10 +0200 Subject: [PATCH 2/3] Docs: Mix in a separate window Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 2 ++ docs/ui-parity.md | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index bab0d92..b02f9f5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -125,6 +125,8 @@ mutated and truncated movies. Field reports from the first public week are track - **2026-10-12:** `soundcraft-cli convert` rejects an unparsable or zero `--rate` and an unknown `--bit-depth` (exit 1, nothing written) instead of converting with a default (#256) - **2026-10-12:** Timecode labels with huge fields no longer overflow: frame counts are computed in 128 bits and clamp, so `setup.current_timecode` and `session.format_time` saturate instead of failing (#248) - **2026-10-12:** `session.format_time` with the smallest bar number no longer fails with an internal error: the bar offset saturates (#249) +- **2026-10-12 (Mix in a separate window):** Window › Mix in Separate Window shows the Mix window in its own native window, so Edit and Mix can be on screen at once (e.g. one per monitor), as in Pro Tools. No readiness percentage change. + - **2026-10-10 (UI docking):** Tracks and Groups, Clips, MIDI Editor, Memory Locations, and Undo History use movable panels. Edit and Mix retain separate arrangements; Clips and MIDI Editor belong to Edit. Transport, plug-in, and specialist utility windows retain their existing hosts. Panel moves and reset are available as UI commands, and saved UI preferences retain arrangements. Common toolbar and track record-enable buttons share interaction, accessible labels and keyboard focus through `craft-ui`, retaining blue tool selection and red record-arm states. No readiness percentage change. - **2026-10-10** — Stage re-normalized to **pre-alpha** by the core-workflow gate (interface recording, MIDI recording and session interchange fail). Full re-measure against Pro Tools Ultimate 2026.4.1 and the standard progress-docs set (this page, target-app parity, gaps, roadmap, UI/format/hardware/plugin/ diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 80ff25b..54910c8 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (first interaction checklist against Pro Tools 2026.4.1) · **Target:** Avid Pro Tools Ultimate 2026.4.1 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (Mix in a separate window) · **Target:** Avid Pro Tools Ultimate 2026.4.1 How SoundCraft feels in the hands of a Pro Tools user: tools, modes, modifiers, shortcuts, windows, meters. Measured from `crates/model/src/session.rs` (tools, modes), the command @@ -39,7 +39,7 @@ Legend: ✅ matches · 🟡 partial · ❌ missing. | Window | Status | Notes | |---|---|---| | Edit window: rulers, track headers, view columns, Clip List, Groups, Tracks list | ✅ | Track Pin (new in 2026.4) ✅ (`track.pin`) | -| Mix window: strips, views (inserts, sends, I/O, comments, EQ curve, preamps, instruments, object) | ✅ | Narrow Mix ✅; Delay Compensation view and HEAT missing | +| Mix window: strips, views (inserts, sends, I/O, comments, EQ curve, preamps, instruments, object) | ✅ | Narrow Mix ✅; Mix and Edit on screen at once (Window › Mix in Separate Window, its own native window) ✅; Delay Compensation view and HEAT missing | | MIDI Editor, Score Editor, Event List | 🟡 | Dock height bug fixed (#113); notation editing shallow | | Transport, Big Counter, Memory Locations, Automation, Video, Universe, Renderer, UI Customization | ✅ present | | | Workspace / sound browser with previews | ❌ | G-16 | @@ -64,4 +64,5 @@ Legend: ✅ matches · 🟡 partial · ❌ missing. | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | Mix window: Mix in Separate Window (Edit and Mix on screen at once) | | 2026-10-10 | major | Created: tools, modes, shortcuts, windows and meters checklist against Pro Tools 2026.4.1 | From 3b7a1f2b336472e1806455887fdf99ff67c15584 Mon Sep 17 00:00:00 2001 From: Limestudio90 Date: Tue, 13 Oct 2026 11:47:49 +0200 Subject: [PATCH 3/3] ROADMAP: no blank line inside the progress log (rebase leftover) Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 1 - 1 file changed, 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index b02f9f5..c83a992 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -126,7 +126,6 @@ mutated and truncated movies. Field reports from the first public week are track - **2026-10-12:** Timecode labels with huge fields no longer overflow: frame counts are computed in 128 bits and clamp, so `setup.current_timecode` and `session.format_time` saturate instead of failing (#248) - **2026-10-12:** `session.format_time` with the smallest bar number no longer fails with an internal error: the bar offset saturates (#249) - **2026-10-12 (Mix in a separate window):** Window › Mix in Separate Window shows the Mix window in its own native window, so Edit and Mix can be on screen at once (e.g. one per monitor), as in Pro Tools. No readiness percentage change. - - **2026-10-10 (UI docking):** Tracks and Groups, Clips, MIDI Editor, Memory Locations, and Undo History use movable panels. Edit and Mix retain separate arrangements; Clips and MIDI Editor belong to Edit. Transport, plug-in, and specialist utility windows retain their existing hosts. Panel moves and reset are available as UI commands, and saved UI preferences retain arrangements. Common toolbar and track record-enable buttons share interaction, accessible labels and keyboard focus through `craft-ui`, retaining blue tool selection and red record-arm states. No readiness percentage change. - **2026-10-10** — Stage re-normalized to **pre-alpha** by the core-workflow gate (interface recording, MIDI recording and session interchange fail). Full re-measure against Pro Tools Ultimate 2026.4.1 and the standard progress-docs set (this page, target-app parity, gaps, roadmap, UI/format/hardware/plugin/