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 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-10-01 14:16:06 +03:00
1 parent c5790c74a9
commit c992b73cdf
3 files changed
+41 -2

No files matched your search

+6
View File
@@ -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);
+32 -1
View File
@@ -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)
+3 -1
View File
@@ -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());