forked from 1b-agent/opencadstudio-upstream
fix(style): block edits to xref-dependent dimstyles
This commit is contained in:
1 parent
c0baeda6a6
commit
43bdd18061
3 files changed
+138
-2
No files matched your search
+24
-1
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
Reference in new issue
Block a user