feat(layout): reopen a drawing in the space it was saved in

Files saved while a paper layout was active reopened in Model space
because the loader hardcoded the current layout to "Model" and never
consulted the space recorded in the file.

The active space is a standard part of the format and acadrust already
round-trips it: $TILEMODE (header.show_model_space) for model-vs-paper,
and the CTAB current-tab variable for the exact layout name.

- Read: on open, pick the current layout from CTAB (when it names a
  layout that exists), else $TILEMODE (Model, or the first paper layout).
- Write: Scene::sync_active_space_to_document() mirrors the active layout
  back into the document (show_model_space + CTAB). It runs from
  set_current_layout, so every active-layout change — the status-bar tab,
  the Layout Manager's Set Current, create / rename / delete, and
  undo/redo — keeps the document in sync for the next save.

$TILEMODE is the guaranteed mechanism (read and written for both DXF and
DWG); CTAB refines the exact tab when the variable is present.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-12 01:01:40 +03:00
1 parent 5215a9773b
commit dd3ce6767c
6 files changed
+53 -8

No files matched your search

+22 -1
View File
@@ -489,7 +489,28 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
}
self.tabs[i].scene.selected = rustc_hash::FxHashSet::default();
self.tabs[i].scene.preview_wires = vec![];
self.tabs[i].scene.current_layout = "Model".to_string();
// Reopen in whichever space the file was saved in — the CTAB
// tab name when recorded, else the $TILEMODE model/paper flag —
// instead of always landing in Model.
{
let names = self.tabs[i].scene.layout_names();
let saved = crate::io::saved_active_layout(&self.tabs[i].scene.document)
.and_then(|n| {
names.iter().find(|x| x.eq_ignore_ascii_case(&n)).cloned()
});
self.tabs[i].scene.current_layout = match saved {
Some(n) => n,
None if self.tabs[i].scene.document.header.show_model_space => {
"Model".to_string()
}
// Paper was active but no CTAB — fall back to the first
// paper layout (names[0] is always "Model").
None => names
.into_iter()
.nth(1)
.unwrap_or_else(|| "Model".to_string()),
};
}
// Rebuild the Isolate/Hide set from the entities the file itself
// marks invisible (DXF code 60), so hidden objects stay hidden on
// reopen and End Isolation can bring them back.
+3 -5
View File
@@ -2569,7 +2569,7 @@ impl OpenCADStudio {
self.push_undo_snapshot(i, "LAYOUT RENAME");
self.tabs[i].scene.rename_layout(&old_name, &new_name);
if self.tabs[i].scene.current_layout == old_name {
self.tabs[i].scene.current_layout = new_name.clone();
self.tabs[i].scene.set_current_layout(new_name.clone());
}
self.layout_manager_selected = new_name.clone();
self.tabs[i].dirty = true;
@@ -2610,8 +2610,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
// Switch to Model if active layout was deleted.
if self.tabs[i].scene.current_layout == name {
self.tabs[i].scene.current_layout = "Model".to_string();
self.tabs[i].scene.bump_geometry();
self.tabs[i].scene.set_current_layout("Model".to_string());
}
self.layout_manager_selected = "Model".to_string();
self.layout_manager_rename_buf = String::new();
@@ -2658,8 +2657,7 @@ impl OpenCADStudio {
Message::LayoutManagerSetCurrent => {
let i = self.active_tab;
let name = self.layout_manager_selected.clone();
self.tabs[i].scene.current_layout = name.clone();
self.tabs[i].scene.bump_geometry();
self.tabs[i].scene.set_current_layout(name.clone());
self.command_line
.push_output(&format!("Switched to layout '{name}'."));
Task::none()
+2 -2
View File
@@ -3050,7 +3050,7 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
}
}
}
self.tabs[i].scene.current_layout = new_name.clone();
self.tabs[i].scene.set_current_layout(new_name.clone());
// Safety net — `add_layout` already creates the overall
// sheet viewport; this covers any path that doesn't.
self.tabs[i].scene.ensure_sheet_viewport(&new_name);
@@ -3085,7 +3085,7 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
self.push_undo_snapshot(i, "LAYOUT RENAME");
self.tabs[i].scene.rename_layout(&orig, &new_name);
if self.tabs[i].scene.current_layout == orig {
self.tabs[i].scene.current_layout = new_name.clone();
self.tabs[i].scene.set_current_layout(new_name.clone());
}
self.tabs[i].dirty = true;
self.command_line