fix(style): block edits to xref-dependent dimstyles

This commit is contained in:
Karim Jerbi committed 2026-10-18 10:40:14 +01:00
1 parent c0baeda6a6
commit 43bdd18061
3 files changed
+138 -2

No files matched your search

+24 -1
View File
@@ -12050,7 +12050,9 @@ impl OpenCADStudio {
Message::DimStyleDialogApply => {
let i = self.active_tab;
self.apply_dimstyle_bufs(i);
self.style_stage_commit();
if !self.selected_dimstyle_is_read_only() {
self.style_stage_commit();
}
Task::none()
}
Message::DimStyleDialogSelect(name) => {
@@ -12073,6 +12075,9 @@ impl OpenCADStudio {
Message::DimStyleDialogCopy => self.style_copy(crate::app::StyleKind::Dim),
Message::DimStyleDialogSetCurrent => {
// Staged: persists on Apply.
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let i = self.active_tab;
self.tabs[i].scene.document.header.current_dimstyle_name =
@@ -12093,6 +12098,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsToggle(field) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let separate_arrows = field == crate::app::DsField::Dimsah;
self.apply_ds_toggle(field);
if separate_arrows && self.ds_dimsah {
@@ -12114,6 +12122,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsToleranceMode(mode) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
self.ds_dimlim = mode == "limits";
self.ds_dimtol = matches!(mode.as_str(), "symmetrical" | "deviation");
if mode == "symmetrical" {
@@ -12128,6 +12139,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsZeroBase(field, base) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
@@ -12142,6 +12156,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsZeroFlag(field, bit) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
@@ -12156,6 +12173,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsCenterMarkMode(mode) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let size = self.ds_dimcen.trim().parse::<f64>().unwrap_or(0.09).abs();
self.ds_dimcen = match mode.as_str() {
"mark" => size.max(f64::EPSILON).to_string(),
@@ -12165,6 +12185,9 @@ impl OpenCADStudio {
Task::none()
}
Message::DsColorMore(field) => {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
self.ds_color_open = if self.ds_color_open.as_ref() == Some(&field) {
None
} else {
+112
View File
@@ -21,6 +21,18 @@ use iced::time::Instant;
use iced::{mouse, Point, Task};
impl OpenCADStudio {
pub(in crate::app) fn selected_dimstyle_is_read_only(&self) -> bool {
let Some(style) = self.tabs[self.active_tab]
.scene
.document
.dim_styles
.get(&self.dimstyle_selected)
else {
return true;
};
style.xref_dependent || style.name.contains('|')
}
pub(in crate::app) fn mlstyle_mut(
&mut self,
tab: usize,
@@ -364,6 +376,17 @@ impl OpenCADStudio {
pub(in crate::app) fn apply_dimstyle_bufs(&mut self, tab: usize) {
let doc = &mut self.tabs[tab].scene.document;
// Merged xref dimstyles are identified by their `xref|style` name.
// The codec's dependency bit is cleared during merge, so use the
// stable imported-name marker here as well as the DWG/DXF flag.
let selected_name = self.dimstyle_selected.clone();
let Some(selected) = doc.dim_styles.get(&selected_name) else {
return;
};
if selected.xref_dependent || selected.name.contains('|') {
return;
}
let text_style_handle = doc
.text_styles
.get(&self.ds_dimtxsty)
@@ -499,6 +522,9 @@ impl OpenCADStudio {
/// Update a single string buffer field.
pub(in crate::app) fn apply_ds_edit(&mut self, field: crate::app::DsField, val: String) {
if self.selected_dimstyle_is_read_only() {
return;
}
use crate::app::DsField::*;
match field {
Dimdle => self.ds_dimdle = val,
@@ -570,6 +596,9 @@ impl OpenCADStudio {
/// Toggle a boolean buffer field.
pub(in crate::app) fn apply_ds_toggle(&mut self, field: crate::app::DsField) {
if self.selected_dimstyle_is_read_only() {
return;
}
use crate::app::DsField::*;
match field {
Dimsd1 => self.ds_dimsd1 = !self.ds_dimsd1,
@@ -1260,6 +1289,9 @@ impl OpenCADStudio {
}
pub(super) fn on_ds_set_handle(&mut self, field: &'static str, value: String) -> Task<Message> {
if self.selected_dimstyle_is_read_only() {
return Task::none();
}
let i = self.active_tab;
let name = self.dimstyle_selected.clone();
let is_lt = matches!(
@@ -1358,4 +1390,84 @@ mod ds_set_handle_tests {
"picking the first arrowhead must not touch the second"
);
}
#[test]
fn xref_dimstyle_is_read_only_and_rejects_direct_edits() {
let mut app = app_with_arrow_blocks();
let i = app.active_tab;
let name = app.dimstyle_selected.clone();
let before = app.tabs[i]
.scene
.document
.dim_styles
.get(&name)
.unwrap()
.dimdle;
app.tabs[i]
.scene
.document
.dim_styles
.get_mut(&name)
.unwrap()
.xref_dependent = true;
assert!(app.selected_dimstyle_is_read_only());
app.ds_dimdle = "123".to_string();
app.apply_dimstyle_bufs(i);
let _ = app.on_ds_set_handle("dimblk1", "ARROW_A".to_string());
assert_eq!(
app.tabs[i]
.scene
.document
.dim_styles
.get(&name)
.unwrap()
.dimdle,
before
);
assert_eq!(
app.tabs[i]
.scene
.document
.dim_styles
.get(&name)
.unwrap()
.dimblk1,
codec::types::Handle::NULL
);
}
#[test]
fn merged_xref_dimstyle_name_is_read_only() {
let mut app = app_with_arrow_blocks();
let i = app.active_tab;
let old_name = app.dimstyle_selected.clone();
let mut style = app.tabs[i]
.scene
.document
.dim_styles
.get(&old_name)
.unwrap()
.clone();
let before = style.dimdle;
app.tabs[i].scene.document.dim_styles.remove(&old_name);
style.name = "ARCH|Imported".to_string();
app.tabs[i].scene.document.dim_styles.add_or_replace(style);
app.dimstyle_selected = "ARCH|Imported".to_string();
assert!(app.selected_dimstyle_is_read_only());
app.ds_dimdle = "456".to_string();
app.apply_dimstyle_bufs(i);
assert_ne!(
app.tabs[i]
.scene
.document
.dim_styles
.get("ARCH|Imported")
.unwrap()
.dimdle,
before
);
}
}
+2 -1
View File
@@ -1477,7 +1477,8 @@ impl OpenCADStudio {
}
};
let ds_sel = doc.dim_styles.get(&self.dimstyle_selected);
let read_only = false;
let read_only =
ds_sel.is_none_or(|style| style.xref_dependent || style.name.contains('|'));
let in_use = doc.entities().any(|entity| {
matches!(entity, codec::EntityType::Dimension(dimension)
if dimension.base().style_name.eq_ignore_ascii_case(&self.dimstyle_selected))