fix(ui): Sketch Palette line type buttons follow the selected curves (#422)

With sketch curves selected, the palette's Normal / Construction / Centerline
buttons now show the line type of the selection (each type of a mixed
selection); with nothing selected they show the drawing mode, as before.
Previously no button was highlighted while curves were selected.

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Tobias BreckleandClaude Opus 5.5 authored and GitHub committed 2026-10-12 18:45:19 -04:00
1 parent b447adafaa
commit 0bb5b7eb09
1 file changed
+61 -2
+61 -2
View File
@@ -128,6 +128,31 @@ fn selected_curves(app: &SolveApp) -> Vec<String> {
app.session.selection.iter().filter_map(|s| if let Sel::SketchCurve { id } = s { Some(id.clone()) } else { None }).collect()
}
/// The line types among the selected curves of the active sketch, indexed like the palette's
/// buttons (0 normal, 1 construction, 2 centerline); a mixed selection marks each of its types.
fn selected_linetypes(app: &SolveApp) -> [bool; 3] {
let mut types = [false; 3];
let curves = selected_curves(app);
if curves.is_empty() {
return types;
}
let st = app.session.world_state();
let Some(ss) = app.session.active_sketch.and_then(|s| st.sketch(s)) else { return types };
for c in curves.iter().filter_map(|id| ss.sketch.curve_index(id).and_then(|i| ss.sketch.curves.get(i))) {
let k = if c.centerline {
2
} else if c.construction {
1
} else {
0
};
if let Some(t) = types.get_mut(k) {
*t = true;
}
}
types
}
/// Set the line type of the selected curves: 0 normal, 1 construction, 2 centerline (lines).
pub fn set_linetype(app: &mut SolveApp, kind: u8) {
let curves = selected_curves(app);
@@ -205,6 +230,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
let mut look = false;
let mut finish = false;
let has_curves = !selected_curves(app).is_empty();
let selected_types = selected_linetypes(app);
let response = crate::frame::docked(
app.tr("ui.heading_sketch_palette"),
egui::Id::new("sc_sketch_palette"),
@@ -241,10 +267,11 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
ui.vertical(|ui| {
ui.label(app.tr("ui.linetype"));
ui.horizontal(|ui| {
// With a selection: convert it; without: the mode new curves are drawn in.
// With a selection: its line type, and a click converts it; without:
// the mode new curves are drawn in.
let current = mode(app);
for (i, (label, tip)) in [("—", "Normal"), ("- -", "Construction"), ("-·-", "Centerline")].iter().enumerate() {
let on = !has_curves && current == i as u8;
let on = if has_curves { selected_types.get(i).copied().unwrap_or(false) } else { current == i as u8 };
let tr_tip = app.tr_label(tip);
let tip = if has_curves {
crate::i18n::format("sketch.make_selection", &[("linetype", tr_tip)])
@@ -352,6 +379,38 @@ mod tests {
}
}
#[test]
fn linetype_buttons_follow_the_selection_and_fall_back_to_the_mode() {
let mut h = crate::scenario::Harness::new();
h.app.run("sketch.create", json!({"plane":"XY"})).unwrap();
let curve = |r: Value| r["curves"][0].as_str().unwrap().to_string();
let normal = curve(h.app.run("sketch.line", json!({"points":[[0,0],[20,0]],"infer":false,"connect":false})).unwrap());
let cons = curve(h.app.run("sketch.line", json!({"points":[[0,10],[20,10]],"infer":false,"connect":false})).unwrap());
let center = curve(h.app.run("sketch.line", json!({"points":[[0,20],[20,20]],"infer":false,"connect":false})).unwrap());
h.app.run("sketch.construction", json!({"curves":[cons],"value":true})).unwrap();
h.app.run("sketch.centerline", json!({"curves":[center],"value":true})).unwrap();
// Which of Normal, Construction and Centerline the palette shows pressed.
let pressed = |h: &mut crate::scenario::Harness, ids: &[&String]| {
h.app.session.selection = ids.iter().map(|id| Sel::SketchCurve { id: (*id).clone() }).collect();
h.settle();
let tree = h.output.accesskit_update.as_ref().unwrap();
["—", "- -", "-·-"]
.map(|label| tree.nodes.iter().any(|(_, n)| n.label() == Some(label) && n.toggled() == Some(egui::accesskit::Toggled::True)))
};
assert_eq!(pressed(&mut h, &[&normal]), [true, false, false]);
assert_eq!(pressed(&mut h, &[&cons]), [false, true, false]);
assert_eq!(pressed(&mut h, &[&center]), [false, false, true]);
// A mixed selection shows each of its line types.
assert_eq!(pressed(&mut h, &[&normal, &center]), [true, false, true]);
// Nothing selected: the drawing mode.
assert_eq!(pressed(&mut h, &[]), [true, false, false]);
set_mode(&mut h.app, 1);
assert_eq!(pressed(&mut h, &[]), [false, true, false]);
// A selection overrides the mode until it is cleared.
assert_eq!(pressed(&mut h, &[&normal]), [true, false, false]);
assert_eq!(pressed(&mut h, &[]), [false, true, false]);
}
#[test]
fn dof_readout() {
assert_eq!(dof_text(0, true), "Fully constrained");