Dialog parity: Mirror has Object Type (Bodies / Features, a hole mirrored as a feature; Edit Feature keeps it); Thread has Full Length (a length only when off)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
23d38fab97
commit
c0725ebc86
2 files changed
+42
-9
No files matched your search
@@ -873,7 +873,7 @@ fn objects_label(accept: Accept) -> &'static str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_pattern(k: &Kind) -> bool {
|
fn is_pattern(k: &Kind) -> bool {
|
||||||
matches!(k, Kind::PatternRect { .. } | Kind::PatternCirc { .. } | Kind::PathPattern { .. })
|
matches!(k, Kind::PatternRect { .. } | Kind::PatternCirc { .. } | Kind::PathPattern { .. } | Kind::Mirror)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Object Type row of a pattern: bodies (picked in the view) or features (picked in the
|
/// The Object Type row of a pattern: bodies (picked in the view) or features (picked in the
|
||||||
@@ -896,6 +896,10 @@ fn object_type_row(d: &mut Dialog, ui: &mut egui::Ui) {
|
|||||||
/// Rows above the selection inputs: the pattern type and object type, the Hole placement (one
|
/// Rows above the selection inputs: the pattern type and object type, the Hole placement (one
|
||||||
/// face point, or sketch points).
|
/// face point, or sketch points).
|
||||||
fn placement_row(d: &mut Dialog, ui: &mut egui::Ui) {
|
fn placement_row(d: &mut Dialog, ui: &mut egui::Ui) {
|
||||||
|
if matches!(d.kind, Kind::Mirror) {
|
||||||
|
object_type_row(d, ui);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if matches!(d.kind, Kind::Move { .. }) {
|
if matches!(d.kind, Kind::Move { .. }) {
|
||||||
crate::dialogs_move::type_row(d, ui);
|
crate::dialogs_move::type_row(d, ui);
|
||||||
return;
|
return;
|
||||||
@@ -1331,15 +1335,22 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
|||||||
ui.end_row();
|
ui.end_row();
|
||||||
}
|
}
|
||||||
Kind::Thread { designation, length } => {
|
Kind::Thread { designation, length } => {
|
||||||
|
// Fusion's order: Full Length, then the size; a length only when not full.
|
||||||
|
row_label(ui, "Full Length");
|
||||||
|
let mut full = length.trim().is_empty();
|
||||||
|
if ui.checkbox(&mut full, "").changed() {
|
||||||
|
*length = if full { String::new() } else { "10 mm".into() };
|
||||||
|
}
|
||||||
|
ui.end_row();
|
||||||
row_label(ui, "Size");
|
row_label(ui, "Size");
|
||||||
let r = ui.add(egui::TextEdit::singleline(designation).hint_text("fits the face, e.g. M8"));
|
let r = ui.add(egui::TextEdit::singleline(designation).hint_text("fits the face, e.g. M8"));
|
||||||
enter |= r.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter));
|
enter |= r.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter));
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
row_label(ui, "Length");
|
if !full {
|
||||||
let r = ui.add(egui::TextEdit::singleline(length).hint_text("whole face"));
|
row_label(ui, "Length");
|
||||||
crate::params_dialog::complete(ui, &r, length);
|
enter |= field(ui, length);
|
||||||
enter |= r.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter));
|
ui.end_row();
|
||||||
ui.end_row();
|
}
|
||||||
}
|
}
|
||||||
Kind::Material { index } => {
|
Kind::Material { index } => {
|
||||||
let names: Vec<&str> = solvecraft_engine::doc::MATERIALS.iter().map(|(n, _)| *n).collect();
|
let names: Vec<&str> = solvecraft_engine::doc::MATERIALS.iter().map(|(n, _)| *n).collect();
|
||||||
@@ -1814,9 +1825,9 @@ fn dialog_commands(app: &SolveApp, d: &Dialog) -> Result<Vec<(String, Value)>, S
|
|||||||
("FusionDraftCommand", json!({"faces": face_points(0), "angle": angle, "neutral": neutral}))
|
("FusionDraftCommand", json!({"faces": face_points(0), "angle": angle, "neutral": neutral}))
|
||||||
}
|
}
|
||||||
Kind::Mirror => {
|
Kind::Mirror => {
|
||||||
need(0, "bodies")?;
|
need(0, "objects")?;
|
||||||
need(1, "the mirror plane")?;
|
need(1, "the mirror plane")?;
|
||||||
let features = source_features(s, &body_names(0));
|
let features = pattern_features(s, sels(d, 0));
|
||||||
let plane = plane_value(s, sels(d, 1).first()).ok_or("the mirror plane must be a plane or a planar face")?;
|
let plane = plane_value(s, sels(d, 1).first()).ok_or("the mirror plane must be a plane or a planar face")?;
|
||||||
("MirrorCommand", json!({"features": features, "plane": plane}))
|
("MirrorCommand", json!({"features": features, "plane": plane}))
|
||||||
}
|
}
|
||||||
@@ -2481,8 +2492,16 @@ pub fn for_feature(app: &SolveApp, id: u64, marker: Option<usize>) -> Option<Dia
|
|||||||
FeatureKind::Mirror { features, plane, .. } => {
|
FeatureKind::Mirror { features, plane, .. } => {
|
||||||
let mut d = start("MirrorCommand")?;
|
let mut d = start("MirrorCommand")?;
|
||||||
let ids: Vec<u64> = features.iter().filter_map(|n| s.doc.find_feature(n).map(|f| f.id)).collect();
|
let ids: Vec<u64> = features.iter().filter_map(|n| s.doc.find_feature(n).map(|f| f.id)).collect();
|
||||||
|
// Features that made no body of their own (a hole) were picked as features.
|
||||||
|
let as_features = ids.iter().any(|id| !st.bodies.iter().any(|b| b.feature == *id));
|
||||||
if let Some(inp) = d.inputs.get_mut(0) {
|
if let Some(inp) = d.inputs.get_mut(0) {
|
||||||
inp.items = st.bodies.iter().filter(|b| ids.contains(&b.feature)).map(|b| Sel::Body { name: b.name.clone() }).collect();
|
if as_features {
|
||||||
|
inp.accept = selection::FEATURES;
|
||||||
|
inp.label = objects_label(inp.accept);
|
||||||
|
inp.items = ids.iter().map(|id| Sel::Feature { id: *id }).collect();
|
||||||
|
} else {
|
||||||
|
inp.items = st.bodies.iter().filter(|b| ids.contains(&b.feature)).map(|b| Sel::Body { name: b.name.clone() }).collect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(inp) = d.inputs.get_mut(1) {
|
if let Some(inp) = d.inputs.get_mut(1) {
|
||||||
inp.items = plane_sel(s, plane).into_iter().collect();
|
inp.items = plane_sel(s, plane).into_iter().collect();
|
||||||
|
|||||||
@@ -176,3 +176,17 @@ fn a_hole_is_patterned_as_a_feature() {
|
|||||||
assert_eq!(e.inputs[0].accept, crate::selection::FEATURES);
|
assert_eq!(e.inputs[0].accept, crate::selection::FEATURES);
|
||||||
assert_eq!(e.inputs[0].items, vec![Sel::Feature { id: hole }]);
|
assert_eq!(e.inputs[0].items, vec![Sel::Feature { id: hole }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_hole_is_mirrored_as_a_feature() {
|
||||||
|
let mut app = app_with(json!([
|
||||||
|
{"command": "PrimitiveBox", "params": {"length": 60, "width": 40, "height": 10}},
|
||||||
|
{"command": "FusionHoleCommand", "params": {"position": [10, 10, 10], "diameter": 5}}
|
||||||
|
]));
|
||||||
|
let hole = app.session.doc.features.last().unwrap().id;
|
||||||
|
let mut d = start(&mut app, vec![Sel::Feature { id: hole }], "MirrorCommand");
|
||||||
|
assert_eq!(d.inputs[0].accept, crate::selection::FEATURES);
|
||||||
|
d.inputs[1].items = vec![Sel::Plane { name: "YZ".into() }];
|
||||||
|
let cmds = apply_commands(&app, &d).unwrap();
|
||||||
|
assert_eq!(cmds[0].1["features"], json!(["Hole1"]));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user