diff --git a/src/slic3r/GUI/CAD/DesignCanvas.cpp b/src/slic3r/GUI/CAD/DesignCanvas.cpp index bba4d42014..6234fa6f61 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.cpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.cpp @@ -1489,6 +1489,11 @@ const std::vector& DesignCanvas::sketch_entities() const return m_sketch_tool.entities(); } +int DesignCanvas::sketch_constraint_count() const +{ + return int(m_sketch_tool.constraints().size()); +} + bool DesignCanvas::try_add_sketch_constraints(const std::vector& defs) { return m_sketch_tool.try_add_constraints(defs); diff --git a/src/slic3r/GUI/CAD/DesignCanvas.hpp b/src/slic3r/GUI/CAD/DesignCanvas.hpp index 7f8de25a04..fe87936f8b 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.hpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.hpp @@ -299,6 +299,9 @@ public: // append->solve->keep-or-rollback, rather than reaching into mcp_sketch_tool(). const std::vector& sketch_selection() const; const std::vector& sketch_entities() const; + // How many constraints the LIVE session holds. Only a count: the hint line needs to know + // whether any badge is on screen to talk about, nothing more. + int sketch_constraint_count() const; bool try_add_sketch_constraints(const std::vector& defs); // In-canvas bbox transform of imported Text/SVG art (replaces the Move/Scale dialog). diff --git a/src/slic3r/GUI/CAD/DesignPanel.cpp b/src/slic3r/GUI/CAD/DesignPanel.cpp index 5266b1f3a9..cddecfbbb1 100644 --- a/src/slic3r/GUI/CAD/DesignPanel.cpp +++ b/src/slic3r/GUI/CAD/DesignPanel.cpp @@ -6329,6 +6329,12 @@ void DesignPanel::on_sketch_step(int mode, int step, int picks) if (step == 0 && picks == 0 && DesignSketchTool::Mode(mode) != DesignSketchTool::Mode::Select && !text.IsEmpty()) text += _L(" · Esc goes back to Select"); + // Badges are clickable and nothing said so — a glyph reads as decoration until something + // tells you it is a target. Only in Select mode (the only mode where the click is wired) and + // only once a constraint exists, so it never advertises a badge that is not on screen. + if (DesignSketchTool::Mode(mode) == DesignSketchTool::Mode::Select && m_viewport != nullptr && + m_viewport->sketch_constraint_count() > 0 && !text.IsEmpty()) + text += _L(" · click a constraint badge to remove it"); m_sketch_step = text; if (text.IsEmpty() || m_status == nullptr) return; m_status->SetForegroundColour(wxNullColour); @@ -7842,7 +7848,9 @@ void DesignPanel::apply_live_constraint(SketchConstraintType type) } m_viewport->request_repaint(); m_status->SetForegroundColour(wxNullColour); - set_status(_L("Applied constraint")); + // Say where it went and how to undo it, here at the moment of applying: the hint line + // only refreshes when the step tuple changes, which applying a constraint does not. + set_status(_L("Applied constraint · its badge is on the sketch — click the badge to remove it")); m_status->Refresh(); }; diff --git a/src/slic3r/GUI/CAD/DesignSketchTool.cpp b/src/slic3r/GUI/CAD/DesignSketchTool.cpp index f205b800eb..68c2196912 100644 --- a/src/slic3r/GUI/CAD/DesignSketchTool.cpp +++ b/src/slic3r/GUI/CAD/DesignSketchTool.cpp @@ -2382,7 +2382,11 @@ bool DesignSketchTool::remove_constraint_near(const Vec2d& p) } if (best < 0) return false; m_constraints.erase(m_constraints.begin() + best); - solve_sketch_entities(m_entities, m_constraints); + // resolve_live(), not a bare solve: it is the path that recomputes the DoF, clears the + // per-entity conflict flags and fires on_solve_state. Solving directly would relax the + // geometry while leaving the DoF readout and any red over-constrained tint stale — the + // readout would still describe the constraint that was just deleted. + resolve_live(); m_glyph_hits.clear(); // stale until the next render rebuilds them return true; }