96 lines
4.2 KiB
Rust
96 lines
4.2 KiB
Rust
//! Shared pane resizing in the full application, including application shortcut ownership.
|
|
|
|
use egui::{Event, Id, Key, Modifiers, PointerButton, Rect, pos2, vec2};
|
|
use egui_kittest::Harness;
|
|
use filmcraft_engine::Session;
|
|
use filmcraft_ui_egui::FilmcraftApp;
|
|
use filmcraft_ui_egui::dock::{DockNode, PanelKind, SplitSize};
|
|
use filmcraft_ui_egui::theme::ThemeKind;
|
|
use serde_json::json;
|
|
|
|
fn step(h: &mut Harness<'_, FilmcraftApp>) {
|
|
h.step();
|
|
assert!(h.state().ui_error.is_none(), "the app caught a UI panic: {:?}", h.state().ui_error);
|
|
}
|
|
|
|
fn frames(h: &mut Harness<'_, FilmcraftApp>, count: usize) {
|
|
for _ in 0..count {
|
|
step(h);
|
|
}
|
|
}
|
|
|
|
fn snapshots(h: &mut Harness<'_, FilmcraftApp>, directory: Option<&std::path::Path>, phase: &str) {
|
|
let Some(directory) = directory else { return };
|
|
std::fs::create_dir_all(directory).unwrap();
|
|
for (name, theme) in [("dark", ThemeKind::Dark), ("medium", ThemeKind::Medium), ("light", ThemeKind::Light)] {
|
|
let ctx = h.ctx.clone();
|
|
h.state_mut().set_theme(&ctx, theme);
|
|
frames(h, 3);
|
|
h.render().unwrap().save(directory.join(format!("filmcraft-{phase}-{name}.png"))).unwrap();
|
|
}
|
|
let ctx = h.ctx.clone();
|
|
h.state_mut().set_theme(&ctx, ThemeKind::Dark);
|
|
frames(h, 3);
|
|
}
|
|
|
|
fn first_size(h: &Harness<'_, FilmcraftApp>) -> f32 {
|
|
match h.state().ui.dock {
|
|
DockNode::Split { size: SplitSize::FixedA(value), .. } => value,
|
|
ref other => panic!("fixed-size mode changed: {other:?}"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn focused_dock_resize_owns_arrows_and_keeps_pointer_dragging() {
|
|
let mut session = Session::default();
|
|
session.execute("file.openDemoProject", json!({})).unwrap();
|
|
let app = FilmcraftApp::new(session);
|
|
// Opt in to GPU snapshots while the ordinary test remains headless and renderer-independent.
|
|
let directory = std::env::var_os("CRAFT_UI_PANES_SNAPSHOT_DIR").map(std::path::PathBuf::from);
|
|
let mut builder = Harness::builder().with_size(vec2(1400.0, 900.0)).with_max_steps(10_000);
|
|
if directory.is_some() {
|
|
builder = builder.wgpu();
|
|
}
|
|
let mut h = builder.build_eframe(move |_| app);
|
|
frames(&mut h, 4);
|
|
snapshots(&mut h, directory.as_deref(), "workspace");
|
|
h.state_mut().ui.focused = PanelKind::Timeline;
|
|
h.state_mut().ui.dock = DockNode::Split {
|
|
vertical: false,
|
|
size: SplitSize::FixedA(400.0),
|
|
a: Box::new(DockNode::Tabs { panels: vec![PanelKind::Project], active: 0 }),
|
|
b: Box::new(DockNode::Tabs { panels: vec![PanelKind::Timeline], active: 0 }),
|
|
};
|
|
frames(&mut h, 3);
|
|
let before_project = h.state().session.project.clone();
|
|
let before_playheads = h.state().session.state.playheads.clone();
|
|
let id = Id::new(("dock-gutter", String::new()));
|
|
h.ctx.memory_mut(|memory| memory.request_focus(id));
|
|
frames(&mut h, 2);
|
|
assert_eq!(h.ctx.memory(|memory| memory.focused()), Some(id));
|
|
snapshots(&mut h, directory.as_deref(), "focused-resize");
|
|
h.event(Event::Key { key: Key::ArrowRight, physical_key: None, pressed: true, repeat: false, modifiers: Modifiers::NONE });
|
|
step(&mut h);
|
|
h.event(Event::Key { key: Key::ArrowRight, physical_key: None, pressed: false, repeat: false, modifiers: Modifiers::NONE });
|
|
step(&mut h);
|
|
assert_eq!(first_size(&h), 408.0);
|
|
assert_eq!(h.state().session.state.playheads, before_playheads, "the Timeline shortcut must not seek");
|
|
assert!(std::sync::Arc::ptr_eq(&h.state().session.project, &before_project));
|
|
|
|
frames(&mut h, 2);
|
|
let element = h.state().auto.find("dock.gutter.").unwrap();
|
|
let from = Rect::from_min_size(pos2(element.rect[0], element.rect[1]), vec2(element.rect[2], element.rect[3])).center();
|
|
h.event(Event::PointerMoved(from));
|
|
step(&mut h);
|
|
h.event(Event::PointerButton { pos: from, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
|
|
step(&mut h);
|
|
for offset in [5.0, 10.0, 15.0, 20.0] {
|
|
h.event(Event::PointerMoved(from + vec2(offset, 0.0)));
|
|
step(&mut h);
|
|
}
|
|
h.event(Event::PointerButton { pos: from + vec2(20.0, 0.0), button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });
|
|
step(&mut h);
|
|
assert_eq!(first_size(&h), 428.0);
|
|
assert_eq!(h.state().session.state.playheads, before_playheads);
|
|
}
|