diff --git a/src/slic3r/GUI/DesignCanvas.cpp b/src/slic3r/GUI/DesignCanvas.cpp index 05de5abac2..2296896a37 100644 --- a/src/slic3r/GUI/DesignCanvas.cpp +++ b/src/slic3r/GUI/DesignCanvas.cpp @@ -604,6 +604,11 @@ void DesignCanvas::set_loop_pick(int feature, int region) request_repaint(); } +void DesignCanvas::set_escalate_on_repick(bool on) +{ + m_sketch_tool.set_escalate_on_repick(on); +} + void DesignCanvas::set_solid_pick(const std::vector* bodies, const TriangleMesh* mesh, const std::vector* tri_face, const std::vector* tri_body, const std::vector* visible, diff --git a/src/slic3r/GUI/DesignCanvas.hpp b/src/slic3r/GUI/DesignCanvas.hpp index 74c238c365..833902b9cd 100644 --- a/src/slic3r/GUI/DesignCanvas.hpp +++ b/src/slic3r/GUI/DesignCanvas.hpp @@ -85,6 +85,7 @@ public: std::vector> region_entity_indices(const std::vector& ents) const; void clear_loop_pick(); // drop the click-selected loop highlight (e.g. after extrude) void set_loop_pick(int feature, int region); // adopt a loop pick made before the commit + void set_escalate_on_repick(bool on); // off while a card has armed a face/edge pick // Solid whole/face/edge selection: point the tool at the bodies + concatenated // tessellation (with per-triangle face & body ids), and a callback fired on each // whole->face->edge cycle (level, body index, face id, edge id). diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index 6441c0f1ef..865ea29eab 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -3493,6 +3493,7 @@ DesignPanel::DesignPanel(wxWindow* parent) default: break; } if (got) { m_plane_pick = PlanePick::None; refresh_plane_labels(); } + if (got && m_viewport) m_viewport->set_escalate_on_repick(true); } // Axis tool with a pick armed: face or edge. if (m_active == Tool::Axis && m_axis_pick != AxisPick::None) { @@ -3503,6 +3504,7 @@ DesignPanel::DesignPanel(wxWindow* parent) default: break; } if (got) { m_axis_pick = AxisPick::None; refresh_axis_labels(); } + if (got && m_viewport) m_viewport->set_escalate_on_repick(true); } // CoordSys tool with a pick armed: face or edge. if (m_active == Tool::CoordSys && m_coordsys_pick != CoordSysPick::None) { @@ -3513,6 +3515,7 @@ DesignPanel::DesignPanel(wxWindow* parent) default: break; } if (got) { m_coordsys_pick = CoordSysPick::None; refresh_coordsys_labels(); } + if (got && m_viewport) m_viewport->set_escalate_on_repick(true); } m_status->SetForegroundColour(wxNullColour); const int nb = int(m_doc.bodies.size()); @@ -5843,6 +5846,7 @@ void DesignPanel::reset_plane_refs() m_pl_faceA_body = m_pl_faceA = -1; m_pl_faceB_body = m_pl_faceB = -1; m_pl_edgeA_body = m_pl_edgeA = -1; m_pl_edgeB_body = m_pl_edgeB = -1; m_plane_pick = PlanePick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_plane_labels(); } @@ -5882,6 +5886,7 @@ void DesignPanel::reset_axis_refs() m_ax_face_body = m_ax_face = -1; m_ax_edge = -1; m_axis_pick = AxisPick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_axis_labels(); } @@ -5942,6 +5947,7 @@ void DesignPanel::reset_coordsys_refs() m_cs_face_body = m_cs_face = -1; m_cs_edge = -1; m_coordsys_pick = CoordSysPick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_coordsys_labels(); if (m_cs_body) m_cs_body->SetSelection(0); if (m_viewport) m_viewport->set_xray_focus(-1); @@ -5951,6 +5957,10 @@ void DesignPanel::reset_coordsys_refs() void DesignPanel::arm_coordsys_pick(CoordSysPick target) { m_coordsys_pick = target; + // While this pick is armed the click the card asked for must reach it, so the whole-body + // escalation is off: clicking the face the card is pointing at is the ANSWER here, not a + // request for its body. + if (m_viewport) m_viewport->set_escalate_on_repick(false); m_status->SetForegroundColour(wxNullColour); set_status(target == CoordSysPick::Face ? _L("Click a solid FACE in the viewport") : _L("Click a solid EDGE in the viewport")); @@ -8163,6 +8173,8 @@ void DesignPanel::load_feature_into_dialog(const CadFeature& f) m_plane_usize->SetValue(f.plane_u_size); m_plane_vsize->SetValue(f.plane_v_size); m_plane_pick = PlanePick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_plane_labels(); break; case CadFeatureType::Loft: @@ -8188,6 +8200,8 @@ void DesignPanel::load_feature_into_dialog(const CadFeature& f) m_axis_p1x->SetValue(f.axis_p1.x()); m_axis_p1y->SetValue(f.axis_p1.y()); m_axis_p1z->SetValue(f.axis_p1.z()); m_axis_p2x->SetValue(f.axis_p2.x()); m_axis_p2y->SetValue(f.axis_p2.y()); m_axis_p2z->SetValue(f.axis_p2.z()); m_axis_pick = AxisPick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_axis_labels(); break; case CadFeatureType::CoordSys: @@ -8201,6 +8215,8 @@ void DesignPanel::load_feature_into_dialog(const CadFeature& f) m_cs_hy->SetValue(f.coordsys_x_hint.y()); m_cs_hz->SetValue(f.coordsys_x_hint.z()); m_coordsys_pick = CoordSysPick::None; + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned + if (m_viewport) m_viewport->set_escalate_on_repick(true); // pick abandoned refresh_coordsys_labels(); refresh_cs_body_choice(); if (m_cs_body && f.coordsys_body >= 0) { diff --git a/src/slic3r/GUI/DesignSketchTool.cpp b/src/slic3r/GUI/DesignSketchTool.cpp index b696703c06..da6b9a67c9 100644 --- a/src/slic3r/GUI/DesignSketchTool.cpp +++ b/src/slic3r/GUI/DesignSketchTool.cpp @@ -3159,7 +3159,7 @@ bool DesignSketchTool::handle_solid_click(GLCanvas3D& canvas, const wxMouseEvent : m_solid_sel == SolidSel::Edge ? m_sel_edge == prev_edge : m_solid_sel == SolidSel::Face ? m_sel_face == prev_face : true); - if (same_pick) { + if (same_pick && m_escalate_repick) { select_body(m_sel_body); // clears face/edge/vertex, tints the whole body dp_pick_trace("re-pick -> escalated to whole body %d", m_sel_body); } diff --git a/src/slic3r/GUI/DesignSketchTool.hpp b/src/slic3r/GUI/DesignSketchTool.hpp index 4c19937199..db89f88295 100644 --- a/src/slic3r/GUI/DesignSketchTool.hpp +++ b/src/slic3r/GUI/DesignSketchTool.hpp @@ -90,6 +90,13 @@ public: // Does the live session hold anything a cancel would throw away? Escape must not silently // destroy drawn geometry; the panel asks this before treating Escape as "discard sketch". bool live_sketch_has_work() const { return !m_entities.empty(); } + + // Clicking the same sub-element again escalates to the whole body. That is right for free + // picking and WRONG while a card has armed a face/edge pick: the card says "click a FACE", + // the user clicks the face it is already showing, and the escalation turns it into a + // whole-body pick that the armed capture then rejects. The host turns this off for as long + // as a pick is armed. + void set_escalate_on_repick(bool on) { m_escalate_repick = on; } bool constrain_value_anchor(wxPoint& out) const; // screen anchor over the picked constrain geometry void begin(const SketchPlane& plane, Mode mode = Mode::Polyline); @@ -1043,6 +1050,7 @@ private: int& edge_feat, int& edge_reg, int& edge_ent, double& edge_d, int& face_feat, int& face_reg) const; bool m_right_consumed{false}; // last RightDown was a gesture terminator, not a menu + bool m_escalate_repick{true}; // re-picking the same sub-element takes the whole body void render_solid_highlight(); // The shared body of the above: one highlight from explicit arguments, so the committed // selection and the hover pre-highlight cannot drift apart in how they look.