forked from 1b-agent/opencadstudio-upstream
Layouts reopen in the viewport they were saved in (#1670)
A save records the entered model viewport (or the sheet) as the layout's last active viewport, and opening the layout enters it again with its UCS. Picks up the codec fix that kept a last-active link from being read as the sheet viewport (codec d57097c, kernel b40fa59, graph 2360341). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
072aeb9dbf
commit
2c329b2889
9 files changed
+102
-13
No files matched your search
Generated
+4
-4
@@ -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",
|
||||
]
|
||||
|
||||
+4
-4
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
@@ -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"] }
|
||||
@@ -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"
|
||||
|
||||
Generated
+1
-1
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Handle> {
|
||||
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,
|
||||
|
||||
@@ -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:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user