forked from 1b-agent/opencadstudio-upstream
fix(box): preserve construction semantics
This commit is contained in:
commit
fc93efeed7
52 files changed
+6700
-1754
No files matched your search
+151
-20
@@ -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())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user