Audio Clip Mixer: click the dB readout to type a volume (#481)

This commit is contained in:
MarekSpodBiedry committed 2026-10-10 11:44:16 +02:00
1 parent 55d10195fb
commit 77becde085
2 files changed
+38 -2

No files matched your search

+17 -2
View File
@@ -1010,8 +1010,23 @@ pub fn clip_mixer(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) {
let m = meters.get(&tr.id.0).cloned().unwrap_or_default();
draw_meters(ui, mrect, &m, if m.is_empty() { filmcraft_render::mixer::width_of(tr.channels) } else { m.len() }, &t);
}
small_text(ui, pos2(sr.min.x + 8.0, sr.max.y - 34.0), Align2::LEFT_CENTER, &db_text(vol), 11.5, dimc(t.hot_text));
app.auto.add(&format!("{ap}.value"), Rect::from_min_size(pos2(sr.min.x + 4.0, sr.max.y - 42.0), vec2(50.0, 16.0)), &db_text(vol));
// dB readout: drag to scrub, click to type a value (clamped to the fader range), like the track mixer
let vr = Rect::from_min_size(pos2(sr.min.x + 4.0, sr.max.y - 42.0), vec2(50.0, 16.0));
let mut vui = ui.new_child(egui::UiBuilder::new().max_rect(vr));
if !active {
vui.set_opacity(0.4);
}
let (vresp, nv) = crate::widgets::hot_number(&mut vui, egui::Id::new((&ap, "value")), vol.max(-96.0), 0.1, (FADER_MIN_DB, FADER_MAX_DB), 1, "", &t);
app.auto.add(&format!("{ap}.value"), vresp.rect, &db_text(vol));
if let (Some(v), true) = (nv, active) {
set(&mut acts, "volume", "level", v, !vresp.dragged() || vresp.drag_started());
if !vresp.dragged() {
release(&mut acts, "volume");
}
}
if vresp.drag_stopped() {
release(&mut acts, "volume");
}
small_text(ui, pos2(sr.min.x + 6.0, sr.max.y - 10.0), Align2::LEFT_CENTER, &label, 12.0, t.text);
small_text(ui, pos2(sr.min.x + 30.0, sr.max.y - 10.0), Align2::LEFT_CENTER, &tr.name, 12.0, t.text);
}
+21
View File
@@ -269,6 +269,27 @@ fn clip_mixer_strips_follow_the_playhead() {
d.snapshot("mixer-clip-mixer", Some("clipMixer."));
}
#[test]
fn clip_mixer_db_value_can_be_typed() {
let mut d = Driver::demo();
d.ok("ui.panel.show", json!({"panel": "AudioClipMixer"}));
d.frames(3);
d.exec("playhead.set", json!({"seconds": 1.0}));
d.frames(2);
d.click("clipMixer.A1.value");
d.ok("ui.key", json!({"key": "Cmd+A"}));
d.frames(1);
d.ok("ui.type", json!({"text": "-20"}));
d.frames(2);
d.ok("ui.key", json!({"key": "Enter"}));
d.frames(3);
let seq = d.exec("sequence.inspect", json!({}));
let fx = &seq["audio"][0]["items"][0]["effects"];
let vol = fx.as_array().unwrap().iter().find(|e| e["effect"] == "volume").unwrap();
let level: f64 = vol["params"]["level"]["value"].as_str().and_then(|v| v.strip_prefix("Float(")?.strip_suffix(')')?.parse().ok()).unwrap();
assert!((level + 20.0).abs() < 1e-6, "typed -20 dB into the clip mixer readout: {level}");
}
#[test]
fn audio_gain_dialog_normalizes_the_selection() {
let mut d = Driver::demo();