From c992b73cdfb69883dbc8649503e0d6b3103735ec Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Thu, 1 Oct 2026 14:16:06 +0300 Subject: [PATCH] ATTDEF: Fit/Align attribute text, TEXTSIZE, single-line restart Align and Fit attributes run their text between the two baseline points, an ATTDEF height becomes the next text height, and Multiple lines is not carried to the next definition (measured). Co-Authored-By: Claude Opus 5.5 --- src/app/command_driver/entity_commit.rs | 6 +++++ src/entities/attribute.rs | 33 ++++++++++++++++++++++++- src/modules/draw/draw/attdef.rs | 4 ++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/app/command_driver/entity_commit.rs b/src/app/command_driver/entity_commit.rs index 2fcb4e256..13b3c1ddf 100644 --- a/src/app/command_driver/entity_commit.rs +++ b/src/app/command_driver/entity_commit.rs @@ -220,6 +220,12 @@ impl OpenCADStudio { // Record where this draw ended so ARC_CONT can continue from it // (before `entity` is moved into commit_entity). self.update_cont_anchor(&entity); + // ATTDEF's height becomes the next text height (TEXTSIZE), as TEXT's does. + if let codec::EntityType::AttributeDefinition(attribute) = &entity { + if self.tabs[i].active_cmd.as_ref().is_some_and(|cmd| cmd.name().ends_with("ATTDEF")) { + self.tabs[i].scene.document.header.text_height = attribute.height; + } + } let label = self.history_label_from_active_cmd(i, "ENTITY"); let delta_safe = self.delta_add_safe(i, &entity); let pending = self.begin_undo(i, label, 1, delta_safe); diff --git a/src/entities/attribute.rs b/src/entities/attribute.rs index 2247cfc29..aa382cc08 100644 --- a/src/entities/attribute.rs +++ b/src/entities/attribute.rs @@ -101,7 +101,7 @@ fn mtext_flag_str(f: MTextFlag) -> &'static str { /// Render text strokes for an attribute, honouring alignment, oblique angle, /// width factor, generation flags (backward / upside-down), text-style /// resolution, and basic multiline splitting on `\n` / `\\P`. -fn build_attr_render(input: AttrTextInputs<'_>, document: &codec::CadDocument) -> RenderEntity { +fn build_attr_render(mut input: AttrTextInputs<'_>, document: &codec::CadDocument) -> RenderEntity { let normal = (input.normal.x, input.normal.y, input.normal.z); let (wsx, wsy, wsz) = transform::ocs_point_to_wcs( ( @@ -147,6 +147,37 @@ fn build_attr_render(input: AttrTextInputs<'_>, document: &codec::CadDocument) - resolved.oblique_angle }; + // Align / Fit run the text along the baseline between the two points: + // Fit stretches its width, Align scales its height too. + let (mut rotation, mut width_factor) = (rotation, width_factor); + let span = ( + input.alignment_point.x - input.insertion_point.x, + input.alignment_point.y - input.insertion_point.y, + ); + let length = span.0.hypot(span.1); + if matches!(input.horizontal_alignment, AHA::Aligned | AHA::Fit) + && length > 1.0e-9 + && !input.value.contains("\\P") + { + if let Some(b) = text_local_bounds( + &resolved.font_name, + &resolve_dxf_special_chars(input.value), + input.height as f32, + width_factor.abs(), + oblique_angle, + ) + .filter(|b| b.advance > 1.0e-6) + { + let scale = length / b.advance as f64; + rotation = span.1.atan2(span.0) as f32; + if matches!(input.horizontal_alignment, AHA::Aligned) { + input.height *= scale; + } else { + width_factor *= scale as f32; + } + } + } + // Anchor selection mirrors Text: only Left/Baseline uses insertion_point; // every other alignment uses alignment_point. let needs_align_pt = !(matches!(input.horizontal_alignment, AHA::Left) diff --git a/src/modules/draw/draw/attdef.rs b/src/modules/draw/draw/attdef.rs index 786e95ecd..d6e5c83a9 100644 --- a/src/modules/draw/draw/attdef.rs +++ b/src/modules/draw/draw/attdef.rs @@ -498,9 +498,11 @@ impl AttdefCommand { } /// Keep AFLAGS / Annotative and the placed definition for the next ATTDEF. +/// Multiple lines is not kept: the reference starts the next definition +/// single-line again. pub fn remember(spec: &AttdefSpec, entity: &EntityType) { let mut s = session(); - s.aflags = spec.aflags; + s.aflags = spec.aflags & !AFLAG_MULTILINE; s.annotative = spec.annotative; if let EntityType::AttributeDefinition(a) = entity { s.last = Some(a.clone());