feat(block-editor): wire Rotation, Alignment and Flip parameter placement

Enable the existing palette rows and BPARAMETER choices. Rotation accepts a
center, picked or numeric radius, and picked or numeric default angle.
Alignment places a tangent direction from its base point. Flip places a
reflection line and state label, with native grip and state expressions.

Extend shared graph append/capacity checks for Flip's additional state node
while preserving existing subgraphs. Keep Polar/Rotation angle labels unique
in either placement order. Add editor graphics, extents and definition
reframing through the existing overlay/history/save paths.

This milestone implements native parameter placement and persistence.
Rotate/Flip action association, reference alignment/grip editing, parameter
property editing and parameter sets remain separate work.

Validation covers command and palette placement, cancellation, local/parent
undo, save/discard, native DWG/DXF objects, existing graph preservation and
the 17 research fixtures. Broader block/dock regressions and editor renders
are also checked.
This commit is contained in:
Karim Jerbi committed 2026-10-15 16:50:47 +01:00
1 parent 6dab5a7229
commit 72c762e944
19 files changed
+1483 -25

No files matched your search

+48
View File
@@ -863,6 +863,54 @@ fn distance_parameter_batch_starts_from_actual_palette_rows() {
});
}
#[test]
fn orientation_parameter_batch_starts_from_actual_palette_rows() {
with_stack(|| {
for (id, name, inputs) in [
(
"authoring-tool-rotation",
"rotation",
vec!["0.35,-0.12", "0.65,-0.12", "0.35,0.2"],
),
(
"authoring-tool-alignment",
"alignment",
vec!["0.25,-0.1", "0.6,0.15"],
),
(
"authoring-tool-flip",
"flip",
vec!["0.35,-0.15", "0.35,0.15", "0.6,0.15"],
),
] {
let mut app = authoring_app();
let _ = app.dispatch_command("BAUTHORPALETTE");
let point = authoring_control(&app, id);
authoring_click(&mut app, point);
let i = app.active_tab;
let before = app.tabs[i].scene.document.clone();
for text in &inputs[..inputs.len() - 1] {
let _ = app.update(Message::CommandInput((*text).into()));
let _ = app.update(Message::CommandSubmit);
assert_eq!(app.tabs[i].scene.document, before);
}
let _ = app.update(Message::CommandInput(inputs.last().unwrap().to_string()));
let _ = app.update(Message::CommandSubmit);
let definition = app.tabs[i].active_block_edit_session().unwrap().br_handle;
let found = crate::scene::block_orientation_parameter::parameters(
&app.tabs[i].scene.document,
definition,
);
assert_eq!(found.len(), 1);
assert!(found[0].kind.name().eq_ignore_ascii_case(name));
assert!(app.tabs[i].scene.preview_wires.is_empty());
assert_eq!(app.tabs[i].history.undo_stack.len(), 1);
let _ = app.run_command_line("ZOOM E");
authoring_capture(&app, &format!("{name}-parameter-placed"));
}
});
}
fn authoring_app() -> OpenCADStudio {
use codec::{
entities::{Insert, Line},
+1
View File
@@ -408,6 +408,7 @@ impl OpenCADStudio {
chrome,
self.visibility_placement_error(),
self.point_parameter_placement_error(),
self.parameter_placement_error("FLIP"),
)
}
crate::ui::dock::PanelId::BlockPalette => {