fix(commands): ADDSELECTED keeps CLAYER, adopts dimension style (#239)
Two follow-ups to ADDSELECTED: - It no longer permanently changes the current layer/colour/linetype/ lineweight. The template's properties are captured as the drawing defaults only while the launched draw command runs; a snapshot taken in cmd_add_selected is restored the moment that command ends (central hook in apply_cmd_result) or is interrupted by another command. - Dimensions are supported: add_selected_verb maps each DimensionType to its DIM* command, and the template's dimension style is adopted as the current DIMSTYLE (restored afterwards). commit_entity_handle now stamps every new dimension with the current DIMSTYLE — the DIM commands left the default "Standard" on the entity, so a normal dimension also picks up the active style now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f9b6834ad9
commit
5e4e7c1020
5 changed files with 145 additions and 4 deletions
|
|
@ -165,6 +165,12 @@ impl OpenCADStudio {
|
||||||
self.tabs[i].scene.deselect_all();
|
self.tabs[i].scene.deselect_all();
|
||||||
self.refresh_properties();
|
self.refresh_properties();
|
||||||
}
|
}
|
||||||
|
// A command just ended (any terminal result) — if it was the draw
|
||||||
|
// command an ADDSELECTED launched, revert the template-property override
|
||||||
|
// so CLAYER / CECOLOR / … are left unchanged (#239). No-op otherwise.
|
||||||
|
if was_active && self.tabs[i].active_cmd.is_none() {
|
||||||
|
self.restore_add_selected_defaults();
|
||||||
|
}
|
||||||
task
|
task
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1385,7 +1391,7 @@ impl OpenCADStudio {
|
||||||
verts_low,
|
verts_low,
|
||||||
normals,
|
normals,
|
||||||
indices,
|
indices,
|
||||||
} => Some(crate::scene::model::mesh_model::MeshModel {
|
} => Some((crate::scene::model::mesh_model::MeshModel {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
verts,
|
verts,
|
||||||
verts_low,
|
verts_low,
|
||||||
|
|
@ -1393,19 +1399,22 @@ impl OpenCADStudio {
|
||||||
indices,
|
indices,
|
||||||
color,
|
color,
|
||||||
selected: false,
|
selected: false,
|
||||||
}),
|
}, solid)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some(mut mesh) = result {
|
if let Some((mut mesh, solid)) = result {
|
||||||
self.push_undo_snapshot(i, "EXTRUDE");
|
self.push_undo_snapshot(i, "EXTRUDE");
|
||||||
let new_entity = empty_solid3d();
|
let new_entity = empty_solid3d();
|
||||||
let new_handle = self.tabs[i].scene.add_entity(new_entity);
|
let new_handle = self.tabs[i].scene.add_entity(new_entity);
|
||||||
mesh.name = format!("{}", new_handle.value());
|
mesh.name = format!("{}", new_handle.value());
|
||||||
self.tabs[i].scene.meshes.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
|
self.tabs[i].scene.meshes.insert(new_handle, crate::scene::MeshLodSet::from_single(mesh));
|
||||||
|
// Keep the truck B-rep so the save path can export exact
|
||||||
|
// ACIS geometry (else the solid is dropped by other CAD apps).
|
||||||
|
self.tabs[i].scene.solid_models.insert(new_handle, solid);
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
self.command_line.push_output("EXTRUDE: solid created.");
|
self.command_line.push_output("EXTRUDE: solid created.");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -813,9 +813,16 @@ impl OpenCADStudio {
|
||||||
c.linetype.clone(),
|
c.linetype.clone(),
|
||||||
c.linetype_scale,
|
c.linetype_scale,
|
||||||
c.line_weight,
|
c.line_weight,
|
||||||
|
// A dimension template also carries its dimension style, adopted
|
||||||
|
// as the current DIMSTYLE so the cloned dimension matches (#239).
|
||||||
|
match e {
|
||||||
|
acadrust::EntityType::Dimension(d) => Some(d.base().style_name.clone()),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
let Some((verb, kind, layer, color, linetype, lt_scale, lw)) = info else {
|
let Some((verb, kind, layer, color, linetype, lt_scale, lw, template_dimstyle)) = info
|
||||||
|
else {
|
||||||
self.command_line
|
self.command_line
|
||||||
.push_error("ADDSELECTED: selected object not found.");
|
.push_error("ADDSELECTED: selected object not found.");
|
||||||
return Task::none();
|
return Task::none();
|
||||||
|
|
@ -830,6 +837,29 @@ impl OpenCADStudio {
|
||||||
// rewrite the template, and so the draw starts on a clean slate.
|
// rewrite the template, and so the draw starts on a clean slate.
|
||||||
self.tabs[i].scene.deselect_all();
|
self.tabs[i].scene.deselect_all();
|
||||||
|
|
||||||
|
// Snapshot the current drawing defaults so the override below reverts
|
||||||
|
// once the launched draw command ends — ADDSELECTED must adopt the
|
||||||
|
// template's properties for the new object without permanently changing
|
||||||
|
// CLAYER / CECOLOR / CELTYPE / CELWEIGHT (issue #239).
|
||||||
|
let restore = crate::app::AddSelectedRestore {
|
||||||
|
layer_name: self.tabs[i].scene.document.header.current_layer_name.clone(),
|
||||||
|
layer_handle: self.tabs[i].scene.document.header.current_layer_handle,
|
||||||
|
color: self.tabs[i].scene.document.header.current_entity_color,
|
||||||
|
linetype_name: self.tabs[i].scene.document.header.current_linetype_name.clone(),
|
||||||
|
linetype_handle: self.tabs[i].scene.document.header.current_linetype_handle,
|
||||||
|
line_weight: self.tabs[i].scene.document.header.current_line_weight,
|
||||||
|
lt_scale: self.tabs[i].scene.document.header.current_entity_linetype_scale,
|
||||||
|
dimstyle_name: self.tabs[i].scene.document.header.current_dimstyle_name.clone(),
|
||||||
|
dimstyle_handle: self.tabs[i].scene.document.header.current_dimstyle_handle,
|
||||||
|
tab_active_layer: self.tabs[i].active_layer.clone(),
|
||||||
|
tab_layers_current: self.tabs[i].layers.current_layer.clone(),
|
||||||
|
ribbon_layer: self.ribbon.active_layer.clone(),
|
||||||
|
ribbon_color: self.ribbon.active_color,
|
||||||
|
ribbon_linetype: self.ribbon.active_linetype.clone(),
|
||||||
|
ribbon_lineweight: self.ribbon.active_lineweight,
|
||||||
|
};
|
||||||
|
self.add_selected_restore = Some(restore);
|
||||||
|
|
||||||
// Adopt the template's general properties as the current defaults. The
|
// Adopt the template's general properties as the current defaults. The
|
||||||
// entity-creation path stamps new objects from the tab's active layer
|
// entity-creation path stamps new objects from the tab's active layer
|
||||||
// and the ribbon's active colour / linetype / lineweight, mirrored into
|
// and the ribbon's active colour / linetype / lineweight, mirrored into
|
||||||
|
|
@ -860,6 +890,21 @@ impl OpenCADStudio {
|
||||||
header.current_line_weight = lw.value();
|
header.current_line_weight = lw.value();
|
||||||
header.current_entity_linetype_scale = lt_scale;
|
header.current_entity_linetype_scale = lt_scale;
|
||||||
}
|
}
|
||||||
|
// A dimension template also sets the current DIMSTYLE so the cloned
|
||||||
|
// dimension inherits the template's dimension style (#239).
|
||||||
|
if let Some(ds) = &template_dimstyle {
|
||||||
|
let ds_handle = self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.document
|
||||||
|
.dim_styles
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.name.eq_ignore_ascii_case(ds))
|
||||||
|
.map(|s| s.handle)
|
||||||
|
.unwrap_or(acadrust::types::Handle::NULL);
|
||||||
|
let header = &mut self.tabs[i].scene.document.header;
|
||||||
|
header.current_dimstyle_name = ds.clone();
|
||||||
|
header.current_dimstyle_handle = ds_handle;
|
||||||
|
}
|
||||||
self.tabs[i].active_layer = layer.clone();
|
self.tabs[i].active_layer = layer.clone();
|
||||||
self.tabs[i].layers.current_layer = layer.clone();
|
self.tabs[i].layers.current_layer = layer.clone();
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
|
|
@ -875,6 +920,35 @@ impl OpenCADStudio {
|
||||||
// Launch the matching draw command (installs its interactive step).
|
// Launch the matching draw command (installs its interactive step).
|
||||||
self.dispatch_command(verb)
|
self.dispatch_command(verb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restore the drawing defaults ADDSELECTED overrode, once the draw command
|
||||||
|
/// it launched ends (commit / cancel / interrupt). No-op unless an
|
||||||
|
/// ADDSELECTED override is pending. Issue #239.
|
||||||
|
pub(crate) fn restore_add_selected_defaults(&mut self) {
|
||||||
|
let Some(r) = self.add_selected_restore.take() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let i = self.active_tab;
|
||||||
|
{
|
||||||
|
let h = &mut self.tabs[i].scene.document.header;
|
||||||
|
h.current_layer_name = r.layer_name;
|
||||||
|
h.current_layer_handle = r.layer_handle;
|
||||||
|
h.current_entity_color = r.color;
|
||||||
|
h.current_linetype_name = r.linetype_name;
|
||||||
|
h.current_linetype_handle = r.linetype_handle;
|
||||||
|
h.current_line_weight = r.line_weight;
|
||||||
|
h.current_entity_linetype_scale = r.lt_scale;
|
||||||
|
h.current_dimstyle_name = r.dimstyle_name;
|
||||||
|
h.current_dimstyle_handle = r.dimstyle_handle;
|
||||||
|
}
|
||||||
|
self.tabs[i].active_layer = r.tab_active_layer;
|
||||||
|
self.tabs[i].layers.current_layer = r.tab_layers_current;
|
||||||
|
self.ribbon.active_layer = r.ribbon_layer;
|
||||||
|
self.ribbon.active_color = r.ribbon_color;
|
||||||
|
self.ribbon.active_linetype = r.ribbon_linetype;
|
||||||
|
self.ribbon.active_lineweight = r.ribbon_lineweight;
|
||||||
|
self.refresh_properties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map a template entity to the draw-command verb that creates the same kind of
|
/// Map a template entity to the draw-command verb that creates the same kind of
|
||||||
|
|
@ -899,6 +973,19 @@ fn add_selected_verb(entity: &acadrust::EntityType) -> Option<&'static str> {
|
||||||
EntityType::Solid(_) => "SOLID",
|
EntityType::Solid(_) => "SOLID",
|
||||||
EntityType::Ray(_) => "RAY",
|
EntityType::Ray(_) => "RAY",
|
||||||
EntityType::XLine(_) => "XLINE",
|
EntityType::XLine(_) => "XLINE",
|
||||||
|
// Dimensions launch the matching dimension command by their stored type
|
||||||
|
// (issue #239). Angular 2-line and 3-point both use DIMANGULAR.
|
||||||
|
EntityType::Dimension(d) => {
|
||||||
|
use acadrust::entities::DimensionType;
|
||||||
|
match d.base().dimension_type {
|
||||||
|
DimensionType::Linear => "DIMLINEAR",
|
||||||
|
DimensionType::Aligned => "DIMALIGNED",
|
||||||
|
DimensionType::Angular | DimensionType::Angular3Point => "DIMANGULAR",
|
||||||
|
DimensionType::Diameter => "DIMDIAMETER",
|
||||||
|
DimensionType::Radius => "DIMRADIUS",
|
||||||
|
DimensionType::Ordinate => "DIMORDINATE",
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ impl OpenCADStudio {
|
||||||
if self.tabs[i].active_cmd.is_some() {
|
if self.tabs[i].active_cmd.is_some() {
|
||||||
self.tabs[i].scene.clear_preview_wire();
|
self.tabs[i].scene.clear_preview_wire();
|
||||||
self.tabs[i].active_cmd = None;
|
self.tabs[i].active_cmd = None;
|
||||||
|
// Interrupting an ADDSELECTED draw with another command reverts its
|
||||||
|
// template-property override too (#239).
|
||||||
|
self.restore_add_selected_defaults();
|
||||||
}
|
}
|
||||||
// Starting any command leaves interactive PAN mode (the PAN arm below
|
// Starting any command leaves interactive PAN mode (the PAN arm below
|
||||||
// re-enables it).
|
// re-enables it).
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,27 @@ pub struct OpenProgress {
|
||||||
|
|
||||||
// ── Application state ──────────────────────────────────────────────────────
|
// ── Application state ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/// Drawing defaults ADDSELECTED overrides while it draws a new object matching a
|
||||||
|
/// template, then restores so the current layer/colour/linetype/lineweight are
|
||||||
|
/// left unchanged (issue #239).
|
||||||
|
struct AddSelectedRestore {
|
||||||
|
layer_name: String,
|
||||||
|
layer_handle: acadrust::types::Handle,
|
||||||
|
color: AcadColor,
|
||||||
|
linetype_name: String,
|
||||||
|
linetype_handle: acadrust::types::Handle,
|
||||||
|
line_weight: i16,
|
||||||
|
lt_scale: f64,
|
||||||
|
dimstyle_name: String,
|
||||||
|
dimstyle_handle: acadrust::types::Handle,
|
||||||
|
tab_active_layer: String,
|
||||||
|
tab_layers_current: String,
|
||||||
|
ribbon_layer: String,
|
||||||
|
ribbon_color: AcadColor,
|
||||||
|
ribbon_linetype: String,
|
||||||
|
ribbon_lineweight: LineWeight,
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct OpenCADStudio {
|
pub(super) struct OpenCADStudio {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
tabs: Vec<DocumentTab>,
|
tabs: Vec<DocumentTab>,
|
||||||
|
|
@ -242,6 +263,10 @@ pub(super) struct OpenCADStudio {
|
||||||
otrack_active: Option<(glam::Vec3, glam::Vec3)>,
|
otrack_active: Option<(glam::Vec3, glam::Vec3)>,
|
||||||
/// Whether Tangent snap was enabled before a tangent-pick command started.
|
/// Whether Tangent snap was enabled before a tangent-pick command started.
|
||||||
pre_cmd_tangent: Option<bool>,
|
pre_cmd_tangent: Option<bool>,
|
||||||
|
/// Drawing defaults captured by ADDSELECTED before it adopts the template
|
||||||
|
/// object's properties, restored when the launched draw command ends so
|
||||||
|
/// ADDSELECTED doesn't permanently change CLAYER / CECOLOR / … (issue #239).
|
||||||
|
add_selected_restore: Option<AddSelectedRestore>,
|
||||||
/// Whether Ortho mode was temporarily suppressed by a command (e.g. RECTANG).
|
/// Whether Ortho mode was temporarily suppressed by a command (e.g. RECTANG).
|
||||||
rect_suppressed_ortho: bool,
|
rect_suppressed_ortho: bool,
|
||||||
/// Orthogonal drawing constraint (F8): constrains picks to 0°/90°/180°/270°.
|
/// Orthogonal drawing constraint (F8): constrains picks to 0°/90°/180°/270°.
|
||||||
|
|
@ -1949,6 +1974,7 @@ impl OpenCADStudio {
|
||||||
perf_hud: false,
|
perf_hud: false,
|
||||||
cycle_candidates: None,
|
cycle_candidates: None,
|
||||||
pre_cmd_tangent: None,
|
pre_cmd_tangent: None,
|
||||||
|
add_selected_restore: None,
|
||||||
rect_suppressed_ortho: false,
|
rect_suppressed_ortho: false,
|
||||||
ortho_mode: false,
|
ortho_mode: false,
|
||||||
polar_mode: false,
|
polar_mode: false,
|
||||||
|
|
|
||||||
|
|
@ -667,6 +667,22 @@ impl OpenCADStudio {
|
||||||
entity.as_entity_mut().set_layer(layer.clone());
|
entity.as_entity_mut().set_layer(layer.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A new dimension adopts the current dimension style (DIMSTYLE), like
|
||||||
|
// AutoCAD — the DIM commands leave the default "Standard" on the entity,
|
||||||
|
// so stamp the header's current style here. ADDSELECTED sets DIMSTYLE to
|
||||||
|
// the template's first, so a cloned dimension keeps its style (#239).
|
||||||
|
if let acadrust::EntityType::Dimension(ref mut d) = entity {
|
||||||
|
let cur = self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.document
|
||||||
|
.header
|
||||||
|
.current_dimstyle_name
|
||||||
|
.clone();
|
||||||
|
if !cur.trim().is_empty() {
|
||||||
|
d.base_mut().style_name = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// INSUNITS: when inserting a block whose BlockRecord.units differ
|
// INSUNITS: when inserting a block whose BlockRecord.units differ
|
||||||
// from the host's header.insertion_units, scale the new INSERT so
|
// from the host's header.insertion_units, scale the new INSERT so
|
||||||
// 1 source-unit equals the matching host length. When either side
|
// 1 source-unit equals the matching host length. When either side
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue