diff --git a/src/app/mtext_editor.rs b/src/app/mtext_editor.rs index e51f8208c..8e78f5a0c 100644 --- a/src/app/mtext_editor.rs +++ b/src/app/mtext_editor.rs @@ -1108,6 +1108,14 @@ impl super::OpenCADStudio { let Some(ed) = self.mtext_editor.take() else { return false }; let body_empty = ed.content.text().trim().is_empty(); let mut mt = ed.build_mtext(); + let annotative = ed.editing.is_none() + && crate::scene::annotative::text_style_is_annotative( + &self.tabs[i].scene.document, + &mt.style, + ); + if annotative { + mt.is_annotative = true; + } if body_empty { // Empty content: drop a new entity; leave an edited one untouched. self.refresh_properties(); @@ -1141,7 +1149,17 @@ impl super::OpenCADStudio { // Align new MText to the active UCS (text runs along the UCS X axis). mt.rotation = self.tabs[i].ucs_rotation_angle(); self.push_undo_snapshot(i, "MTEXT"); - self.commit_entity(EntityType::MText(mt)); + let handle = self.commit_entity_handle(EntityType::MText(mt)); + if annotative { + let scale = self.tabs[i].scene.current_annotation_scale_handle(); + if let (Some(handle), Some(scale)) = (handle, scale) { + crate::scene::annotative::create_annotation_context( + &mut self.tabs[i].scene.document, + handle, + scale, + ); + } + } self.tabs[i].dirty = true; } self.refresh_properties(); @@ -1163,6 +1181,14 @@ impl super::OpenCADStudio { ), None => return, }; + let annotative = editing.is_none() + && crate::scene::annotative::text_style_is_annotative( + &self.tabs[i].scene.document, + &mt.style, + ); + if annotative { + mt.is_annotative = true; + } if body_empty { return; } @@ -1195,6 +1221,16 @@ impl super::OpenCADStudio { self.push_undo_snapshot(i, "MTEXT"); let handle = self.commit_entity_handle(EntityType::MText(mt)); self.tabs[i].dirty = true; + if annotative { + let scale = self.tabs[i].scene.current_annotation_scale_handle(); + if let (Some(handle), Some(scale)) = (handle, scale) { + crate::scene::annotative::create_annotation_context( + &mut self.tabs[i].scene.document, + handle, + scale, + ); + } + } // Bind the editor to the fresh entity so the next Apply updates it. if let (Some(h), Some(ed)) = (handle, self.mtext_editor.as_mut()) { ed.editing = Some(h); diff --git a/src/app/text_inline.rs b/src/app/text_inline.rs index 5e7bf9d2b..91086d733 100644 --- a/src/app/text_inline.rs +++ b/src/app/text_inline.rs @@ -227,10 +227,24 @@ impl super::OpenCADStudio { if !cur_style.is_empty() { t.style = cur_style; } + let annotative = crate::scene::annotative::text_style_is_annotative( + &self.tabs[i].scene.document, + &t.style, + ); // Align new text to the active UCS (baseline along the UCS X axis). t.rotation = self.tabs[i].ucs_rotation_angle(); self.push_undo_snapshot(i, "TEXT"); - self.commit_entity(EntityType::Text(t)); + let handle = self.commit_entity_handle(EntityType::Text(t)); + if annotative { + let scale = self.tabs[i].scene.current_annotation_scale_handle(); + if let (Some(handle), Some(scale)) = (handle, scale) { + crate::scene::annotative::create_annotation_context( + &mut self.tabs[i].scene.document, + handle, + scale, + ); + } + } self.tabs[i].dirty = true; } self.refresh_properties(); diff --git a/src/scene/annotative.rs b/src/scene/annotative.rs index 1e1266fb0..9015ec9b7 100644 --- a/src/scene/annotative.rs +++ b/src/scene/annotative.rs @@ -4,7 +4,9 @@ //! tessellation bake (which scales annotative content by the current annotation //! scale) must agree on *which* entities are annotative — so that logic lives //! here, once. An entity is annotative if it carries a per-object annotation -//! context, the legacy annotative XDATA, or an annotative style. +//! context, legacy annotative XDATA, or an entity-level annotative flag. Text +//! style state is consulted only while creating a new text object: changing a +//! style later must not retroactively scale existing text. use acadrust::entities::{EntityCommon, EntityType}; use acadrust::objects::{ @@ -73,8 +75,8 @@ pub fn root_named_dict_handle(doc: &mut CadDocument) -> Handle { /// (MTEXT, MULTILEADER). Turning it off also strips the per-object annotation /// context and legacy markers via [`clear_annotation_context`] so the object /// stops resolving annotative; turning it on leaves the base geometry as the -/// single (implicit, current-scale) representation. Other entity types get -/// their annotative state from a style and are not toggled here. +/// single (implicit, current-scale) representation. TEXT uses a context rather +/// than a native flag; other entity types are not toggled here. pub fn set_entity_annotative(doc: &mut CadDocument, handle: Handle, want: bool) { if let Some(e) = doc.get_entity_mut(handle) { match e { @@ -963,7 +965,12 @@ fn name_matches(style_name: &str, name: &str) -> bool { || (name.trim().is_empty() && style_name.eq_ignore_ascii_case("Standard")) } -fn text_style_annotative(doc: &CadDocument, name: &str) -> bool { +/// Whether `name` currently names an annotative text style. +/// +/// Creation paths use this to stamp a new TEXT/MTEXT with its own annotation +/// context. Render-time detection deliberately does not use it: an existing +/// non-annotative object may still reference a style later made annotative. +pub fn text_style_is_annotative(doc: &CadDocument, name: &str) -> bool { doc.text_styles .iter() .find(|s| name_matches(&s.name, name)) @@ -1037,10 +1044,12 @@ pub fn is_annotative(doc: &CadDocument, entity: &EntityType) -> bool { if xd.get_record("AcAnnoPO").is_some() || xd.get_record("AcAnnotativeData").is_some() { return true; } - // Annotative via the assigned style (or the entity's own flag). + // Annotative via the entity's own flag or assigned non-text style. + // Text styles can be made annotative without converting existing text; + // those objects must keep their stored height until explicitly updated. match entity { - EntityType::Text(t) => text_style_annotative(doc, &t.style), - EntityType::MText(t) => t.is_annotative || text_style_annotative(doc, &t.style), + EntityType::Text(_) => false, + EntityType::MText(t) => t.is_annotative, EntityType::Dimension(d) => dim_style_annotative(doc, &d.base().style_name), EntityType::Leader(l) => dim_style_annotative(doc, &l.dimension_style), EntityType::MultiLeader(ml) => {