feat(scale): drive scales from the drawing's scale list

Read the model-space annotation scale from the standard CANNOSCALE /
CANNOSCALEVALUE header variables instead of a user-variable hack, and
populate both the status-bar scale picker and the viewport Scale
property purely from the drawing's ACAD_SCALELIST — no built-in
fallback set. Xref-derived scales (`_XREF` suffix, `name|` prefix)
are filtered out so only the host drawing's own scales appear.

Bumps the patched acadrust to the commit that adds CANNOSCALE/
CANNOSCALEVALUE read/write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-04 16:18:01 +03:00
commit edc8cbc969
8 changed files with 128 additions and 30 deletions

View file

@ -144,6 +144,34 @@ impl OpenCADStudio {
});
}
}
// Drive the viewport scale picker from the drawing's
// own scale list instead of a built-in set.
let file_scales = self.tabs[i].scene.scale_list();
if !file_scales.is_empty() {
let eff = crate::scene::vp_effective_scale(
vp.custom_scale,
vp.view_height,
vp.height,
);
let selected = file_scales
.iter()
.find(|(_, _, f)| (f - eff).abs() < 0.001 * f.max(0.001))
.map(|(n, _, _)| n.clone())
.unwrap_or_default();
let options: Vec<String> =
file_scales.iter().map(|(n, _, _)| n.clone()).collect();
if let Some(geom) = sections.last_mut() {
if let Some(prop) =
geom.props.iter_mut().find(|p| p.field == "vscale_std")
{
prop.value = crate::scene::object::PropValue::Choice {
selected,
options,
};
}
}
}
}
// Inject DimStyle picker for Dimension entities.

View file

@ -163,9 +163,12 @@ impl OpenCADStudio {
self.tabs[i].current_path = Some(path.clone());
self.tabs[i].scene.document = doc;
let stored = self.tabs[i].scene.document.header.user_real1;
// Current model-space annotation scale comes from the drawing's
// CANNOSCALEVALUE (paper/drawing factor); the multiplier we use
// for text/dim sizing is its inverse (1:50 -> 0.02 -> 50.0).
let cannoscale_value = self.tabs[i].scene.document.header.annotation_scale_value;
self.tabs[i].scene.annotation_scale =
if stored > 1e-9 { stored as f32 } else { 1.0 };
if cannoscale_value > 1e-9 { (1.0 / cannoscale_value) as f32 } else { 1.0 };
// Auto-resolve XREFs relative to the opened file's directory.
if let Some(base_dir) = path.parent() {
@ -632,8 +635,7 @@ impl OpenCADStudio {
let (_, version) = crate::io::parse_save_format(&self.save_dialog_format);
let close = self.close_save_dialog_window();
let i = self.active_tab;
self.tabs[i].scene.document.header.user_real1 =
self.tabs[i].scene.annotation_scale as f64;
sync_annotation_scale_header(&mut self.tabs[i].scene);
match crate::io::save_as_version(&self.tabs[i].scene.document, &path, version) {
Ok(()) => {
self.command_line
@ -7691,6 +7693,37 @@ impl OpenCADStudio {
/// Parse a scale string like "1:50" or "2:1" into (numerator, denominator).
/// Returns (1.0, 1.0) for "Fit" or unknown formats.
/// Sync the model-space annotation scale into the standard CANNOSCALE /
/// CANNOSCALEVALUE header variables before a save, so the scale round-trips
/// through the file (and is read correctly by other CAD applications).
fn sync_annotation_scale_header(scene: &mut Scene) {
let anno = scene.annotation_scale;
let value = if anno.abs() > 1e-9 { 1.0 / anno as f64 } else { 1.0 };
// Prefer the name of a matching scale already in the drawing's list;
// fall back to a formatted ratio when none matches.
let name = scene
.scale_list()
.into_iter()
.find(|(_, a, _)| (a - anno).abs() < 0.001 * anno.max(0.001))
.map(|(n, _, _)| n)
.unwrap_or_else(|| format_annotation_scale_name(anno));
let hdr = &mut scene.document.header;
hdr.current_annotation_scale = name;
hdr.annotation_scale_value = value;
}
/// Format an annotation-scale multiplier as a ratio name: 50.0 -> "1:50",
/// 0.5 -> "2:1", 1.0 -> "1:1".
fn format_annotation_scale_name(anno: f32) -> String {
if anno >= 1.0 {
format!("1:{}", anno.round() as i64)
} else if anno > 0.0 {
format!("{}:1", (1.0 / anno).round() as i64)
} else {
"1:1".to_string()
}
}
fn parse_plot_scale(s: &str) -> (f64, f64) {
if s == "Fit" {
return (1.0, 1.0);

View file

@ -1163,6 +1163,7 @@ impl OpenCADStudio {
is_model,
tab.scene.annotation_scale,
tab.scene.first_viewport_scale(),
tab.scene.scale_list(),
)
} else {
iced::widget::Space::new().width(0).height(0).into()