From 80cf197be6f1d400bf0b9c84bf8557f88c895aa6 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 11 Sep 2026 01:27:48 -0700 Subject: [PATCH] Remeasure scenario Fit viewport after owner or document changes --- .../src/behavior/scenario/workspace.rs | 1 + .../src/behavior/scenario/workspace/tests.rs | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/crates/oa-desktop/src/behavior/scenario/workspace.rs b/crates/oa-desktop/src/behavior/scenario/workspace.rs index ea63b579..121136ce 100644 --- a/crates/oa-desktop/src/behavior/scenario/workspace.rs +++ b/crates/oa-desktop/src/behavior/scenario/workspace.rs @@ -649,6 +649,7 @@ fn canvas_pane<'a, R: iced::advanced::text::Renderer + 'a>( .width(Fill) .height(Fill), )) + .key((context.document, context.scenario)) .on_show(move |size| Message::ScenarioCanvas(CanvasEvent::Viewport(context, size))) .on_resize(move |size| Message::ScenarioCanvas(CanvasEvent::Viewport(context, size))), ) diff --git a/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs b/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs index 8829a024..8c32bfa7 100644 --- a/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs +++ b/crates/oa-desktop/src/behavior/scenario/workspace/tests.rs @@ -341,6 +341,72 @@ fn scenario_workspace_fit_uses_measured_inner_viewport_and_rejects_nonfinite_inp ); } +#[test] +fn scenario_workspace_same_size_owner_and_document_changes_remeasure_fit_viewport() { + use super::super::direct_tests::{navigation_event, navigation_fixture}; + let (project, [a, b, _], [reference, _, _]) = navigation_fixture(); + let mut app = App::with_project(project.clone()); + let _ = app.update(Message::Select(a)); + let _ = app.update(Message::Page(crate::app::Page::Behavior)); + let size = Size::new(500., 570.); + let graph = Size::new(1800., 2400.); + let mut view = fixture_view( + &app.behavior.scenario, + app.scenario_context().unwrap(), + false, + 68., + ); + let mut tree = widget::Tree::new(view.as_widget()); + redraw(&mut view, &mut tree, size, &mut app); + let first_viewport = app.behavior.scenario.presentation.viewport.unwrap(); + navigation_event(&mut app, |ctx| CanvasEvent::Zoom(ctx, None)); + assert!(app.behavior.scenario.presentation.scale(graph) < 1.); + + navigation_event(&mut app, |ctx| CanvasEvent::OpenUse(ctx, reference)); + assert_eq!(app.scenario_context().unwrap().scenario, b); + assert!(app.behavior.scenario.presentation.viewport.is_none()); + view = fixture_view( + &app.behavior.scenario, + app.scenario_context().unwrap(), + false, + 68., + ); + tree.diff(view.as_widget()); + redraw(&mut view, &mut tree, size, &mut app); + assert_eq!( + app.behavior.scenario.presentation.viewport, + Some(first_viewport) + ); + navigation_event(&mut app, |ctx| CanvasEvent::Zoom(ctx, None)); + let fitted = app.behavior.scenario.presentation.scale(graph); + assert!(graph.width * fitted <= first_viewport.width - 16.); + assert!(graph.height * fitted <= first_viewport.height - 16.); + + let prior_document = app.scenario_context().unwrap().document; + app = App::with_project(project); + let _ = app.update(Message::Select(b)); + let _ = app.update(Message::Page(crate::app::Page::Behavior)); + let context = app.scenario_context().unwrap(); + assert_ne!(context.document, prior_document); + assert_eq!( + context.scenario, b, + "semantic UUID is retained across documents" + ); + assert!(app.behavior.scenario.presentation.viewport.is_none()); + let accepted = app.document.snapshot(); + view = fixture_view(&app.behavior.scenario, context, false, 68.); + tree.diff(view.as_widget()); + redraw(&mut view, &mut tree, size, &mut app); + assert_eq!( + app.behavior.scenario.presentation.viewport, + Some(first_viewport) + ); + navigation_event(&mut app, |ctx| CanvasEvent::Zoom(ctx, None)); + assert_eq!(app.behavior.scenario.presentation.scale(graph), fitted); + assert!(std::sync::Arc::ptr_eq(&accepted, &app.document.snapshot())); + assert!(!app.document.can_undo()); +} + #[test] fn scenario_workspace_open_and_back_restore_owner_and_mounted_scroll_after_preselection() { use super::super::direct_tests::{navigation_event, navigation_fixture};