Files
effectcraft/crates/ui-egui/tests/it/ui_panel_windows.rs
T
skylartaylor 9ee853715d M0.37: migrate EffectCraft to egui 0.37
Reconcile main 991904888a and preserve the reviewed lifecycle, IME, rendering and lockfile changes.

Formatting, strict lint, layers, assets and WASM passed. Full CI retained 3,961 passes, 14 baseline-matching GPU failures and 31 ignored executions. The local review commit has explicit approval to retain these documented failures; native/browser acceptance and paired app performance remain open.
2026-10-25 02:01:16 +01:00

88 lines
5.0 KiB
Rust

//! Multiple monitors (#486): a panel moves out of the main window into a native window of its
//! own (Move Panel to New Window), which can be placed on another screen, and back.
use effectcraft_engine::Session;
use effectcraft_ui_egui::EffectcraftApp;
use effectcraft_ui_egui::dock::{PanelKind, PanelWindow};
use egui::vec2;
use egui_kittest::Harness;
use serde_json::json;
fn invoke(app: &mut EffectcraftApp, ctx: &egui::Context, params: serde_json::Value) -> Result<serde_json::Value, String> {
effectcraft_ui_egui::menus::invoke(app, ctx, "window.panelWindow", params)
}
#[test]
fn panel_window_command_moves_a_docked_panel_into_its_own_window_and_back() {
let mut app = EffectcraftApp::new(Session::default());
let ctx = egui::Context::default();
assert!(app.ui.dock.contains(PanelKind::Project));
assert_eq!(invoke(&mut app, &ctx, json!({"panel": "Project", "window": true})).unwrap(), json!({"window": true}));
// Undocked first, then given a window of its own.
assert!(!app.ui.dock.contains(PanelKind::Project));
assert!(app.ui.floating.iter().any(|group| group.panels == [PanelKind::Project]));
assert!(app.in_panel_window(PanelKind::Project));
let window = app.ui.panel_windows.iter().find(|w| w.panel == PanelKind::Project).copied().unwrap();
assert_eq!(window.rect, PanelWindow::sanitized(window.rect));
// Asking again changes nothing; no `window` toggles.
assert_eq!(invoke(&mut app, &ctx, json!({"panel": "Project", "window": true})).unwrap(), json!({"window": true}));
assert_eq!(app.ui.panel_windows.len(), 1);
assert_eq!(invoke(&mut app, &ctx, json!({"panel": "Project"})).unwrap(), json!({"window": false}));
// Back in the main window, still floating where it was.
assert!(!app.in_panel_window(PanelKind::Project));
assert!(app.ui.panel_windows.is_empty());
assert!(app.ui.floating.iter().any(|group| group.panels == [PanelKind::Project]));
// The serialized panel form works too.
assert_eq!(invoke(&mut app, &ctx, json!({"panel": PanelKind::Project})).unwrap(), json!({"window": true}));
// Bad requests are errors and change nothing.
let before = app.ui.panel_windows.clone();
for params in [json!({}), json!({"panel": "Nope"}), json!({"panel": 7}), json!({"panel": "Project", "window": "yes"}), json!({"panel": {"Viewer": 9}})] {
assert!(invoke(&mut app, &ctx, params.clone()).is_err(), "{params} must be rejected");
}
assert_eq!(app.ui.panel_windows, before);
}
#[test]
fn a_panel_in_its_own_window_leaves_the_main_window() {
let mut app = EffectcraftApp::new(Session::default());
app.ui.start_screen = false;
let mut h = Harness::builder().with_size(vec2(1200.0, 760.0)).build_eframe(move |_| app);
h.run_steps(3);
let ctx = h.ctx.clone();
invoke(h.state_mut(), &ctx, json!({"panel": "Project", "window": true})).unwrap();
h.run_steps(3);
// No in-window floating group is drawn for it (no move strip, no floating area)...
assert!(!h.state().auto.elements.iter().any(|e| e.id.starts_with("panel.float.")));
let area = egui::Id::unique(("floating-panel", PanelKind::Project.id()));
assert!(!h.ctx.memory(|m| m.layer_ids().any(|layer| layer.id == area && m.areas().is_visible(&layer))));
// ...the window draws it (here embedded: the test harness has no native windows).
assert!(h.state().auto.elements.iter().any(|e| e.id == "panel.Project"));
// Docking it back into the main window closes the window entry.
let ctx = h.ctx.clone();
effectcraft_ui_egui::menus::invoke(h.state_mut(), &ctx, "window.dockPanel", json!({"panel": "Project", "anchor": "Timeline"})).unwrap();
h.run_steps(2);
assert!(h.state().ui.panel_windows.is_empty());
assert!(!h.state().in_panel_window(PanelKind::Project));
}
#[test]
fn panel_windows_survive_restart_with_hostile_places_made_safe() {
use effectcraft_engine::config::MemoryConfig;
use std::sync::Arc;
let store = Arc::new(MemoryConfig::default());
let mut app = EffectcraftApp::new(Session { config: Some(store.clone()), ..Default::default() });
let ctx = egui::Context::default();
invoke(&mut app, &ctx, json!({"panel": "Project", "window": true})).unwrap();
let hostile = [1.0e9, -3.0e12, 1.0e9, 0.5];
if let Some(w) = app.ui.panel_windows.first_mut() {
w.rect = hostile;
}
// A window for a panel that doesn't float is dropped on load.
app.ui.panel_windows.push(PanelWindow { panel: PanelKind::Timeline, rect: [10.0, 10.0, 300.0, 200.0] });
eframe::App::on_exit(&mut app);
let restarted = EffectcraftApp::new(Session { config: Some(store), ..Default::default() });
assert_eq!(restarted.ui.panel_windows, vec![PanelWindow { panel: PanelKind::Project, rect: PanelWindow::sanitized(hostile) }]);
let [x, y, w, h] = PanelWindow::sanitized(hostile);
assert!(x <= 100_000.0 && y >= -100_000.0 && (160.0..=16_384.0).contains(&w) && (100.0..=16_384.0).contains(&h));
assert!(PanelWindow::sanitized([f32::NAN, f32::INFINITY, f32::NAN, f32::NEG_INFINITY]).iter().all(|v| v.is_finite()));
}