fix(box): preserve construction semantics

This commit is contained in:
Hakan Seven committed 2026-08-28 20:44:14 +03:00
commit fc93efeed7
52 files changed
+6700 -1754

No files matched your search

+151 -20
View File
@@ -121,7 +121,14 @@ impl OpenCADStudio {
.and_then(|entity| match entity {
acadrust::EntityType::LwPolyline(polyline) => Some(polyline.vertices.len()),
acadrust::EntityType::Polyline2D(polyline) => Some(polyline.vertices.len()),
acadrust::EntityType::PolygonMesh(mesh) => Some(mesh.vertices.len()),
acadrust::EntityType::Polyline3D(polyline) => Some(
crate::entities::polyline::polyline3d_control_vertex_count(polyline),
),
acadrust::EntityType::Leader(leader) => Some(leader.vertices.len()),
acadrust::EntityType::Face3D(face) => {
Some(if face.is_triangle() { 3 } else { 4 })
}
acadrust::EntityType::Spline(spline) => {
Some(if crate::entities::spline::shows_fit_points(spline) {
spline.fit_points.len()
@@ -860,6 +867,12 @@ impl OpenCADStudio {
.map(|b| b.name.clone()),
)
.collect();
let block_names: Vec<String> = doc
.block_records
.iter()
.map(|block| block.name.clone())
.filter(|name| !name.is_empty() && !name.starts_with('*'))
.collect();
let tstyle_names = text_style_names.clone();
// Currently selected names.
let cur_style = ml
@@ -893,6 +906,15 @@ impl OpenCADStudio {
doc.line_types.iter().find(|l| l.handle == h).map(|l| l.name.clone())
})
.unwrap_or_else(|| "ByBlock".to_string());
let cur_block = ml
.block_content_handle
.and_then(|handle| {
doc.block_records
.iter()
.find(|block| block.handle == handle)
.map(|block| block.name.clone())
})
.unwrap_or_else(|| "(none)".to_string());
let mut set_choice =
|field: &str, selected: String, options: Vec<String>| {
for section in sections.iter_mut() {
@@ -911,6 +933,9 @@ impl OpenCADStudio {
set_choice("text_style_handle", cur_tstyle, tstyle_names);
set_choice("arrowhead_handle", cur_arrow, arrow_names);
set_choice("line_type_handle", cur_ltype, ltype_names);
if !block_names.is_empty() {
set_choice("block_content_handle", cur_block, block_names);
}
}
// Inject viewport-only properties that require doc access.
@@ -1018,6 +1043,26 @@ impl OpenCADStudio {
}
}
// Legacy leaders omit Handle and report annotation association.
if let acadrust::EntityType::Leader(leader) = entity {
if let Some(general) = sections.first_mut() {
general.props.retain(|property| property.field != "handle");
let associative = !leader.annotation_handle.is_null()
&& self.tabs[i]
.scene
.document
.get_entity(leader.annotation_handle)
.is_some();
general.props.push(crate::scene::model::object::Property {
label: t!("Associative").into_owned(),
field: "associative",
value: crate::scene::model::object::PropValue::ReadOnly(
if associative { "Yes" } else { "No" }.to_string(),
),
});
}
}
// Inject DimStyle picker + style-derived groups for Dimensions.
if let acadrust::EntityType::Dimension(d) = entity {
if let Some(general) = sections.first_mut() {
@@ -1212,14 +1257,7 @@ impl OpenCADStudio {
}
}
}
// Lines & Arrows / Text / Fit default to the assigned
// dimension style (the same source the tessellator
// uses); most rows are editable per-object overrides
// stored in ACAD_DSTYLE. Arrow size / block / overall
// scale and dim-line lineweight drive the render; text
// offset / vertical position round-trip to file but
// don't change the leader glyph here (its annotation
// is a separate entity). Dim-line colour is read-only.
// Resolve editable overrides from the assigned dimension style.
if let Some(ds) = find_dim_style(doc, &ld.dimension_style) {
use crate::entities::dim_override as dov;
use crate::scene::model::object::PropValue;
@@ -1265,7 +1303,7 @@ impl OpenCADStudio {
set_row_value(
&mut sections,
"arrow_size",
PropValue::EditText(format!("{asz:.4}")),
PropValue::EditText(asz.to_string()),
);
let lwd = dov::int(xd, dov::DIMLWD).unwrap_or(ds.dimlwd);
@@ -1283,10 +1321,7 @@ impl OpenCADStudio {
},
);
// Dim-line colour: a per-object ACAD_DSTYLE
// override (code 176, an ACI index) wins over the
// style's DIMCLRD. Editable — the picked colour is
// written back as that override so it round-trips.
// A per-object color override wins over the style.
let dim_c = dov::color(xd, dov::DIMCLRD)
.unwrap_or_else(|| acadrust::types::Color::from_index(ds.dimclrd));
set_row_value(
@@ -1299,7 +1334,7 @@ impl OpenCADStudio {
set_row_value(
&mut sections,
"text_offset",
PropValue::EditText(format!("{gap:.4}")),
PropValue::EditText(gap.to_string()),
);
let tad = dov::int(xd, dov::DIMTAD).unwrap_or(ds.dimtad);
@@ -1316,7 +1351,7 @@ impl OpenCADStudio {
set_row_value(
&mut sections,
"dim_scale_overall",
PropValue::EditText(format!("{scl:.4}")),
PropValue::EditText(scl.to_string()),
);
}
}
@@ -1409,6 +1444,21 @@ impl OpenCADStudio {
// MultiLeader: max points + segment-angle constraints
// are MLeaderStyle settings, not stored on the entity.
acadrust::EntityType::MultiLeader(ml) => {
if ml
.text_style_handle
.and_then(|handle| {
doc.text_styles.iter().find(|style| style.handle == handle)
})
.is_some_and(|style| style.has_fixed_height())
{
set_row_value(
&mut sections,
"text_height",
PropValue::ReadOnly(
crate::entities::common::format_length(ml.text_height),
),
);
}
if let Some(sh) = ml.style_handle {
if let Some((mx, a1, a2)) =
doc.objects.iter().find_map(|(h, o)| match o {
@@ -1833,6 +1883,11 @@ impl OpenCADStudio {
doc, entity,
)
}
acadrust::EntityType::Leader(_) => {
crate::scene::annotative::annotation_style_is_annotative(
doc, entity,
)
}
_ => false,
};
// Dimensions/tables/tolerances carry no Annotative row yet — add one
@@ -1870,8 +1925,17 @@ impl OpenCADStudio {
"annotative",
if is_anno { "Yes" } else { "No" }.to_string(),
),
acadrust::EntityType::Leader(_)
if crate::scene::annotative::annotation_style_is_annotative(
doc, entity,
) => set_row(
&mut sections,
"annotative",
"Yes".to_string(),
),
acadrust::EntityType::Text(_)
| acadrust::EntityType::Insert(_)
| acadrust::EntityType::Leader(_)
| acadrust::EntityType::Hatch(_)
| acadrust::EntityType::Dimension(_) => set_row_value(
&mut sections,
@@ -2494,10 +2558,40 @@ impl OpenCADStudio {
/// (or `None` if it could not be added). Lets callers follow up — e.g.
/// open the in-place text editor on a freshly created MultiLeader.
pub(super) fn commit_entity_handle(
&mut self,
entity: acadrust::EntityType,
) -> Option<Handle> {
self.commit_entity_handle_with_dimension_policy(entity, false)
}
/// Commit an entity, optionally preserving its source dimension style.
pub(super) fn commit_entity_handle_with_dimension_policy(
&mut self,
mut entity: acadrust::EntityType,
preserve_dimension_layer_and_style: bool,
) -> Option<Handle> {
let i = self.active_tab;
let tracks_dimension_chain = matches!(
&entity,
acadrust::EntityType::Dimension(
acadrust::entities::Dimension::Linear(_)
| acadrust::entities::Dimension::Aligned(_)
| acadrust::entities::Dimension::Angular2Ln(_)
| acadrust::entities::Dimension::Angular3Pt(_)
| acadrust::entities::Dimension::Ordinate(_)
)
);
let inherited_dimension = if preserve_dimension_layer_and_style {
match &entity {
acadrust::EntityType::Dimension(dimension) => Some((
dimension.base().common.layer.clone(),
dimension.base().style_name.clone(),
)),
_ => None,
}
} else {
None
};
if let acadrust::EntityType::Table(table) = &mut entity {
const PREFIX: &str = "__OPENCAD_LINK_PENDING__";
if let Some(path) = table.name.strip_prefix(PREFIX).map(str::to_string) {
@@ -2553,9 +2647,21 @@ impl OpenCADStudio {
| acadrust::EntityType::Polyline2D(_)
| acadrust::EntityType::Polyline3D(_)
);
let layer = &self.tabs[i].active_layer;
if layer != "0" || entity.as_entity().layer().is_empty() {
entity.as_entity_mut().set_layer(layer.clone());
let explicit_mleader_layer = match &entity {
acadrust::EntityType::MultiLeader(leader) => leader
.common
.layer
.strip_prefix("__MLEADER_LAYER__")
.map(str::to_owned),
_ => None,
};
if let Some(layer) = explicit_mleader_layer {
entity.as_entity_mut().set_layer(layer);
} else {
let layer = &self.tabs[i].active_layer;
if layer != "0" || entity.as_entity().layer().is_empty() {
entity.as_entity_mut().set_layer(layer.clone());
}
}
// INSUNITS: when inserting a block whose BlockRecord.units differ
@@ -2599,6 +2705,12 @@ impl OpenCADStudio {
&self.tabs[i].scene.document,
&mut entity,
);
if let (Some((layer, style_name)), acadrust::EntityType::Dimension(dimension)) =
(inherited_dimension, &mut entity)
{
dimension.base_mut().common.layer = layer;
dimension.base_mut().style_name = style_name;
}
// Smart centre objects carry their own drawing-level creation style.
// Apply it after the generic ribbon style so ordinary LINE entities
@@ -2758,6 +2870,9 @@ impl OpenCADStudio {
self.tabs[i].last_draw_anchor = Some(handle);
}
}
if tracks_dimension_chain {
self.tabs[i].scene.last_created_dimension = new_handle;
}
new_handle
}
}
@@ -2788,8 +2903,13 @@ fn make_sections_read_only(
acadrust::types::Color::Index(index) => index.to_string(),
acadrust::types::Color::Rgb { r, g, b } => format!("{r},{g},{b}"),
},
PropValue::ColorVaries | PropValue::LwVaries => VARIES_LABEL.to_string(),
PropValue::LwChoice(lineweight) => {
PropValue::ColorVaries
| PropValue::LwVaries
| PropValue::FieldLwVaries { .. } => VARIES_LABEL.to_string(),
PropValue::LwChoice(lineweight)
| PropValue::FieldLwChoice {
value: lineweight, ..
} => {
ui::properties::LwItem(*lineweight).to_string()
}
PropValue::BoolToggle { value, .. } => {
@@ -2947,6 +3067,17 @@ fn merge_prop_value(
(PropValue::LwChoice(_), PropValue::LwChoice(_))
| (PropValue::LwVaries, _)
| (_, PropValue::LwVaries) => PropValue::LwVaries,
(
PropValue::FieldLwChoice { field, .. },
PropValue::FieldLwChoice {
field: other_field,
..
},
) if field == other_field => PropValue::FieldLwVaries { field },
(PropValue::FieldLwVaries { field }, _)
| (_, PropValue::FieldLwVaries { field }) => {
PropValue::FieldLwVaries { field }
}
(PropValue::LinetypeChoice(_), PropValue::LinetypeChoice(_)) => {
PropValue::LinetypeChoice(VARIES_LABEL.into())
}