forked from 1b-agent/opencadstudio-upstream
feat(blocks): persist independent Move and Scale reference grips
Selected drawing references now expose action parameter grips outside Test Block. Point input evaluates immutable definition geometry into an independent anonymous representation and stores per-INSERT values in native AppDataCache XRecords, preserving definition graphs and sibling references. Reuse visibility representation isolation, including shared COPY blocks, and retain cache metadata. Record geometry, INSERT links, new block records and parameter values in one undo step. Support transformed uniform references and Point, Linear, Polar and XY endpoints for the existing Move/Scale actions. Validate synthetic DWG/DXF persistence, re-edit/resave, COPY isolation, XY/Polar cache layouts, metadata, cancellation, transformed grips and undo/redo. 327 block regressions pass (6 existing opt-in checks ignored).
This commit is contained in:
1 parent
ddf348af22
commit
f67f2cf4f5
8 files changed
+804
-26
No files matched your search
@@ -59,6 +59,125 @@ fn feed(app: &mut OpenCADStudio, text: &str) {
|
||||
let _ = app.update(Message::CommandSubmit);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_actions_drawing_grips_history_cancel_transform_and_reopen() {
|
||||
use crate::scene::block_actions::{self as actions, Kind};
|
||||
let (mut app, reference) = fixture();
|
||||
begin(&mut app, reference);
|
||||
let i = app.active_tab;
|
||||
let _ = app.run_command_line("BPARAMETER LINEAR 0,0 10,0 5,2");
|
||||
let def = app.tabs[i].active_block_edit_session().unwrap().br_handle;
|
||||
let p = actions::parameters(&app.tabs[i].scene.document, def, Kind::Move)[0].clone();
|
||||
let targets = members(&app);
|
||||
actions::create(
|
||||
&mut app.tabs[i].scene.document,
|
||||
def,
|
||||
Kind::Move,
|
||||
p.handle,
|
||||
&targets,
|
||||
glam::DVec3::ZERO,
|
||||
)
|
||||
.unwrap();
|
||||
let _ = app.dispatch_command("BSAVE");
|
||||
let _ = app.dispatch_command("BEDIT_DISCARD");
|
||||
let sibling = app.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.add_entity(EntityType::Insert(Insert::new(
|
||||
"EDIT_ME",
|
||||
Vector3::new(40., 0., 0.),
|
||||
)))
|
||||
.unwrap();
|
||||
let EntityType::Insert(ins) = app.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity_mut(reference)
|
||||
.unwrap()
|
||||
else {
|
||||
panic!()
|
||||
};
|
||||
ins.insert_point = Vector3::new(20., 30., 0.);
|
||||
ins.rotation = std::f64::consts::FRAC_PI_2;
|
||||
ins.set_x_scale(2.);
|
||||
ins.set_y_scale(2.);
|
||||
ins.set_z_scale(2.);
|
||||
let original = app.tabs[i].scene.document.clone();
|
||||
app.tabs[i].scene.selected.insert(reference);
|
||||
app.tabs[i].selected_handle = Some(reference);
|
||||
app.refresh_properties();
|
||||
let grip = app.tabs[i]
|
||||
.selected_grips
|
||||
.iter()
|
||||
.find(|g| super::block_actions::is_test_grip(g.id))
|
||||
.unwrap()
|
||||
.clone();
|
||||
assert!(grip.world.distance(glam::DVec3::new(20., 50., 0.)) < 1e-8);
|
||||
let depth = app.tabs[i].history.undo_stack.len();
|
||||
assert!(app.start_test_action_grip(reference, grip.id));
|
||||
let _ = app.update(Message::CommandEscape);
|
||||
assert_eq!(app.tabs[i].scene.document, original);
|
||||
assert_eq!(app.tabs[i].history.undo_stack.len(), depth);
|
||||
// Escape also clears the ordinary drawing selection.
|
||||
app.tabs[i].scene.selected.insert(reference);
|
||||
app.refresh_properties();
|
||||
assert!(app.start_test_action_grip(reference, grip.id));
|
||||
feed(&mut app, "20,70");
|
||||
assert!(app.tabs[i].active_cmd.is_none());
|
||||
let changed = app.tabs[i].scene.document.clone();
|
||||
assert_eq!(app.tabs[i].history.undo_stack.len(), depth + 1);
|
||||
let EntityType::Insert(ins) = changed.get_entity(reference).unwrap() else {
|
||||
panic!()
|
||||
};
|
||||
assert_ne!(ins.block_name, "EDIT_ME");
|
||||
let member = changed
|
||||
.block_records
|
||||
.get(&ins.block_name)
|
||||
.unwrap()
|
||||
.entity_handles[0];
|
||||
let EntityType::Line(line) = changed.get_entity(member).unwrap() else {
|
||||
panic!()
|
||||
};
|
||||
assert!((line.start.x - 10.).abs() < 1e-8);
|
||||
assert_eq!(
|
||||
changed.get_entity(targets[0]),
|
||||
original.get_entity(targets[0])
|
||||
);
|
||||
assert_eq!(changed.get_entity(sibling), original.get_entity(sibling));
|
||||
app.undo_steps(1);
|
||||
assert_eq!(
|
||||
app.tabs[i].scene.document.get_entity(reference),
|
||||
original.get_entity(reference)
|
||||
);
|
||||
assert!(app.tabs[i].scene.document.get_entity(member).is_none());
|
||||
app.redo_steps(1);
|
||||
assert_eq!(
|
||||
app.tabs[i].scene.document.get_entity(member),
|
||||
changed.get_entity(member)
|
||||
);
|
||||
assert_eq!(
|
||||
app.tabs[i].scene.document.get_entity(reference),
|
||||
changed.get_entity(reference)
|
||||
);
|
||||
let bytes = codec::DwgWriter::write_to_vec(&app.tabs[i].scene.document).unwrap();
|
||||
app.tabs[i].scene.document = codec::DwgReader::from_stream(std::io::Cursor::new(bytes))
|
||||
.read()
|
||||
.unwrap();
|
||||
app.refresh_properties();
|
||||
let grip = app.tabs[i]
|
||||
.selected_grips
|
||||
.iter()
|
||||
.find(|g| super::block_actions::is_test_grip(g.id))
|
||||
.unwrap();
|
||||
assert!(grip.world.distance(glam::DVec3::new(20., 70., 0.)) < 1e-8);
|
||||
let id = grip.id;
|
||||
assert!(app.start_test_action_grip(reference, id));
|
||||
feed(&mut app, "20,50");
|
||||
let EntityType::Line(line) = app.tabs[i].scene.document.get_entity(member).unwrap() else {
|
||||
panic!()
|
||||
};
|
||||
assert!(line.start.x.abs() < 1e-8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn authoring_edit_basepoint_attribute_relocation_undo_and_cancel() {
|
||||
let (mut app, reference) = fixture();
|
||||
@@ -478,6 +597,7 @@ fn block_actions_command_selection_cancel_undo_and_test_block_isolation() {
|
||||
let shared_before = app.tabs[test].scene.document.clone();
|
||||
let id = app.tabs[test].id;
|
||||
let _ = app.handle_block_action_result(crate::command::CmdResult::EvaluateBlockParameter {
|
||||
insert: None,
|
||||
document: id,
|
||||
definition,
|
||||
parameter: p.handle,
|
||||
@@ -558,6 +678,7 @@ fn block_actions_test_reference_transform_visibility_and_noop_history() {
|
||||
.apply(actions::native(p.end)),
|
||||
);
|
||||
let _ = app.handle_block_action_result(crate::command::CmdResult::EvaluateBlockParameter {
|
||||
insert: None,
|
||||
document: id,
|
||||
definition,
|
||||
parameter: p.handle,
|
||||
@@ -596,6 +717,7 @@ fn block_actions_test_reference_transform_visibility_and_noop_history() {
|
||||
);
|
||||
let before = app.tabs[i].scene.document.clone();
|
||||
let _ = app.handle_block_action_result(crate::command::CmdResult::EvaluateBlockParameter {
|
||||
insert: None,
|
||||
document: id,
|
||||
definition,
|
||||
parameter: p.handle,
|
||||
|
||||
Reference in new issue
Block a user