fix(layout): complete paperspace integration

Apply each layout's embedded page setup and plot style consistently across display, PDF, printing, and multi-layout output.\n\nRefs #844
This commit is contained in:
Hakan Seven committed 2026-08-26 08:58:44 +03:00
1 parent 9c8f841f71
commit 8c61d89b1e
18 files changed
+1393 -373

No files matched your search

+130 -10
View File
@@ -256,12 +256,11 @@ impl DocumentTab {
.unwrap_or(glam::DVec3::ZERO)
}
/// True when the active pane edits **model-space** geometry: the Model tab,
/// or inside a floating viewport (MSPACE). The UCS applies in both; plain
/// paper space (no active viewport) is excluded. Single predicate so every
/// UCS-aware system shares one rule. [[feedback_shared_infra]]
/// True when the active pane has a drawing coordinate plane.
pub(super) fn editing_model_space(&self) -> bool {
self.scene.current_layout == "Model" || self.scene.active_viewport.is_some()
self.scene.current_layout == "Model"
|| self.scene.active_viewport.is_some()
|| self.active_ucs.is_some()
}
/// The document's saved model-space UCS (header), as a `Ucs`. `None` when it
@@ -321,9 +320,51 @@ impl DocumentTab {
}
}
pub(super) fn ucs_from_layout(&self) -> Option<Ucs> {
let layout = self.scene.document.objects.values().find_map(|object| {
let acadrust::objects::ObjectType::Layout(layout) = object else {
return None;
};
(layout.name == self.scene.current_layout).then_some(layout)
})?;
let mut ucs = self
.scene
.document
.ucss
.iter()
.find(|ucs| ucs.handle == layout.named_ucs)
.cloned()
.unwrap_or_else(|| Ucs::new("*PAPERUCS*"));
ucs.origin = acadrust::types::Vector3::new(
layout.ucs_origin.0,
layout.ucs_origin.1,
layout.ucs_origin.2,
);
ucs.x_axis = acadrust::types::Vector3::new(
layout.ucs_x_axis.0,
layout.ucs_x_axis.1,
layout.ucs_x_axis.2,
);
ucs.y_axis = acadrust::types::Vector3::new(
layout.ucs_y_axis.0,
layout.ucs_y_axis.1,
layout.ucs_y_axis.2,
);
ucs.elevation = layout.elevation;
ucs.ortho_type = layout.ucs_ortho_type;
ucs.named_ucs_handle = layout.named_ucs;
ucs.base_ucs_handle = layout.base_ucs;
let is_world = layout.named_ucs.is_null()
&& layout.base_ucs.is_null()
&& layout.ucs_ortho_type == 0
&& layout.elevation.abs() <= f64::EPSILON
&& super::helpers::UcsXform::from_ucs(&ucs).is_identity();
(!is_world).then_some(ucs)
}
/// Set `active_ucs` to the UCS of the *current pane*: the entered viewport's
/// own per-viewport UCS, the model header UCS in the Model tab, or none in
/// plain paper space. Keeps the ViewCube in lock-step. Call on every pane
/// own per-viewport UCS, the model header UCS, or the layout UCS. Keeps the
/// ViewCube in lock-step. Call on every pane
/// change (enter/exit viewport, layout / tab switch, load) so one field
/// drives all UCS-aware systems regardless of where editing happens.
pub(super) fn refresh_active_ucs(&mut self) {
@@ -334,15 +375,52 @@ impl DocumentTab {
} else if self.scene.current_layout == "Model" {
self.model_ucs_from_header()
} else {
None
self.ucs_from_layout()
};
if self.active_block_edit.is_none()
&& self.scene.active_viewport.is_none()
&& self.scene.current_layout != "Model"
{
self.sync_paper_ucs_header();
}
self.sync_ucs_to_scene();
}
fn sync_paper_ucs_header(&mut self) {
use acadrust::types::Vector3;
let header = &mut self.scene.document.header;
match &self.active_ucs {
Some(ucs) => {
header.paper_space_ucs_origin = ucs.origin;
header.paper_space_ucs_x_axis = ucs.x_axis;
header.paper_space_ucs_y_axis = ucs.y_axis;
header.paper_elevation = ucs.elevation;
header.paper_space_ucs_name = if (ucs.named_ucs_handle.is_valid()
|| ucs.handle.is_valid())
&& !ucs.name.starts_with('*')
{
ucs.name.clone()
} else {
String::new()
};
header.paper_ucs_ortho_ref = ucs.base_ucs_handle;
header.paper_ucs_ortho_view = ucs.ortho_type;
}
None => {
header.paper_space_ucs_origin = Vector3::ZERO;
header.paper_space_ucs_x_axis = Vector3::UNIT_X;
header.paper_space_ucs_y_axis = Vector3::UNIT_Y;
header.paper_elevation = 0.0;
header.paper_space_ucs_name.clear();
header.paper_ucs_ortho_ref = Handle::NULL;
header.paper_ucs_ortho_view = 0;
}
}
}
/// Persist `active_ucs` back to its pane's storage so it round-trips: the
/// entered viewport's per-viewport UCS fields, or the document header's
/// model-space UCS in the Model tab. No-op in plain paper space. Call after
/// any UCS change.
/// model-space UCS in the Model tab, or the layout UCS. Call after a change.
pub(super) fn persist_active_ucs(&mut self) {
use acadrust::types::Vector3;
if let Some(index) = self.active_block_edit {
@@ -385,6 +463,48 @@ impl DocumentTab {
h.model_space_ucs_name.clear();
}
}
} else {
let (origin, x_axis, y_axis, elevation, ortho, named, base) =
match &self.active_ucs {
Some(ucs) => (
ucs.origin,
ucs.x_axis,
ucs.y_axis,
ucs.elevation,
ucs.ortho_type,
if ucs.named_ucs_handle.is_valid() {
ucs.named_ucs_handle
} else {
ucs.handle
},
ucs.base_ucs_handle,
),
None => (
Vector3::ZERO,
Vector3::UNIT_X,
Vector3::UNIT_Y,
0.0,
0,
Handle::NULL,
Handle::NULL,
),
};
for object in self.scene.document.objects.values_mut() {
let acadrust::objects::ObjectType::Layout(layout) = object else {
continue;
};
if layout.name == self.scene.current_layout {
layout.ucs_origin = (origin.x, origin.y, origin.z);
layout.ucs_x_axis = (x_axis.x, x_axis.y, x_axis.z);
layout.ucs_y_axis = (y_axis.x, y_axis.y, y_axis.z);
layout.elevation = elevation;
layout.ucs_ortho_type = ortho;
layout.named_ucs = named;
layout.base_ucs = base;
break;
}
}
self.sync_paper_ucs_header();
}
}