Fix: paper limits, Cohen-Sutherland clipping, frozen layers UI, PDF improvements

Paper limits:
- Change A4 fallback from 12×9 to 297×210 mm in paper_limits()

Context menu:
- Translate layout context menu labels to English (Rename / Delete)

Viewport clipping:
- Replace AABB-only culling with proper Cohen-Sutherland line clipping
  in viewport_content_wires(); each projected segment is now clipped at
  the exact viewport boundary instead of being included or discarded whole
- Add cs_clip() and clip_polyline_to_rect() free functions in scene/mod.rs

Frozen layers per-viewport UI:
- Inject a "Frozen Layers" EditText property in the Properties panel for
  viewport entities (layer names resolved from handles at display time)
- Handle "frozen_layers" in PropGeomCommit: parse comma-separated names,
  resolve to layer handles, update vp.frozen_layers in-place

PDF export improvements:
- Add offset_x/offset_y params to export_pdf() for model-space normalization:
  coordinates are shifted so the drawing origin maps to the page origin
- Model space export computes extents via model_space_extents() (now public)
  and adds a 5 % margin; falls back to A4 landscape for empty drawings
- Skip __paper_boundary__ wire in PDF (white background covers it)
- Map yellow (active viewport border) → black and cyan (vp border) → dark
  blue for print-friendly output

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Sonnet 4.6 committed 2026-03-31 08:18:29 +03:00
1 parent e1d296da10
commit 845770938c
5 files changed
+262 -67

No files matched your search

+23
View File
@@ -55,6 +55,29 @@ impl H7CAD {
let group_names = self.tabs[i].scene.group_names_for_entity(handle);
let mut sections =
dispatch::properties_sectioned(handle, entity, &text_style_names);
// Inject frozen-layer property for viewports (requires doc access).
if let acadrust::EntityType::Viewport(vp) = entity {
let frozen_names: Vec<String> = vp
.frozen_layers
.iter()
.filter_map(|&h| {
self.tabs[i].scene.document.layers.iter()
.find(|l| l.handle == h)
.map(|l| l.name.clone())
})
.collect();
if let Some(geom) = sections.last_mut() {
geom.props.push(crate::scene::object::Property {
label: "Frozen Layers".to_string(),
field: "frozen_layers",
value: crate::scene::object::PropValue::EditText(
frozen_names.join(", "),
),
});
}
}
if !group_names.is_empty() {
let label = group_names.join(", ");
if let Some(general) = sections.first_mut() {