feat(annotative): synthesize per-object contexts + editable UI

Make objects genuinely annotative — carrying real per-scale
representations that interoperate with other CAD apps — rather than just
a native flag. `create_annotation_context` synthesizes the extension-dict
chain (AcDbContextDataManager -> ACDB_ANNOTATIONSCALES -> per-scale leaf)
from the entity's placement; the editable Annotative toggle now covers
Text and block references as well as MText/MLeader; and a new
"Annotation Object Scale" dialog (OBJECTSCALE) adds/removes an object's
per-scale memberships. Requires the acadrust ObjectContextData encoder
(Cargo.lock bump).

Also fixes a render bug where objects carrying an *empty*
ACDB_ANNOTATIONSCALES (a single-representation marker with no per-scale
reps) were treated as annotative and (mis)scaled by the annotation factor
in scaled paper viewports, ballooning the text: an object is now
annotative-by-context only when its scale collection is non-empty, so
such objects render at their base geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-07-13 22:38:29 +03:00
commit c0844ad55c
14 changed files with 922 additions and 30 deletions

View file

@ -669,6 +669,7 @@ impl OpenCADStudio {
let anno: Option<(&str, Option<&str>)> = match entity {
acadrust::EntityType::Text(_)
| acadrust::EntityType::MText(_)
| acadrust::EntityType::Insert(_)
| acadrust::EntityType::Leader(_) => Some(("annotative", None)),
acadrust::EntityType::MultiLeader(_) => {
Some(("enable_annotation_scale", None))
@ -696,25 +697,35 @@ impl OpenCADStudio {
),
);
}
// MTEXT carries a per-object annotative flag, so its
// row is an editable toggle (like MLeader's); the
// style-derived types stay read-only Yes/No.
// Objects that carry a per-object annotation context
// (MTEXT via its native flag, single-line TEXT via the
// context alone) get an editable toggle: turning it on
// synthesizes a real per-scale representation. The
// remaining types are style-driven and stay read-only.
if anno_field == "annotative" {
if let acadrust::EntityType::MText(t) = entity {
set_row_value(
match entity {
acadrust::EntityType::MText(t) => set_row_value(
&mut sections,
"annotative",
crate::scene::model::object::PropValue::BoolToggle {
field: "is_annotative",
value: t.is_annotative,
},
);
} else {
set_row(
),
acadrust::EntityType::Text(_)
| acadrust::EntityType::Insert(_) => set_row_value(
&mut sections,
"annotative",
crate::scene::model::object::PropValue::BoolToggle {
field: "annotative_ctx",
value: is_anno,
},
),
_ => set_row(
&mut sections,
"annotative",
if is_anno { "Yes" } else { "No" }.to_string(),
);
),
}
}
if is_anno {