diff --git a/src/app/command_driver.rs b/src/app/command_driver.rs index 09eb09718..d33b27233 100644 --- a/src/app/command_driver.rs +++ b/src/app/command_driver.rs @@ -1287,6 +1287,7 @@ impl OpenCADStudio { CmdResult::CommitDimension { mut entity, association, + preserve_base_style, } => { let label = self.history_label_from_active_cmd(i, "DIMENSION"); let association_mode = self.tabs[i] @@ -1300,6 +1301,17 @@ impl OpenCADStudio { acadrust::entities::Dimension::Ordinate(_) ) ); + let inherited_dimension = if preserve_base_style { + match &entity { + acadrust::EntityType::Dimension(dimension) => Some(( + dimension.base().common.layer.clone(), + dimension.base().style_name.clone(), + )), + _ => None, + } + } else { + None + }; let pending = if association_mode == 0 { let layer = self.tabs[i].active_layer.clone(); if layer != "0" || entity.as_entity().layer().is_empty() { @@ -1330,6 +1342,12 @@ impl OpenCADStudio { &self.tabs[i].scene.document, &mut entity, ); + if let (Some((layer, style_name)), acadrust::EntityType::Dimension(dimension)) = + (inherited_dimension, &mut entity) + { + dimension.base_mut().common.layer = layer; + dimension.base_mut().style_name = style_name; + } let pieces = crate::modules::draw::modify::explode::explode_entity( &entity, &self.tabs[i].scene.document, @@ -1345,7 +1363,10 @@ impl OpenCADStudio { } else { let delta_safe = self.delta_add_safe(i, &entity); let pending = self.begin_undo(i, label, 1, delta_safe); - if let Some(handle) = self.commit_entity_handle(entity) { + if let Some(handle) = self.commit_entity_handle_with_dimension_policy( + entity, + preserve_base_style, + ) { if association_mode == 2 { let mut changes = vec![ (handle, crate::scene::ChangeKind::Modified), diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 39d4cd93c..31f72f161 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -931,6 +931,7 @@ impl OpenCADStudio { | "CENTERCROSSSIZE" | "CENTERCROSSGAP" | "CENTERMARKEXE" + | "DIMCONTINUEMODE" ) => { return self.dispatch_styleprops(&format!("SETVAR {cmd}"), i); @@ -953,7 +954,7 @@ impl OpenCADStudio { let value = it.next().map(|s| s.trim().to_string()); if name.is_empty() || name == "?" { self.command_line.push_info( - "SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG TEXTFILL CLIPROMPTLINES ATTREQ ATTDIA DIMASSOC ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE DONUTID DONUTOD CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE | CLAYER CELTYPE TEXTSTYLE (read-only)", + "SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG TEXTFILL CLIPROMPTLINES ATTREQ ATTDIA DIMASSOC DIMCONTINUEMODE ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE DONUTID DONUTOD CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE | CLAYER CELTYPE TEXTSTYLE (read-only)", ); } else { let frame_kind = crate::scene::frame::kind_for_name(&name); @@ -1069,6 +1070,28 @@ impl OpenCADStudio { } return Some(self.finish_dispatch(cmd)); } + if name == "DIMCONTINUEMODE" { + let current = self.dimension_continue_mode; + if let Some(value) = &value { + match value.parse::() { + Ok(mode @ 0..=1) => { + self.dimension_continue_mode = mode; + self.persist_settings_if_changed(); + self.command_line + .push_output(&format!("DIMCONTINUEMODE = {mode}")); + } + _ => self.command_line.push_error( + "SETVAR: DIMCONTINUEMODE requires 0 or 1.", + ), + } + } else { + self.command_line.push_output(crate::tf!( + "Enter new value for {name} <{current}>:" + ).as_ref()); + self.pending_setvar = Some(name.clone()); + } + return Some(self.finish_dispatch(cmd)); + } if matches!(name.as_str(), "DONUTID" | "DONUTOD") { let current = if name == "DONUTID" { crate::modules::draw::defaults::get_donut_inner_diameter() diff --git a/src/app/mod.rs b/src/app/mod.rs index b18e53012..e4f0fcb84 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -465,6 +465,8 @@ pub(super) struct OpenCADStudio { options_tab: crate::ui::window::options::OptionsTab, /// Controls whether the TEXTEDIT command repeats automatically (0 = Multiple, 1 = Single). pub texteditmode: bool, + /// Creation-style policy used by continuing and baseline dimensions. + pub dimension_continue_mode: i16, /// When true (default), saving over an existing file first writes a `.bak` /// copy of it for recovery (#205). Toggle with the ISAVEBAK command. pub backup_on_save: bool, @@ -3210,6 +3212,7 @@ impl OpenCADStudio { dyn_input: true, options_tab: crate::ui::window::options::OptionsTab::General, texteditmode: false, + dimension_continue_mode: 1, backup_on_save: true, file_assoc_enabled: true, savetime_min: 10, diff --git a/src/app/properties.rs b/src/app/properties.rs index 006877cc4..6129dd8b8 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -2455,10 +2455,33 @@ impl OpenCADStudio { /// (or `None` if it could not be added). Lets callers follow up — e.g. /// open the in-place text editor on a freshly created MultiLeader. pub(super) fn commit_entity_handle( + &mut self, + entity: acadrust::EntityType, + ) -> Option { + self.commit_entity_handle_with_dimension_policy(entity, false) + } + + /// Commit an entity while optionally retaining a dimension's source layer + /// and dimension style. DIMCONTINUEMODE=1 uses this path; ordinary + /// creation continues to receive the current ribbon/style defaults. + pub(super) fn commit_entity_handle_with_dimension_policy( &mut self, mut entity: acadrust::EntityType, + preserve_dimension_layer_and_style: bool, ) -> Option { let i = self.active_tab; + let is_dimension = matches!(&entity, acadrust::EntityType::Dimension(_)); + let inherited_dimension = if preserve_dimension_layer_and_style { + match &entity { + acadrust::EntityType::Dimension(dimension) => Some(( + dimension.base().common.layer.clone(), + dimension.base().style_name.clone(), + )), + _ => None, + } + } else { + None + }; if let acadrust::EntityType::Table(table) = &mut entity { const PREFIX: &str = "__OPENCAD_LINK_PENDING__"; if let Some(path) = table.name.strip_prefix(PREFIX).map(str::to_string) { @@ -2560,6 +2583,12 @@ impl OpenCADStudio { &self.tabs[i].scene.document, &mut entity, ); + if let (Some((layer, style_name)), acadrust::EntityType::Dimension(dimension)) = + (inherited_dimension, &mut entity) + { + dimension.base_mut().common.layer = layer; + dimension.base_mut().style_name = style_name; + } // Smart centre objects carry their own drawing-level creation style. // Apply it after the generic ribbon style so ordinary LINE entities @@ -2719,6 +2748,9 @@ impl OpenCADStudio { self.tabs[i].last_draw_anchor = Some(handle); } } + if is_dimension { + self.tabs[i].scene.last_created_dimension = new_handle; + } new_handle } } diff --git a/src/app/settings.rs b/src/app/settings.rs index 8b65c73e5..8caa5f994 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -198,6 +198,10 @@ pub struct UserSettings { pub osmode: i32, /// Controls whether the TEXTEDIT command repeats automatically (0 = Multiple, 1 = Single). pub texteditmode: bool, + /// DIMCONTINUEMODE: 1 inherits the base dimension's layer/style; 0 uses + /// the current creation layer/style. Registry-style, app-level preference. + #[serde(default = "default_dimension_continue_mode")] + pub dimension_continue_mode: i16, /// TEXTFILL: fill TrueType glyphs (true) or draw them hollow (false). pub textfill: bool, /// When true, saving over an existing file first copies it to a sibling @@ -247,6 +251,10 @@ fn default_clipromptlines() -> i32 { 3 } +fn default_dimension_continue_mode() -> i16 { + 1 +} + fn deserialize_clipromptlines<'de, D>(de: D) -> Result where D: serde::Deserializer<'de>, @@ -284,6 +292,7 @@ impl Default for UserSettings { // off (suppress bit 16384). osmode: 575 | OSMODE_SUPPRESS, texteditmode: false, + dimension_continue_mode: 1, textfill: true, backup_on_save: true, file_assoc_enabled: true, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index bbf906eae..0e85da3ce 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -382,6 +382,7 @@ impl OpenCADStudio { self.snapper.snap_enabled, ), texteditmode: self.texteditmode, + dimension_continue_mode: self.dimension_continue_mode, textfill: crate::scene::text::sdf_atlas::textfill(), backup_on_save: self.backup_on_save, file_assoc_enabled: self.file_assoc_enabled, @@ -440,6 +441,7 @@ impl OpenCADStudio { self.snapper.enabled = modes.into_iter().collect(); self.snapper.snap_enabled = snap_enabled; self.texteditmode = s.texteditmode; + self.dimension_continue_mode = s.dimension_continue_mode.clamp(0, 1); crate::scene::text::sdf_atlas::set_textfill(s.textfill); self.backup_on_save = s.backup_on_save; self.file_assoc_enabled = s.file_assoc_enabled; diff --git a/src/command.rs b/src/command.rs index d4a2312b3..e8bf675e8 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1248,6 +1248,9 @@ pub enum CmdResult { CommitDimension { entity: EntityType, association: DimensionAssociationInput, + /// Retain the source dimension's layer and style instead of replacing + /// them with the current creation defaults (DIMCONTINUEMODE=1). + preserve_base_style: bool, }, /// Commit a Model-tab 3D solid: the acadrust entity (for selection / /// persistence) plus its B-rep (cached for boolean ops + shaded diff --git a/src/modules/annotate/aligned_dim.rs b/src/modules/annotate/aligned_dim.rs index 2ec212d1e..dafc2183b 100644 --- a/src/modules/annotate/aligned_dim.rs +++ b/src/modules/annotate/aligned_dim.rs @@ -135,6 +135,7 @@ impl CadCommand for AlignedDimensionCommand { CmdResult::CommitDimension { entity: self.plane.place_entity(EntityType::Dimension(Dimension::Aligned(dim))), association: DimensionAssociationInput::Infer(self.source_handle), + preserve_base_style: false, } } } diff --git a/src/modules/annotate/angular_dim.rs b/src/modules/annotate/angular_dim.rs index 6bd3ef2e4..f1c00059f 100644 --- a/src/modules/annotate/angular_dim.rs +++ b/src/modules/annotate/angular_dim.rs @@ -234,6 +234,7 @@ impl AngularDimensionCommand { CmdResult::CommitDimension { entity, association: DimensionAssociationInput::Explicit(self.source_refs.clone()), + preserve_base_style: false, } } diff --git a/src/modules/annotate/arc_length_dim.rs b/src/modules/annotate/arc_length_dim.rs index f0225c1c9..434eabbe6 100644 --- a/src/modules/annotate/arc_length_dim.rs +++ b/src/modules/annotate/arc_length_dim.rs @@ -265,6 +265,7 @@ impl ArcLengthDimensionCommand { CmdResult::CommitDimension { entity: plane.place_entity(EntityType::Dimension(Dimension::Arc(dimension))), association, + preserve_base_style: false, } } } diff --git a/src/modules/annotate/diameter_dim.rs b/src/modules/annotate/diameter_dim.rs index 010434c71..946cde255 100644 --- a/src/modules/annotate/diameter_dim.rs +++ b/src/modules/annotate/diameter_dim.rs @@ -113,6 +113,7 @@ impl CadCommand for DiameterDimensionCommand { entity: source_plane .place_entity(EntityType::Dimension(Dimension::Diameter(dim))), association: DimensionAssociationInput::Infer(self.source_handle), + preserve_base_style: false, } } } diff --git a/src/modules/annotate/jogged_radius_dim.rs b/src/modules/annotate/jogged_radius_dim.rs index fdfc6097b..2363082b1 100644 --- a/src/modules/annotate/jogged_radius_dim.rs +++ b/src/modules/annotate/jogged_radius_dim.rs @@ -139,6 +139,7 @@ impl JoggedRadiusDimensionCommand { dimension, ))), association, + preserve_base_style: false, } } } diff --git a/src/modules/annotate/linear_dim.rs b/src/modules/annotate/linear_dim.rs index c2f927c80..fd6d6d6c5 100644 --- a/src/modules/annotate/linear_dim.rs +++ b/src/modules/annotate/linear_dim.rs @@ -187,6 +187,7 @@ impl CadCommand for LinearDimensionCommand { CmdResult::CommitDimension { entity, association: DimensionAssociationInput::Infer(self.source_handle), + preserve_base_style: false, } } } diff --git a/src/modules/annotate/ordinate_dim.rs b/src/modules/annotate/ordinate_dim.rs index 4ac1d8a17..221523c7f 100644 --- a/src/modules/annotate/ordinate_dim.rs +++ b/src/modules/annotate/ordinate_dim.rs @@ -116,6 +116,7 @@ impl CadCommand for OrdinateDimCommand { Dimension::Ordinate(dim), )), association: DimensionAssociationInput::Infer(None), + preserve_base_style: false, } } } diff --git a/src/modules/annotate/radius_dim.rs b/src/modules/annotate/radius_dim.rs index 62a833489..10681bad8 100644 --- a/src/modules/annotate/radius_dim.rs +++ b/src/modules/annotate/radius_dim.rs @@ -111,6 +111,7 @@ impl CadCommand for RadiusDimensionCommand { CmdResult::CommitDimension { entity: source_plane.place_entity(EntityType::Dimension(Dimension::Radius(dim))), association: DimensionAssociationInput::Infer(self.source_handle), + preserve_base_style: false, } } } diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 0894fe12c..161d2a454 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -1420,6 +1420,11 @@ pub struct Scene { pub selection: Rc>, /// The CAD document — single source of truth for all entities. pub document: CadDocument, + /// Last dimension created during this application session. This is + /// intentionally not reconstructed from file handles: continuation and + /// baseline commands must not treat an old, merely high-handle dimension + /// loaded from disk as the user's most recently created dimension. + pub last_created_dimension: Option, /// File-open-prepared index for non-graphical semantic object lookups. pub(crate) object_data_cache: crate::entities::object_data::ObjectDataCache, /// Native AcDbLight/Sun inputs, separated by rendered block and viewport @@ -1848,6 +1853,7 @@ impl Scene { model_pane_min_px: std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)), selection: Rc::new(RefCell::new(SelectionState::default())), document: CadDocument::new(), + last_created_dimension: None, object_data_cache: crate::entities::object_data::ObjectDataCache::default(), lighting_cache: RefCell::new(HashMap::default()), selected: HashSet::default(),