facett-pipeline/tests/camera_centred.rs
//! **The pipeline DAG opens centred, a click never moves it (📌 Stay), and 🎯 Focus
//! flies the clicked stage to the centre** — rendered: real egui frames, the pane
//! beside a 320 px rail (its canvas is NOT at the screen origin), real clicks.
use egui::{Pos2, Rect, Vec2};
use facett_core::fly::NavMode;
use facett_core::Facet;
use facett_pipeline::{PipelineView, Status};
fn view() -> PipelineView {
let names = ["lint", "build", "test", "ui", "doctor"];
PipelineView::new("runa", names.iter().map(|n| (n.to_string(), Status::Idle)).collect(), vec![(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)])
}
struct Rig {
ctx: egui::Context,
t: f64,
rail: f32,
}
impl Rig {
fn new(mode: NavMode) -> Self {
let ctx = egui::Context::default();
ctx.set_pixels_per_point(1.0);
mode.remember(&ctx);
Self { ctx, t: 1.0, rail: 320.0 }
}
fn frame(&mut self, v: &mut PipelineView, events: Vec<egui::Event>) {
self.t += 1.0 / 60.0;
let input = egui::RawInput { screen_rect: Some(Rect::from_min_size(Pos2::ZERO, Vec2::new(1400.0, 900.0))), time: Some(self.t), events, ..Default::default() };
let rail = self.rail;
let mut out = self.ctx.run_ui(input, |ui| {
egui::Panel::left("rail").exact_size(rail).resizable(false).show_inside(ui, |ui| {
ui.label("rail");
});
egui::CentralPanel::default().show_inside(ui, |ui| v.ui(ui));
});
out.textures_delta.clear();
}
fn click(&mut self, v: &mut PipelineView, p: Pos2) {
self.frame(v, vec![egui::Event::PointerMoved(p)]);
let b = |pressed| egui::Event::PointerButton { pos: p, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
self.frame(v, vec![b(true)]);
self.frame(v, vec![b(false)]);
}
}
fn centre_of(v: &PipelineView, name: &str) -> Pos2 {
let i = v.state().nodes.iter().position(|n| n.name == name).unwrap();
v.nav().to_screen(v.layout_scene_centers()[i])
}
/// First load: fitted, CENTRED (±2 px) and wholly inside the visible canvas.
#[test]
fn the_dag_opens_centred_in_its_visible_canvas() {
let mut rig = Rig::new(NavMode::Stay);
let mut v = view();
for _ in 0..4 {
rig.frame(&mut v, Vec::new());
}
let (seen, b) = (v.seen_rect().expect("painted"), v.screen_box().expect("stages"));
assert!((b.center() - seen.center()).length() <= 2.0, "centred: box {b:?} in {seen:?}");
assert!(seen.expand(0.5).contains_rect(b), "fully visible: box {b:?} in {seen:?}");
// the rail grows: the screen-space camera follows its canvas, the picture stays on it
rig.rail = 480.0;
for _ in 0..4 {
rig.frame(&mut v, Vec::new());
}
let (seen, b) = (v.seen_rect().unwrap(), v.screen_box().unwrap());
assert!(b.min.x >= seen.min.x - 0.5, "the picture moved with its canvas: box {b:?} in {seen:?}");
}
/// 📌 Stay: a click selects the stage and moves nothing.
#[test]
fn stay_a_click_never_moves_the_dag() {
let mut rig = Rig::new(NavMode::Stay);
let mut v = view();
for _ in 0..4 {
rig.frame(&mut v, Vec::new());
}
let p = centre_of(&v, "ui");
let nav = *v.nav();
rig.click(&mut v, p);
for _ in 0..30 {
rig.frame(&mut v, Vec::new());
}
assert_eq!(v.state().selected.as_deref(), Some("ui"));
assert_eq!(*v.nav(), nav, "the camera did not move");
}
/// 🎯 Focus: the clicked stage flies to the centre of the visible canvas (±2 px).
#[test]
fn focus_a_click_flies_the_stage_to_the_centre() {
let mut rig = Rig::new(NavMode::Focus);
let mut v = view();
for _ in 0..4 {
rig.frame(&mut v, Vec::new());
}
let p = centre_of(&v, "doctor");
rig.click(&mut v, p);
for _ in 0..60 {
rig.frame(&mut v, Vec::new());
}
let seen = v.seen_rect().unwrap();
let at = centre_of(&v, "doctor");
assert!((at - seen.center()).length() <= 2.0, "doctor at the centre: {at:?} vs {:?}", seen.center());
assert!(v.nav().scale >= 1.0, "at a readable zoom: {}", v.nav().scale);
}