From f4c39320ec98c0cae3fb51acfe9ba018a6e1587e Mon Sep 17 00:00:00 2001 From: bherbruck Date: Thu, 8 Oct 2026 10:54:11 +0000 Subject: [PATCH] One canvas panel: placing a canvas and Edit Canvas open the browser's canvas panel; the separate sketch-tool panel (which overlapped Calibrate) is gone Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL --- crates/ui-egui/src/sketch_tools.rs | 82 +++--------------------------- 1 file changed, 7 insertions(+), 75 deletions(-) diff --git a/crates/ui-egui/src/sketch_tools.rs b/crates/ui-egui/src/sketch_tools.rs index b4c74c89..0e7569d8 100644 --- a/crates/ui-egui/src/sketch_tools.rs +++ b/crates/ui-egui/src/sketch_tools.rs @@ -34,10 +34,6 @@ thread_local! { static ISO: RefCell>> = const { RefCell::new(Vec::new()) }; /// Center of Mass has just started: measure everything on the next frame. static DEFERRED: Cell = const { Cell::new(false) }; - /// The canvas whose panel is open. - static CANVAS_PANEL: Cell> = const { Cell::new(None) }; - /// The opacity slider while it is dragged: (canvas, value). - static OPACITY: Cell> = const { Cell::new(None) }; } /// Commands registered on one panel that Fusion also lists on another: the analyses (sketch @@ -161,8 +157,10 @@ pub fn start_hook(app: &mut SolveApp, id: &str) -> bool { return true; } if id == "canvas.edit" { - let first = app.session.doc.canvases.first().map(|c| c.id); - CANVAS_PANEL.with(|c| c.set(first)); + // The browser's canvas panel (one panel for canvases). + if let Some(first) = app.session.doc.canvases.first().map(|c| c.id) { + app.tree.canvas_panel = Some(crate::browser::CanvasPanel::new(app, first, false)); + } return false; } if !matches!(id, "FusionAddCanvasCommand" | "FusionAddEditDecalCommand") { @@ -174,73 +172,6 @@ pub fn start_hook(app: &mut SolveApp, id: &str) -> bool { ok } -/// The canvas panel: opacity, size, angle, flip, visibility of one canvas. -fn canvas_panel(app: &mut SolveApp, ctx: &egui::Context) { - let Some(id) = CANVAS_PANEL.with(|c| c.get()) else { return }; - let Some(c) = app.session.doc.canvases.iter().find(|c| c.id == id).cloned() else { - CANVAS_PANEL.with(|c| c.set(None)); - return; - }; - let ids: Vec<(u64, String)> = app.session.doc.canvases.iter().map(|c| (c.id, c.name.clone())).collect(); - let mut open = true; - let mut edit: Option = None; - let mut delete = false; - egui::Window::new("Canvas").open(&mut open).collapsible(false).resizable(false).default_pos(egui::pos2(320.0, 160.0)).show(ctx, |ui| { - egui::ComboBox::from_id_salt("sc_canvas_pick").selected_text(&c.name).show_ui(ui, |ui| { - for (cid, name) in &ids { - if ui.selectable_label(*cid == id, name).clicked() { - CANVAS_PANEL.with(|p| p.set(Some(*cid))); - } - } - }); - egui::Grid::new("sc_canvas_grid").num_columns(2).show(ui, |ui| { - ui.label("Opacity"); - let mut o = OPACITY.with(|v| v.get()).filter(|v| v.0 == id).map(|v| v.1).unwrap_or(c.opacity); - let r = ui.add(egui::Slider::new(&mut o, 0.0..=1.0).fixed_decimals(2)); - OPACITY.with(|v| v.set(Some((id, o)))); - if r.drag_stopped() || (r.changed() && !r.dragged()) { - edit = Some(json!({"canvas": id, "opacity": o})); - } - ui.end_row(); - ui.label("Width"); - let mut w = c.width; - if ui.add(egui::DragValue::new(&mut w).range(0.001..=1e6).suffix(" mm").speed(c.width * 0.005)).changed() { - edit = Some(json!({"canvas": id, "width": w})); - } - ui.end_row(); - ui.label("Angle"); - let mut a = c.angle.to_degrees(); - if ui.add(egui::DragValue::new(&mut a).suffix("°").speed(0.5)).changed() { - edit = Some(json!({"canvas": id, "angle": a})); - } - ui.end_row(); - let mut flip = c.flip; - if ui.checkbox(&mut flip, "Flip").changed() { - edit = Some(json!({"canvas": id, "flip": flip})); - } - let mut vis = c.visible; - if ui.checkbox(&mut vis, "Visible").changed() { - edit = Some(json!({"canvas": id, "visible": vis})); - } - ui.end_row(); - }); - if ui.button("Delete canvas").clicked() { - delete = true; - } - }); - if let Some(p) = edit { - let _ = app.run("canvas.edit", p); - OPACITY.with(|v| v.set(None)); - } - if delete { - let _ = app.run("canvas.delete", json!({"canvas": id})); - open = false; - } - if !open { - CANVAS_PANEL.with(|c| c.set(None)); - } -} - fn v3(v: &Value) -> Option { Some(Vec3::new(v.get(0)?.as_f64()?, v.get(1)?.as_f64()?, v.get(2)?.as_f64()?)) } @@ -659,7 +590,9 @@ pub fn on_click(app: &mut SolveApp, tool: &mut Tool, proj: &Proj, pos: Pos2) { if let Ok(v) = app.run(cmd, p) { IMAGE.with(|i| *i.borrow_mut() = None); app.tool = None; - CANVAS_PANEL.with(|c| c.set(v["canvas"].as_u64())); + if let Some(id) = v["canvas"].as_u64() { + app.tree.canvas_panel = Some(crate::browser::CanvasPanel::new(app, id, false)); + } } } Mode::ModelRef => { @@ -1083,7 +1016,6 @@ pub fn show(app: &mut SolveApp, ui: &egui::Ui, painter: &egui::Painter, proj: &P marks(app, painter, proj); iso_lines(app, painter, proj); text_entry(app, ui.ctx()); - canvas_panel(app, ui.ctx()); } /// The text-entry box for a placed text.