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());