diff --git a/Cargo.lock b/Cargo.lock index eccd52d11..3e15e16fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4361,7 +4361,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=f48d673#f48d6739019b470c5b530d76ac873ffc43f7d311" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=d57097c#d57097c05c386380d56b97f6b5f396bafa1612ae" dependencies = [ "anyhow", "bitflags 2.13.1", @@ -4384,7 +4384,7 @@ dependencies = [ [[package]] name = "opencadgraph" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=a9ca185#a9ca185e1658243de2f0e19406f966c1d0150eb5" +source = "git+https://github.com/HakanSeven12/opencadgraph.git?rev=2360341#2360341dd4a159ee2294af62ab527263fb8dc9b4" dependencies = [ "opencadkernel", "serde_json", @@ -4393,7 +4393,7 @@ dependencies = [ [[package]] name = "opencadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=d8f9b7e#d8f9b7e80c1dc8aeaee7aa0becc9d1ecf2ade5fd" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=b40fa59#b40fa597ef84c75f06ba00f0e79daff0927b0ca0" dependencies = [ "cavalier_contours", "opencadcodec", @@ -4404,7 +4404,7 @@ dependencies = [ [[package]] name = "opencadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=d8f9b7e#d8f9b7e80c1dc8aeaee7aa0becc9d1ecf2ade5fd" +source = "git+https://github.com/HakanSeven12/opencadkernel.git?rev=b40fa59#b40fa597ef84c75f06ba00f0e79daff0927b0ca0" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index 07b816b80..a060b09c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ rfd = "0.17" clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "f48d673", features = ["serde"] } -kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "d8f9b7e", features = ["acis", "offset"] } -kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "d8f9b7e" } -graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "a9ca185" } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d57097c", features = ["serde"] } +kernel = { package = "opencadkernel", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "b40fa59", features = ["acis", "offset"] } +kernel-constraints = { package = "opencadkernel-constraints", git = "https://github.com/HakanSeven12/opencadkernel.git", rev = "b40fa59" } +graph = { package = "opencadgraph", git = "https://github.com/HakanSeven12/opencadgraph.git", rev = "2360341" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } # Shared SAVE serialization dispatch + web-worker wire format: one # implementation for the inline (fallback/native) path and the worker path. diff --git a/crates/ocs_plugin_api/Cargo.toml b/crates/ocs_plugin_api/Cargo.toml index 4b653eb36..a1ad2e2f7 100644 --- a/crates/ocs_plugin_api/Cargo.toml +++ b/crates/ocs_plugin_api/Cargo.toml @@ -15,7 +15,7 @@ serde_json = { version = "1", optional = true } # Pulled in only by the `host` feature, which adds the `opencadcodec`-typed # `HostApi` runtime surface. The default crate stays dependency-free so engine # crates and external tooling can depend on the manifest/ribbon contract cheaply. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "f48d673", optional = true, features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d57097c", optional = true, features = ["serde"] } # Runtime IPC and serialization (host feature only). interprocess = { version = "2", optional = true } @@ -39,7 +39,7 @@ serde_json = "1" serde = { version = "1", features = ["derive"] } cargo-lock = "11" # opencadcodec is scanned at build time to generate the embedded type registry. -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "f48d673", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d57097c", features = ["serde"] } [dev-dependencies] serde_json = "1" diff --git a/crates/ocs_save/Cargo.toml b/crates/ocs_save/Cargo.toml index d9684d163..bfa178bff 100644 --- a/crates/ocs_save/Cargo.toml +++ b/crates/ocs_save/Cargo.toml @@ -10,6 +10,6 @@ publish = false # exactly one implementation. No UI/app dependencies — only the codec + serde. [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "f48d673", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d57097c", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } diff --git a/crates/ocs_web_worker/Cargo.toml b/crates/ocs_web_worker/Cargo.toml index 1818412b8..13ff4552a 100644 --- a/crates/ocs_web_worker/Cargo.toml +++ b/crates/ocs_web_worker/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "f48d673", features = ["serde"] } +codec = { package = "opencadcodec", git = "https://github.com/HakanSeven12/opencadcodec.git", rev = "d57097c", features = ["serde"] } bincode = "1.3" serde = { version = "1", features = ["derive"] } console_error_panic_hook = "0.1" diff --git a/plugins/opencad-python/Cargo.lock b/plugins/opencad-python/Cargo.lock index ae9c71e96..5a9e11916 100644 --- a/plugins/opencad-python/Cargo.lock +++ b/plugins/opencad-python/Cargo.lock @@ -1264,7 +1264,7 @@ dependencies = [ [[package]] name = "opencadcodec" version = "0.6.0" -source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=f48d673#f48d6739019b470c5b530d76ac873ffc43f7d311" +source = "git+https://github.com/HakanSeven12/opencadcodec.git?rev=d57097c#d57097c05c386380d56b97f6b5f396bafa1612ae" dependencies = [ "anyhow", "bitflags", diff --git a/src/app/update/file.rs b/src/app/update/file.rs index c4cd4b69c..94f571b71 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -2196,6 +2196,12 @@ impl OpenCADStudio { self.tabs[i].scene.load_current_layout_state(); self.tabs[i].refresh_active_ucs(); } + // A layout saved with a model viewport entered reopens inside it, + // with that viewport's UCS (#1670). + let enter_viewport_task = self.tabs[i] + .scene + .saved_entered_viewport() + .map_or_else(Task::none, |handle| Task::done(Message::EnterViewport(handle))); // The tab may have been reused for the newly opened file. Any Plot // dialog cache belongs to the previous/startup drawing and must not @@ -2317,6 +2323,7 @@ impl OpenCADStudio { interaction_task, startup_script_task, sheet_set_task, + enter_viewport_task, ]) } @@ -2640,6 +2647,7 @@ impl OpenCADStudio { if self.tabs[i].active_block_edit.is_none() { self.tabs[i].scene.sync_camera_to_document(); self.tabs[i].last_synced_camera_gen = self.tabs[i].scene.camera_generation; + self.tabs[i].scene.sync_active_viewport_to_document(); } } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 208296bb7..3a137a715 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -4661,6 +4661,46 @@ impl Scene { crate::io::set_saved_active_layout(&mut self.document, &self.current_layout); } + /// Record the entered viewport (or the sheet, in paper space) as the + /// current layout's last active viewport, which reopens it (#1670). + pub fn sync_active_viewport_to_document(&mut self) { + let Some(handle) = self.current_layout_object_handle() else { + return; + }; + let sheet = match self.document.objects.get(&handle) { + Some(ObjectType::Layout(layout)) => { + Self::layout_sheet_viewport_handle(&self.document, layout) + } + _ => return, + }; + let active = self.active_viewport.unwrap_or(sheet); + if let Some(ObjectType::Layout(layout)) = self.document.objects.get_mut(&handle) { + layout.viewport = active; + } + } + + /// The model viewport the current layout was saved with entered: its + /// last active viewport when that is an on viewport other than the sheet. + pub fn saved_entered_viewport(&self) -> Option { + let handle = self.current_layout_object_handle()?; + let Some(ObjectType::Layout(layout)) = self.document.objects.get(&handle) else { + return None; + }; + let viewport = layout.viewport; + let sheet = Self::layout_sheet_viewport_handle(&self.document, layout); + if viewport.is_null() || viewport == sheet { + return None; + } + match self.document.get_entity(viewport) { + Some(EntityType::Viewport(vp)) + if vp.common.owner_handle == layout.block_record && !vp.status.is_off => + { + Some(viewport) + } + _ => None, + } + } + pub(crate) fn layout_sheet_viewport_handle( document: &codec::CadDocument, layout: &codec::objects::Layout, diff --git a/tests/active_space_roundtrip.rs b/tests/active_space_roundtrip.rs index 7387be1ec..85739c387 100644 --- a/tests/active_space_roundtrip.rs +++ b/tests/active_space_roundtrip.rs @@ -77,3 +77,44 @@ fn ctab_is_created_when_absent_then_updated_in_place() { Some("Layout3") ); } + +/// A layout saved with a model viewport entered reopens inside it; saved +/// from paper space it reopens on the sheet (#1670). +#[test] +fn entered_viewport_survives_a_save_and_reload() { + use codec::{entities::Viewport, EntityType}; + for format in ["dxf", "dwg"] { + let mut scene = Scene::new(); + scene.set_current_layout("Layout1".to_string()); + let mut sheet = Viewport::new(); + sheet.id = 1; + sheet.width = 420.0; + sheet.height = 297.0; + let sheet = scene.add_entity(EntityType::Viewport(sheet)); + let mut model = Viewport::new(); + model.id = 2; + model.width = 100.0; + model.height = 80.0; + model.view_height = 80.0; + let model = scene.add_entity(EntityType::Viewport(model)); + assert_ne!(sheet, model); + + for entered in [Some(model), None] { + scene.active_viewport = entered; + scene.sync_active_viewport_to_document(); + let bytes = + OpenCADStudio::io::save_to_bytes(&scene.document, format, scene.document.version) + .expect("save"); + let doc = OpenCADStudio::io::load_bytes(&format!("roundtrip.{format}"), bytes) + .expect("reload"); + let mut reopened = Scene::new(); + reopened.document = doc; + reopened.current_layout = "Layout1".to_string(); + assert_eq!( + reopened.saved_entered_viewport().is_some(), + entered.is_some(), + "{format}: entered {entered:?}" + ); + } + } +}