Extrude preview: a New Body has its own colour, apart from Join (#1805) (#1861)

Thanks @DuBearte.
This commit is contained in:
DuBearte authored and GitHub committed 2026-10-17 04:08:03 -04:00
1 parent 3689f0d6e5
commit 39850fb6ab
7 files changed
+39 -8

No files matched your search

+1
View File
@@ -48,6 +48,7 @@ impl Tokens {
body_edge: Color32::from_rgb(40, 44, 52),
manipulator: Color32::from_rgb(40, 110, 220),
preview_add: Color32::from_rgb(112, 160, 226),
preview_new: Color32::from_rgb(240, 225, 105),
preview_sketch: Color32::from_rgb(32, 190, 96),
preview_cut: Color32::from_rgba_unmultiplied_const(232, 84, 44, 110),
cube_face: Color32::from_rgb(236, 239, 244),
@@ -292,6 +292,7 @@ fn groups(t: &Tokens) -> Vec<Group> {
("body_selected", t.body_selected),
("hover_face_lift", lift(t.body)),
("preview_add", t.preview_add),
("preview_new", t.preview_new),
],
&[],
),
+1 -1
View File
@@ -1001,7 +1001,7 @@ pub fn world_preview(s: &Session, cmds: &[(String, Value)], colors: Colors) -> O
.map(|(_, r)| r.clone());
let (before, after) = (preview.before, preview.after);
// A moved component looks like itself (no new surface), with its old place as the ghost.
let colors = Colors { added: colors.body, ..colors };
let colors = Colors { added: colors.body, new_body: colors.body, ..colors };
let built = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| crate::preview::build(&before, &after, colors)));
Some(match built {
Ok(mut b) => {
+21 -3
View File
@@ -74,7 +74,13 @@ fn joint_and_drive_preview_on_the_placed_model() {
let mut d = app.dialog.clone().unwrap();
d.pick(&app.session, face_sel(&app.session, Vec3::new(10.0, 10.0, 10.0)).unwrap());
d.pick(&app.session, face_sel(&app.session, Vec3::new(40.0, 10.0, 0.0)).unwrap());
let colors = crate::preview::Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] };
let colors = crate::preview::Colors {
body: [1, 1, 1, 255],
added: [2, 2, 2, 255],
new_body: [2, 2, 2, 255],
removed: [3, 3, 3, 100],
edge: [0, 0, 0, 255],
};
let cmds = preview_commands(&app, &d).unwrap();
let b = world_preview(&app.session, &cmds, colors).unwrap().unwrap();
assert_eq!(b.replaced, vec!["Body2".to_string()], "B moves");
@@ -461,7 +467,13 @@ fn four_bar() -> SolveApp {
#[test]
fn drive_says_where_a_loop_stopped_it() {
let mut app = four_bar();
let colors = crate::preview::Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] };
let colors = crate::preview::Colors {
body: [1, 1, 1, 255],
added: [2, 2, 2, 255],
new_body: [2, 2, 2, 255],
removed: [3, 3, 3, 100],
edge: [0, 0, 0, 255],
};
let rocker = app.session.doc.assembly.joints.iter().position(|j| j.name == "Rocker").unwrap();
let mut d = drive_joint(&app, app.session.doc.assembly.joints[rocker].id).unwrap();
let ask = |d: &mut Dialog, v: &str| {
@@ -514,7 +526,13 @@ fn drive_says_when_its_joint_is_joined_to_nothing_grounded() {
if let Kind::Assembly(Asm::Drive { values, .. }) = &mut d.kind {
values[0] = "45 deg".into();
}
let colors = crate::preview::Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] };
let colors = crate::preview::Colors {
body: [1, 1, 1, 255],
added: [2, 2, 2, 255],
new_body: [2, 2, 2, 255],
removed: [3, 3, 3, 100],
edge: [0, 0, 0, 255],
};
let b = world_preview(&app.session, &apply_commands(&app, &d).unwrap(), colors).unwrap().unwrap();
let why = b.stopped.as_ref().and_then(drive_stop).unwrap();
assert!(why.starts_with("Moves nothing") && why.contains("C:1"), "{why}");
+12 -3
View File
@@ -26,6 +26,8 @@ use crate::theme::Tokens;
pub struct Colors {
pub body: [u8; 4],
pub added: [u8; 4],
/// A body the preview creates (New Body), so it doesn't look like a join.
pub new_body: [u8; 4],
pub removed: [u8; 4],
pub edge: [u8; 4],
}
@@ -33,7 +35,7 @@ pub struct Colors {
impl Colors {
pub fn from_tokens(t: &Tokens) -> Colors {
let c = |c: egui::Color32| c.to_srgba_unmultiplied();
Colors { body: c(t.body), added: c(t.preview_add), removed: c(t.preview_cut), edge: c(t.body_edge) }
Colors { body: c(t.body), added: c(t.preview_add), new_body: c(t.preview_new), removed: c(t.preview_cut), edge: c(t.body_edge) }
}
}
@@ -501,7 +503,11 @@ pub fn build(before: &ModelState, after: &ModelState, c: Colors) -> Built {
let cut = old.as_ref().is_some_and(|bm| am.measure().volume < bm.measure().volume - 1e-6);
for (t, f) in am.triangles.iter().zip(&am.tri_face) {
let new = added.get(*f as usize).copied().unwrap_or(true);
let col = if new { c.added } else { c.body };
let col = match (new, old.is_some()) {
(false, _) => c.body,
(true, true) => c.added,
(true, false) => c.new_body,
};
for k in t {
let i = *k as usize;
if let (Some(p), Some(n)) = (am.positions.get(i), am.normals.get(i)) {
@@ -717,7 +723,7 @@ mod tests {
use serde_json::json;
fn colors() -> Colors {
Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] }
Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], new_body: [4, 4, 4, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] }
}
#[test]
@@ -1006,6 +1012,9 @@ mod tests {
let b = compute(&s, &[("solid.extrude".into(), json!({"distance": "15 mm"}))], colors()).unwrap();
assert!(b.replaced.is_empty());
assert_eq!(count(&b.scene.tris, crate::gpu::TRI_SIZE, colors().body), 0);
// #1805: a new body has its own colour, not a join's.
assert!(count(&b.scene.tris, crate::gpu::TRI_SIZE, colors().new_body) > 0);
assert_eq!(count(&b.scene.tris, crate::gpu::TRI_SIZE, colors().added), 0);
assert!(b.scene.ghost.is_empty());
assert!(compute(&s, &[("solid.extrude".into(), json!({"distance": "1 +"}))], colors()).is_err());
assert!(s.model.state().bodies.is_empty());
+1 -1
View File
@@ -3,7 +3,7 @@ use super::*;
use serde_json::json;
fn colors() -> Colors {
Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] }
Colors { body: [1, 1, 1, 255], added: [2, 2, 2, 255], new_body: [2, 2, 2, 255], removed: [3, 3, 3, 100], edge: [0, 0, 0, 255] }
}
fn fixture() -> Session {
+2
View File
@@ -208,6 +208,8 @@ pub struct Tokens {
pub manipulator: Color32,
/// New surface in a feature preview.
pub preview_add: Color32,
/// The surface of a body a feature preview creates (New Body), apart from a join (#1805).
pub preview_new: Color32,
/// Proposed sketch geometry, distinct from blue selections.
pub preview_sketch: Color32,
/// Removed material in a feature preview (translucent).