Physical Material dialog (body appearance follows the material: steel, brass, copper, PLA…), Enter applies every OK dialog
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
218d19d753
commit
967bee179a
3 files changed
+49
-5
No files matched your search
@@ -78,6 +78,10 @@ pub enum Kind {
|
||||
Sweep {
|
||||
operation: usize,
|
||||
},
|
||||
/// Physical material (and with it the appearance) of bodies.
|
||||
Material {
|
||||
index: usize,
|
||||
},
|
||||
/// Section Analysis: cut the view by a plane, moved along its normal.
|
||||
Section {
|
||||
offset: String,
|
||||
@@ -202,6 +206,7 @@ impl Dialog {
|
||||
"MirrorCommand" => {
|
||||
Dialog::new(Kind::Mirror, vec![SelInput::new("Bodies", BODIES, true), SelInput::new("Mirror plane", PLANES | PLANAR_FACES, false)])
|
||||
}
|
||||
"PhysicalMaterialCommand" => Dialog::new(Kind::Material { index: 1 }, vec![SelInput::new("Bodies", BODIES, true)]),
|
||||
"FusionHalfSectionViewCommand" => {
|
||||
Dialog::new(Kind::Section { offset: "0 mm".into(), flip: false }, vec![SelInput::new("Plane", PLANES | PLANAR_FACES, false)])
|
||||
}
|
||||
@@ -489,6 +494,7 @@ fn title(k: &Kind) -> &'static str {
|
||||
Kind::Draft { .. } => "DRAFT",
|
||||
Kind::Mirror => "MIRROR",
|
||||
Kind::Measure { .. } => "MEASURE",
|
||||
Kind::Material { .. } => "PHYSICAL MATERIAL",
|
||||
Kind::Section { .. } => "SECTION ANALYSIS",
|
||||
Kind::PatternRect { .. } => "RECTANGULAR PATTERN",
|
||||
Kind::PatternCirc { .. } => "CIRCULAR PATTERN",
|
||||
@@ -749,6 +755,12 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
}
|
||||
Kind::Mirror => {}
|
||||
Kind::Measure { result, .. } => measure_rows(ui, result.as_ref()),
|
||||
Kind::Material { index } => {
|
||||
let names: Vec<&str> = solvecraft_engine::doc::MATERIALS.iter().map(|(n, _)| *n).collect();
|
||||
ui.label("Material");
|
||||
combo(ui, "mat", &names, index);
|
||||
ui.end_row();
|
||||
}
|
||||
Kind::Section { offset, flip } => {
|
||||
ui.label("Distance");
|
||||
enter |= field(ui, offset);
|
||||
@@ -902,7 +914,8 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
let (enter_free, esc) = ctx.input(|i| (i.key_pressed(egui::Key::Enter), i.key_pressed(egui::Key::Escape)));
|
||||
let nothing_focused = ctx.memory(|m| m.focused().is_none());
|
||||
let canvas_enter = enter_free && ctx.memory(|m| m.had_focus_last_frame(egui::Id::new("sc_canvas_value")));
|
||||
if d.previews() && (enter || canvas_enter || (enter_free && nothing_focused)) {
|
||||
let enter_applies = !matches!(d.kind, Kind::Sketch | Kind::Params { .. } | Kind::Measure { .. } | Kind::ConfirmDelete { .. });
|
||||
if enter_applies && (enter || canvas_enter || (enter_free && nothing_focused)) {
|
||||
ok = true;
|
||||
}
|
||||
if esc {
|
||||
@@ -1212,6 +1225,11 @@ fn dialog_commands(app: &SolveApp, d: &Dialog) -> Result<Vec<(String, Value)>, S
|
||||
json!({"sketch": sketch, "profiles": idx, "path_sketch": path_sketch, "path": path, "operation": OPS.get(*operation).copied().unwrap_or("new")}),
|
||||
)
|
||||
}
|
||||
Kind::Material { index } => {
|
||||
need(0, "bodies")?;
|
||||
let name = solvecraft_engine::doc::MATERIALS.get(*index).map(|(n, _)| *n).unwrap_or("Default");
|
||||
("PhysicalMaterialCommand", json!({"bodies": body_names(0), "material": name}))
|
||||
}
|
||||
Kind::Section { offset, flip } => {
|
||||
need(0, "a plane or planar face")?;
|
||||
let plane = match sels(d, 0).first() {
|
||||
|
||||
@@ -239,6 +239,26 @@ impl Tokens {
|
||||
}
|
||||
}
|
||||
|
||||
/// How a physical material looks (the default appearance follows the material).
|
||||
pub fn material_color(name: &str) -> Option<Color32> {
|
||||
Some(match name {
|
||||
"Steel" => Color32::from_rgb(158, 164, 172),
|
||||
"Stainless Steel" => Color32::from_rgb(186, 191, 198),
|
||||
"Aluminum" => Color32::from_rgb(204, 208, 214),
|
||||
"Brass" => Color32::from_rgb(208, 172, 88),
|
||||
"Copper" => Color32::from_rgb(204, 122, 80),
|
||||
"Titanium" => Color32::from_rgb(150, 148, 158),
|
||||
"Cast Iron" => Color32::from_rgb(104, 104, 110),
|
||||
"ABS Plastic" => Color32::from_rgb(222, 222, 216),
|
||||
"PLA" => Color32::from_rgb(110, 160, 222),
|
||||
"Nylon" => Color32::from_rgb(236, 230, 214),
|
||||
"Polycarbonate" => Color32::from_rgb(196, 216, 232),
|
||||
"Oak" => Color32::from_rgb(190, 146, 92),
|
||||
"Glass" => Color32::from_rgb(170, 208, 218),
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Switch themes (the visuals follow on the next [`apply`]).
|
||||
pub fn set_dark(dark: bool) {
|
||||
DARK.store(dark, Ordering::Relaxed);
|
||||
|
||||
@@ -195,7 +195,7 @@ fn build_scene(app: &SolveApp) -> GpuScene {
|
||||
if app.ui.hidden_bodies.contains(&b.name) || app.preview.replaced.contains(&b.name) {
|
||||
continue;
|
||||
}
|
||||
let col = c4(tk.body);
|
||||
let col = c4(s.doc.materials.get(&b.name).and_then(|m| crate::theme::material_color(m)).unwrap_or(tk.body));
|
||||
let m = b.mesh();
|
||||
for t in &m.triangles {
|
||||
for k in t {
|
||||
@@ -663,8 +663,8 @@ fn build_highlight(app: &SolveApp) -> GpuScene {
|
||||
// Bodies made by the timeline item under the cursor.
|
||||
if let Some(fid) = app.viewport.hover_feature {
|
||||
let k = t.hover_face_lift;
|
||||
let c = (t.body.r(), t.body.g(), t.body.b());
|
||||
for b in st.bodies.iter().filter(|b| b.feature == fid && !app.ui.hidden_bodies.contains(&b.name)) {
|
||||
let c = body_rgb(app, &b.name);
|
||||
let m = b.mesh();
|
||||
for f in 0..b.body.face_count() {
|
||||
face_tris(&mut sc, &m, f, [c.0.saturating_add(k), c.1.saturating_add(k), c.2.saturating_add(k), 255], true);
|
||||
@@ -682,7 +682,7 @@ fn build_highlight(app: &SolveApp) -> GpuScene {
|
||||
Some(Hit::Face { body, .. }) if app.ui.pick_bodies && app.dialog.is_none() && app.tool.is_none() => {
|
||||
if let Some(b) = st.body(body) {
|
||||
let k = t.hover_face_lift;
|
||||
let c = (t.body.r(), t.body.g(), t.body.b());
|
||||
let c = body_rgb(app, body);
|
||||
let m = b.mesh();
|
||||
for f in 0..b.body.face_count() {
|
||||
face_tris(&mut sc, &m, f, [c.0.saturating_add(k), c.1.saturating_add(k), c.2.saturating_add(k), 255], true);
|
||||
@@ -695,7 +695,7 @@ fn build_highlight(app: &SolveApp) -> GpuScene {
|
||||
{
|
||||
if let Some(b) = st.body(body) {
|
||||
let k = t.hover_face_lift;
|
||||
let c = (t.body.r(), t.body.g(), t.body.b());
|
||||
let c = body_rgb(app, body);
|
||||
face_tris(&mut sc, &b.mesh(), *index, [c.0.saturating_add(k), c.1.saturating_add(k), c.2.saturating_add(k), 255], true);
|
||||
let m = b.mesh();
|
||||
for e in m.face_edges(u32::try_from(*index).unwrap_or(u32::MAX)) {
|
||||
@@ -727,6 +727,12 @@ fn build_highlight(app: &SolveApp) -> GpuScene {
|
||||
sc
|
||||
}
|
||||
|
||||
/// A body's display colour (its material's, else the theme's) as RGB.
|
||||
fn body_rgb(app: &SolveApp, name: &str) -> (u8, u8, u8) {
|
||||
let c = app.session.doc.materials.get(name).and_then(|m| crate::theme::material_color(m)).unwrap_or(Tokens::get().body);
|
||||
(c.r(), c.g(), c.b())
|
||||
}
|
||||
|
||||
fn polyline_mid(pts: &[Vec3]) -> Vec3 {
|
||||
let len: f64 = pts.windows(2).map(|w| w[0].dist(w[1])).sum();
|
||||
let mut acc = 0.0;
|
||||
|
||||
Reference in new issue
Block a user