Joints mate face to face; Drive Joints takes the keyboard; Appearance on the engine's list
Joint dialog: picked origins mate as in Fusion, B's z opposite A's (two top faces put B upside down on A, not inside it; a pin goes into its hole); the dialog's Flip turns B the other way (sent as the command's flip, which turns B over from coinciding frames). Edit Joint shows the same. Found by solvecraft-sketchux's scenarios. Drive Joints: the first value box takes the keyboard with its text selected when the dialog opens, so typing 90 and Enter drives the joint (found by solvecraft-sketchux). Appearance: "In This Design" from appearance.list (in_design) when the engine has it; faces are sent as face targets once the engine knows them. Tests: face snaps mate face to face and Flip undoes it; typing into Drive Joints drives. 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
b2d611bafe
commit
4c3a5d9853
3 files changed
+130
-19
No files matched your search
@@ -131,8 +131,8 @@ fn apply_params(targets: &[Sel], color: [u8; 3], opacity: f32, look: Option<&str
|
||||
}
|
||||
if !faces.is_empty() {
|
||||
p["faces"] = json!(faces);
|
||||
// Until faces have their own looks: their bodies.
|
||||
if bodies.is_empty() {
|
||||
// An engine without face looks: their bodies.
|
||||
if bodies.is_empty() && solvecraft_engine::find_command("appearance.list").is_none() {
|
||||
let mut owners: Vec<String> =
|
||||
targets.iter().filter_map(|x| if let Sel::Face { body, .. } = x { Some(body.clone()) } else { None }).collect();
|
||||
owners.dedup();
|
||||
@@ -164,8 +164,18 @@ fn drop_target(app: &SolveApp, faces: bool) -> Vec<Sel> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The looks bodies have in this design (colour and how many bodies wear it).
|
||||
fn in_design(app: &SolveApp) -> Vec<([u8; 3], usize)> {
|
||||
/// The looks in this design (colour and how many items wear it): the engine's list when it has
|
||||
/// one, else the body colours.
|
||||
fn in_design(app: &mut SolveApp) -> Vec<([u8; 3], usize)> {
|
||||
if let Ok(v) = app.session.execute("appearance.list", &json!({}))
|
||||
&& let Some(list) = v.get("in_design").and_then(Value::as_array)
|
||||
{
|
||||
let count = |x: &Value, k: &str| x.get(k).and_then(Value::as_array).map_or(0, Vec::len);
|
||||
return list
|
||||
.iter()
|
||||
.filter_map(|x| Some((parse_color(x.get("color")?)?, count(x, "bodies") + count(x, "faces") + count(x, "components"))))
|
||||
.collect();
|
||||
}
|
||||
let mut out: Vec<([u8; 3], usize)> = Vec::new();
|
||||
for c in app.session.doc.appearances.values() {
|
||||
match out.iter_mut().find(|(x, _)| x == c) {
|
||||
@@ -270,7 +280,7 @@ pub fn rows(app: &mut SolveApp, ui: &mut egui::Ui, k: &mut Ap, inputs: &mut [Sel
|
||||
let items: Vec<(usize, &([u8; 3], usize))> = used.iter().enumerate().collect();
|
||||
swatch_rows(ui, &items, |ui, (i, (c, n))| {
|
||||
let look = Look { name: hex(*c), category: "In This Design".into(), color: *c, opacity: 1.0 };
|
||||
if swatch(ui, egui::Id::new(("ap_used", *i)), *c, 1.0, k.color == *c, &format!("{} · {n} bodies", hex(*c)), look).clicked() {
|
||||
if swatch(ui, egui::Id::new(("ap_used", *i)), *c, 1.0, k.color == *c, &format!("{} · {n} item(s)", hex(*c)), look).clicked() {
|
||||
k.color = *c;
|
||||
k.look = None;
|
||||
}
|
||||
@@ -382,7 +392,7 @@ mod tests {
|
||||
a.run(&id, p).unwrap();
|
||||
}
|
||||
assert_eq!(a.session.doc.appearances.get("Body2"), Some(&[196, 40, 36]));
|
||||
assert_eq!(in_design(&a), vec![([196, 40, 36], 2)]);
|
||||
assert_eq!(in_design(&mut a), vec![([196, 40, 36], 2)]);
|
||||
}
|
||||
|
||||
/// A swatch dropped on a face in face mode targets the face; otherwise its body.
|
||||
|
||||
Reference in new issue
Block a user