118 lines
5.3 KiB
Rust
118 lines
5.3 KiB
Rust
//! Headless checks for the Tracker panel and the viewer's track point widgets (egui_kittest, UI
|
|
//! logic only: no GPU needed).
|
|
|
|
use effectcraft_engine::Session;
|
|
use effectcraft_ui_egui::EffectcraftApp;
|
|
use effectcraft_ui_egui::dock::PanelKind;
|
|
use egui_kittest::Harness;
|
|
use serde_json::json;
|
|
|
|
fn app() -> EffectcraftApp {
|
|
let mut s = Session::default();
|
|
s.execute("comp.new", json!({"name": "Track", "width": 640, "height": 360, "duration": 2})).unwrap();
|
|
s.execute("layer.newSolid", json!({"name": "Plate", "color": "#406080"})).unwrap();
|
|
s.execute("layer.newSolid", json!({"name": "Target", "width": 80, "height": 80})).unwrap();
|
|
s.execute("layer.select", json!({"layers": ["Plate"]})).unwrap();
|
|
EffectcraftApp::new(s)
|
|
}
|
|
|
|
fn ids(h: &Harness<'_, EffectcraftApp>) -> Vec<String> {
|
|
h.state().auto.previous.iter().chain(h.state().auto.elements.iter()).map(|e| e.id.clone()).collect()
|
|
}
|
|
|
|
fn rect(h: &Harness<'_, EffectcraftApp>, id: &str) -> egui::Rect {
|
|
let e = h.state().auto.find(id).unwrap_or_else(|| panic!("no {id}"));
|
|
egui::Rect::from_min_size(egui::pos2(e.rect[0], e.rect[1]), egui::vec2(e.rect[2], e.rect[3]))
|
|
}
|
|
|
|
#[test]
|
|
fn tracker_panel_and_track_point_widgets() {
|
|
let mut h = Harness::builder().with_size(egui::vec2(1600.0, 1000.0)).build_eframe(|_| app());
|
|
h.state_mut().show_panel(PanelKind::Tracker);
|
|
h.run_steps(3);
|
|
let all = ids(&h);
|
|
for want in [
|
|
"tracker.trackCamera",
|
|
"tracker.warpStabilizer",
|
|
"tracker.trackMotion",
|
|
"tracker.stabilizeMotion",
|
|
"tracker.motionSource",
|
|
"tracker.currentTrack",
|
|
"tracker.trackType",
|
|
"tracker.position",
|
|
"tracker.rotation",
|
|
"tracker.scale",
|
|
"tracker.motionTarget",
|
|
"tracker.editTarget",
|
|
"tracker.options",
|
|
"tracker.analyze.frameBackward",
|
|
"tracker.analyze.backward",
|
|
"tracker.analyze.forward",
|
|
"tracker.analyze.frameForward",
|
|
"tracker.reset",
|
|
"tracker.apply",
|
|
] {
|
|
assert!(all.iter().any(|i| i == want), "missing {want}");
|
|
}
|
|
// Track Motion from the panel.
|
|
let r = rect(&h, "tracker.trackMotion");
|
|
h.input_mut().events.push(egui::Event::PointerMoved(r.center()));
|
|
h.input_mut().events.push(egui::Event::PointerButton {
|
|
pos: r.center(),
|
|
button: egui::PointerButton::Primary,
|
|
pressed: true,
|
|
modifiers: Default::default(),
|
|
});
|
|
h.input_mut().events.push(egui::Event::PointerButton {
|
|
pos: r.center(),
|
|
button: egui::PointerButton::Primary,
|
|
pressed: false,
|
|
modifiers: Default::default(),
|
|
});
|
|
h.run_steps(3);
|
|
let st = h.state_mut().session.execute("track.status", json!({})).unwrap();
|
|
assert_eq!(st["tracker"]["name"], "Tracker 1", "{st}");
|
|
h.state_mut().session.execute("track.setPoint", json!({"point": 1, "featureSize": [60, 60], "searchSize": [120, 120]})).unwrap();
|
|
h.state_mut().show_panel(PanelKind::Composition);
|
|
h.run_steps(3);
|
|
let all = ids(&h);
|
|
for want in ["viewer.track.1.feature", "viewer.track.1.search", "viewer.track.1.attach", "viewer.track.1.feature.0", "viewer.track.1.search.2"] {
|
|
assert!(all.iter().any(|i| i == want), "missing {want}");
|
|
}
|
|
// Drag the feature region: the point moves by the drag in layer pixels (one undo step).
|
|
let c0 = st["tracker"]["points"][0]["center"].clone();
|
|
let fr = rect(&h, "viewer.track.1.feature");
|
|
let zoom = {
|
|
let a = rect(&h, "viewer.comp");
|
|
a.width() / 640.0
|
|
};
|
|
// Inside the feature region, away from the attach point crosshair (which sits on the centre).
|
|
let from = fr.center() + egui::vec2(15.0, 0.0);
|
|
let to = from + egui::vec2(40.0, 20.0);
|
|
h.input_mut().events.push(egui::Event::PointerMoved(from));
|
|
h.input_mut().events.push(egui::Event::PointerButton { pos: from, button: egui::PointerButton::Primary, pressed: true, modifiers: Default::default() });
|
|
h.step();
|
|
for i in 1..=8 {
|
|
h.input_mut().events.push(egui::Event::PointerMoved(from + (to - from) * (i as f32 / 8.0)));
|
|
h.step();
|
|
}
|
|
h.input_mut().events.push(egui::Event::PointerButton { pos: to, button: egui::PointerButton::Primary, pressed: false, modifiers: Default::default() });
|
|
h.run_steps(2);
|
|
let st = h.state_mut().session.execute("track.status", json!({})).unwrap();
|
|
let c1 = &st["tracker"]["points"][0]["center"];
|
|
let dx = c1[0].as_f64().unwrap() - c0[0].as_f64().unwrap();
|
|
let dy = c1[1].as_f64().unwrap() - c0[1].as_f64().unwrap();
|
|
assert!((dx - 40.0 / zoom as f64).abs() < 1.0 && (dy - 20.0 / zoom as f64).abs() < 1.0, "moved by ({dx}, {dy}) at zoom {zoom}");
|
|
let undo = h.state().session.history.undo.iter().filter(|(l, _)| l == "Move Track Point").count();
|
|
assert_eq!(undo, 2, "one undo step per drag");
|
|
// Options and Edit Target dialogs.
|
|
let ctx = h.ctx.clone();
|
|
effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "track.optionsDialog", json!({})).unwrap();
|
|
assert_eq!(h.state().dialog, Some(effectcraft_ui_egui::Dialog::TrackOptions));
|
|
h.step();
|
|
assert!(ids(&h).iter().any(|i| i == "dialog.trackOptions.ok"));
|
|
h.state_mut().dialog = None;
|
|
effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "track.editTargetDialog", json!({})).unwrap();
|
|
assert_eq!(h.state().dialog, Some(effectcraft_ui_egui::Dialog::TrackTarget));
|
|
}
|