84 lines
4.7 KiB
Rust
84 lines
4.7 KiB
Rust
//! Render-fidelity commands: project colour settings, footage colour profile, slip edit.
|
|
|
|
use effectcraft_project::{BitDepth, ColorSpace};
|
|
use serde_json::json;
|
|
|
|
use crate::Session;
|
|
|
|
#[test]
|
|
fn project_colour_settings_are_undoable() {
|
|
let mut s = Session::default();
|
|
s.execute("file.projectSettings", json!({"bitDepth": 32, "workingSpace": "rec2020", "linearize": true, "blendLinear": true})).unwrap();
|
|
let st = &s.project.settings;
|
|
assert_eq!((st.bit_depth, st.working_space, st.linearize, st.blend_linear), (BitDepth::Bpc32, Some(ColorSpace::Rec2020), true, true));
|
|
s.execute("file.projectSettings", json!({"workingSpace": "Display P3"})).unwrap();
|
|
assert_eq!(s.project.settings.working_space, Some(ColorSpace::DisplayP3));
|
|
s.execute("file.projectSettings", json!({"workingSpace": "none"})).unwrap();
|
|
assert_eq!(s.project.settings.working_space, None);
|
|
assert!(s.execute("file.projectSettings", json!({"workingSpace": "acescg-ish"})).is_err());
|
|
assert!(s.undo());
|
|
assert_eq!(s.project.settings.working_space, Some(ColorSpace::DisplayP3));
|
|
assert!(s.undo() && s.undo());
|
|
assert_eq!(s.project.settings.bit_depth, BitDepth::Bpc8);
|
|
assert!(!s.project.settings.blend_linear);
|
|
// The Project panel's depth button cycles 8 → 16 → 32 → 8.
|
|
for want in ["16 bpc", "32 bpc", "8 bpc"] {
|
|
assert_eq!(s.execute("file.cycleBitDepth", json!({})).unwrap(), json!(want));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn footage_colour_profile_is_interpreted() {
|
|
let mut s = Session::default();
|
|
let id = s.execute("file.importPlaceholder", json!({"name": "clip", "width": 64, "height": 36, "frameRate": 24, "duration": 2})).unwrap();
|
|
let item = id["item"].as_u64().or_else(|| id.as_u64()).map(effectcraft_project::ItemId).unwrap_or_else(|| *s.project.items.keys().last().unwrap());
|
|
let profile = |s: &Session| match &s.project.item(item).unwrap().kind {
|
|
effectcraft_project::ItemKind::Footage(f) => f.color_profile,
|
|
_ => panic!("not footage"),
|
|
};
|
|
s.execute("file.interpretFootage", json!({"items": [item.0], "colorProfile": "rec2020"})).unwrap();
|
|
assert_eq!(profile(&s), Some(ColorSpace::Rec2020));
|
|
s.execute("file.interpretFootage", json!({"items": [item.0], "colorProfile": "auto"})).unwrap();
|
|
assert_eq!(profile(&s), None);
|
|
assert!(s.undo());
|
|
assert_eq!(profile(&s), Some(ColorSpace::Rec2020));
|
|
}
|
|
|
|
#[test]
|
|
fn slip_moves_the_source_under_fixed_in_and_out() {
|
|
use effectcraft_time::Tick;
|
|
let mut s = Session::default();
|
|
s.execute("comp.new", json!({"name": "Main", "width": 100, "height": 100, "frameRate": 30, "duration": 10})).unwrap();
|
|
let nested = s.execute("comp.new", json!({"name": "Nested", "duration": 4, "open": false})).unwrap()["comp"].as_u64().unwrap();
|
|
s.execute("layer.addItem", json!({"item": nested})).unwrap();
|
|
let id = s.active_comp().unwrap().layers[0].id.0;
|
|
// Trim to 1 s .. 3 s of a 4 s source.
|
|
s.execute("layer.timing", json!({"layers": [id], "in": 1.0, "out": 3.0})).unwrap();
|
|
let get = |s: &Session| s.active_comp().unwrap().layers[0].clone();
|
|
let before = get(&s);
|
|
assert_eq!((before.start_time, before.in_point.seconds(), before.out_point.seconds()), (Tick::ZERO, 1.0, 3.0));
|
|
// Slip the source 0.5 s later: in/out stay, the source (start) moves.
|
|
s.execute("layer.slip", json!({"layers": [id], "delta": 0.5})).unwrap();
|
|
let l = get(&s);
|
|
assert_eq!((l.start_time.seconds(), l.in_point, l.out_point), (0.5, before.in_point, before.out_point));
|
|
// The source time at comp 2 s is now 1.5 s.
|
|
assert_eq!(l.layer_time(Tick::from_seconds_f64(2.0)).seconds(), 1.5);
|
|
// Clamped so the source still covers in..out: at most start = in (1 s).
|
|
let r = s.execute("layer.slip", json!({"layers": [id], "delta": 5.0})).unwrap();
|
|
assert_eq!(get(&s).start_time.seconds(), 1.0);
|
|
assert_eq!(r["slipped"][0]["delta"], json!(0.5));
|
|
// Alt+PageUp / Alt+PageDown nudge by a frame.
|
|
s.execute("layer.slipBack", json!({"layers": [id]})).unwrap();
|
|
assert!((get(&s).start_time.seconds() - (1.0 - 1.0 / 30.0)).abs() < 1e-9);
|
|
s.execute("layer.slipForward", json!({"layers": [id]})).unwrap();
|
|
assert_eq!(get(&s).start_time.seconds(), 1.0);
|
|
// Undo walks back through the slips.
|
|
assert!(s.undo() && s.undo() && s.undo() && s.undo());
|
|
assert_eq!(get(&s).start_time, Tick::ZERO);
|
|
assert_eq!(crate::find_command("layer.slipBack").and_then(|c| c.shortcut), Some("Alt+PageUp"));
|
|
assert_eq!(crate::find_command("layer.slipForward").and_then(|c| c.shortcut), Some("Alt+PageDown"));
|
|
// Layers without a source duration can't slip.
|
|
s.execute("layer.newSolid", json!({"color": "#ff0000"})).unwrap();
|
|
assert!(s.execute("layer.slip", json!({"delta": 0.5})).is_err());
|
|
}
|