Merge pull request #147 from grovebit/mix-edit-toggle-zoom

Cmd+= only switches Mix/Edit, and the Interface scale slider drags smoothly
This commit is contained in:
Brandon Thomas 2026-10-11 20:05:05 -04:00 committed by GitHub
commit a77c351da3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 3 deletions

View File

@ -52,15 +52,16 @@ pub fn run(app: &mut SoundApp, id: &str, p: &Value) -> Option<Value> {
}
pub fn show(app: &mut SoundApp, ctx: &egui::Context) {
apply_customization(app, ctx);
auto_update(app, ctx);
renderer(app, ctx);
ui_customization(app, ctx);
apply_customization(app, ctx);
}
fn apply_customization(app: &mut SoundApp, ctx: &egui::Context) {
let want = (app.extra.ui_scale.clamp(0.75, 1.5), app.extra.reduce_motion);
if app.extra.applied == Some(want) {
// Rescaling mid-drag would move the Interface scale slider out from under the pointer.
if app.extra.applied == Some(want) || ctx.input(|i| i.pointer.any_down()) {
return;
}
// Only touch the zoom once the user has changed it, so platform scaling stays untouched.

View File

@ -55,6 +55,8 @@ fn search_chord(m: Modifiers, mac: bool) -> bool {
}
pub fn handle(app: &mut SoundApp, ctx: &egui::Context) {
// Cmd+= and Cmd+0 are Mix/Edit and Quantize to Grid, not egui's built-in interface zoom.
ctx.options_mut(|o| o.zoom_with_keyboard = false);
if ctx.egui_wants_keyboard_input() || app.dialogs.open.is_some() {
return;
}

View File

@ -0,0 +1,47 @@
use egui::accesskit::Role;
use egui::{Event, Modifiers, PointerButton, Pos2, Vec2, pos2, vec2};
use egui_kittest::Harness;
use egui_kittest::kittest::Queryable;
use soundcraft_ui_egui::{Services, SoundApp};
const WINDOW_PX: Vec2 = vec2(1600.0, 1000.0);
fn frame(h: &mut Harness<'_, SoundApp>, px: Pos2, pressed: Option<bool>) {
let zoom = h.ctx.zoom_factor();
h.set_size(WINDOW_PX / zoom);
let pos = (px.to_vec2() / zoom).to_pos2();
h.input_mut().events.push(Event::PointerMoved(pos));
if let Some(pressed) = pressed {
h.input_mut().events.push(Event::PointerButton { pos, button: PointerButton::Primary, pressed, modifiers: Modifiers::NONE });
}
h.step();
}
#[test]
fn interface_scale_slider_follows_the_pointer() {
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
app.extra.show_ui_customization = true;
let mut h = Harness::builder().with_size(WINDOW_PX).with_pixels_per_point(1.0).build_ui_state(
|ui, app: &mut SoundApp| {
let ctx = ui.ctx().clone();
app.logic(&ctx);
app.ui(ui);
},
app,
);
h.run_steps(6);
let rail = h.get_by_role(Role::Slider).rect();
let start = pos2(rail.left() + rail.width() / 3.0, rail.center().y);
let end = pos2(rail.right() + 40.0, rail.center().y);
frame(&mut h, start, Some(true));
let mut scales = vec![];
for i in 1..=20 {
frame(&mut h, start.lerp(end, i as f32 / 20.0), None);
scales.push(h.state().extra.ui_scale);
}
assert!(scales.windows(2).all(|w| w[0] <= w[1]), "{scales:?}");
frame(&mut h, end, Some(false));
frame(&mut h, end, None);
assert_eq!(h.state().extra.ui_scale, 1.5);
assert_eq!(h.ctx.zoom_factor(), 1.5);
}

View File

@ -1,7 +1,7 @@
use egui::os::OperatingSystem;
use egui::{Key, Modifiers};
use serde_json::json;
use soundcraft_ui_egui::{Services, SoundApp, shortcuts};
use soundcraft_ui_egui::{MainWindow, Services, SoundApp, shortcuts};
fn press(ctx: &egui::Context, app: &mut SoundApp, key: Key, modifiers: Modifiers) {
let events = [true, false].map(|pressed| egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers }).to_vec();
@ -24,3 +24,23 @@ fn ctrl_shift_arrows_nudge_the_selected_clip_gain() {
assert_eq!(app.engine.session().find_clip(kick).unwrap().1.gain_db, 1.0, "{os:?}");
}
}
#[test]
fn cmd_equals_toggles_mix_and_edit_without_zooming() {
let mac_cmd = Modifiers { mac_cmd: true, command: true, ..Modifiers::NONE };
let pc_ctrl = Modifiers { ctrl: true, command: true, ..Modifiers::NONE };
for (os, cmd) in [(OperatingSystem::Mac, mac_cmd), (OperatingSystem::Windows, pc_ctrl), (OperatingSystem::Nix, pc_ctrl)] {
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
let ctx = egui::Context::default();
ctx.set_os(os);
ctx.set_zoom_factor(1.25);
press(&ctx, &mut app, Key::Equals, cmd);
assert_eq!(app.ui.window, MainWindow::Mix, "{os:?}");
press(&ctx, &mut app, Key::Equals, cmd);
press(&ctx, &mut app, Key::Num0, cmd);
press(&ctx, &mut app, Key::Minus, cmd);
ctx.run_ui(egui::RawInput::default(), |_| {}).textures_delta.clear();
assert_eq!(app.ui.window, MainWindow::Edit, "{os:?}");
assert_eq!(ctx.zoom_factor(), 1.25, "{os:?}");
}
}