diff --git a/src/slic3r/GUI/DesignCanvas.cpp b/src/slic3r/GUI/DesignCanvas.cpp index d553fe3806..baa15ad167 100644 --- a/src/slic3r/GUI/DesignCanvas.cpp +++ b/src/slic3r/GUI/DesignCanvas.cpp @@ -296,6 +296,7 @@ void DesignCanvas::reload(bool keep_view) if (b == m_hl_body_target) c = ColorRGBA(0.30f, 0.90f, 0.70f, 1.0f); // target = teal-green else if (b == m_hl_body_tool) c = ColorRGBA(1.00f, 0.55f, 0.15f, 1.0f); // tool = orange if (m_body_translucent) c.a(0.30f); + else if (m_xray_focus >= 0 && b != m_xray_focus) c.a(0.25f); v->set_color(c); } } else if (obj_idx == 1) { @@ -1050,6 +1051,14 @@ void DesignCanvas::set_body_translucent(bool on) reload(true); // re-applies object-0 alpha so the solid fades for the fillet preview } +void DesignCanvas::set_xray_focus(int body) +{ + if (m_xray_focus == body) return; + m_xray_focus = body; + m_sketch_tool.set_pick_only_body(body); + reload(true); // re-applies per-body alpha so the non-focused bodies fade +} + void DesignCanvas::set_body_hidden(bool on) { if (m_body_hidden == on) return; diff --git a/src/slic3r/GUI/DesignCanvas.hpp b/src/slic3r/GUI/DesignCanvas.hpp index 78034ed66f..41bd2460c5 100644 --- a/src/slic3r/GUI/DesignCanvas.hpp +++ b/src/slic3r/GUI/DesignCanvas.hpp @@ -194,6 +194,7 @@ public: void show_status_hud(bool on); void set_operand_bodies(int target_body, int tool_body); // -1,-1 clears void set_body_translucent(bool on); // render the solid see-through (fillet/chamfer preview) + void set_xray_focus(int body); // >=0: fade+lock out every other body (CoordSys picking) void set_body_hidden(bool on); // preview-only: hide base bodies, show only the result ghost void set_on_move_exit(std::function cb); // right-click finished the move-body gizmo // Right-click (or its platform equivalent) on the viewport with no tool running: open the @@ -292,6 +293,7 @@ private: int m_hl_body_target{-1}; int m_hl_body_tool{-1}; bool m_body_translucent{false};// fillet/chamfer preview → render the body see-through + int m_xray_focus{-1}; // >=0: only this body is opaque+clickable (CoordSys picking) bool m_body_hidden{false}; // preview-only mode → hide base bodies, ghost = the result std::vector m_body_visible; // per-body visibility (empty => all visible) // Live pointer to the document's bodies (stable address: m_doc.bodies), stashed by diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index 65bd47a1ba..a80f3a0836 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -2614,6 +2614,19 @@ DesignPanel::DesignPanel(wxWindow* parent) m_box_coordsys->Add(new wxStaticText(m_cards, wxID_ANY, _L("Type")), 0, wxLEFT | wxRIGHT | wxTOP, 12); m_box_coordsys->Add(m_coordsys_type, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 12); + m_cs_body = make_combo(m_cards); + m_cs_body->Append(_L("(all)")); + m_cs_body->SetSelection(0); + m_cs_body->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { + if (m_viewport) m_viewport->set_xray_focus(m_cs_body->GetSelection() - 1); + }); + m_box_coordsys->Add(new wxStaticText(m_cards, wxID_ANY, _L("Body")), 0, wxLEFT | wxRIGHT | wxTOP, 12); + m_box_coordsys->Add(m_cs_body, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 12); + auto* body_hint = new wxStaticText(m_cards, wxID_ANY, + _L("Restrict picking to one body — the others go see-through and stop catching clicks")); + body_hint->SetForegroundColour(dp_sec_text()); + m_box_coordsys->Add(body_hint, 0, wxLEFT | wxRIGHT | wxTOP, 12); + auto* csform = two_col_form(); m_cs_x = make_spin(m_cards, 0.0, -100000.0, 100000.0); @@ -5589,12 +5602,26 @@ void DesignPanel::refresh_coordsys_labels() if (m_cs_edge_lbl) m_cs_edge_lbl->SetLabel(txt(m_cs_edge)); } +void DesignPanel::refresh_cs_body_choice() +{ + if (!m_cs_body) return; + const int keep = m_cs_body->GetSelection(); + m_cs_body->Clear(); + m_cs_body->Append(_L("(all)")); + for (size_t b = 0; b < m_doc.bodies.size(); ++b) + m_cs_body->Append(wxString::Format(_L("Body %d"), int(b) + 1)); + m_cs_body->SetSelection(keep > 0 && keep < int(m_cs_body->GetCount()) ? keep : 0); +} + void DesignPanel::reset_coordsys_refs() { m_cs_face_body = m_cs_face = -1; m_cs_edge = -1; m_coordsys_pick = CoordSysPick::None; refresh_coordsys_labels(); + if (m_cs_body) m_cs_body->SetSelection(0); + if (m_viewport) m_viewport->set_xray_focus(-1); + refresh_cs_body_choice(); } void DesignPanel::arm_coordsys_pick(CoordSysPick target) @@ -7749,6 +7776,11 @@ void DesignPanel::load_feature_into_dialog(const CadFeature& f) m_cs_hz->SetValue(f.coordsys_x_hint.z()); m_coordsys_pick = CoordSysPick::None; refresh_coordsys_labels(); + refresh_cs_body_choice(); + if (m_cs_body && f.coordsys_body >= 0) { + m_cs_body->SetSelection(f.coordsys_body + 1); + if (m_viewport) m_viewport->set_xray_focus(f.coordsys_body); + } break; case CadFeatureType::Boolean: // List the bodies available to the boolean (as-of its timeline slot), so the consumed @@ -9142,7 +9174,12 @@ void DesignPanel::open_tool(Tool t) // Fillet/Chamfer/Draft no longer fade the body see-through; instead, once a valid target // is picked, refresh_preview hides the base bodies entirely (preview-only). Keep it opaque // here so the body is fully visible for picking the edge/face. - if (m_viewport) { m_viewport->set_body_translucent(false); m_viewport->set_body_hidden(false); } + // Body focus follows the CoordSys card: entering any other tool drops it. Read it back + // from the combo rather than clearing outright — editing a CoordSys feature loads the + // card (and its body) BEFORE open_tool runs, and a blind clear would strand the viewport + // showing "Body N" while picking stayed unrestricted. + if (m_viewport) { m_viewport->set_body_translucent(false); m_viewport->set_body_hidden(false); + m_viewport->set_xray_focus(t == Tool::CoordSys && m_cs_body ? m_cs_body->GetSelection() - 1 : -1); } wxSizer* s = m_cards->GetSizer(); s->Show(m_box_sketch, t == Tool::Sketch, true); s->Show(m_box_extrude, t == Tool::Extrude, true); @@ -9405,7 +9442,7 @@ void DesignPanel::close_tool() { m_active = Tool::None; set_active_tool_btn(nullptr); // clear the active-tool teal highlight - if (m_viewport) { m_viewport->set_body_translucent(false); m_viewport->set_body_hidden(false); } // restore the opaque solid + if (m_viewport) { m_viewport->set_body_translucent(false); m_viewport->set_body_hidden(false); m_viewport->set_xray_focus(-1); } // restore the opaque solid wxSizer* s = m_cards->GetSizer(); s->Show(m_box_sketch, false, true); s->Show(m_box_extrude, false, true); diff --git a/src/slic3r/GUI/DesignPanel.hpp b/src/slic3r/GUI/DesignPanel.hpp index 2f9e3f52ba..f2815ae166 100644 --- a/src/slic3r/GUI/DesignPanel.hpp +++ b/src/slic3r/GUI/DesignPanel.hpp @@ -112,6 +112,7 @@ private: void arm_coordsys_pick(CoordSysPick target); void apply_coordsys_refs(CadFeature& f) const; void refresh_coordsys_labels(); + void refresh_cs_body_choice(); // fill the CoordSys body chooser from current document void reset_coordsys_refs(); void on_add_surface_extrude(); void on_add_surface_revolve(); @@ -721,6 +722,7 @@ private: // CoordSys controls (datum coordinate system: point + orthonormal frame). ComboBox* m_coordsys_type{nullptr}; // CoordSysType: PointWorld/FaceAndDirection + ComboBox* m_cs_body{nullptr}; // body-focus chooser: restrict picking to one body wxSpinCtrlDouble* m_cs_x{nullptr}; wxSpinCtrlDouble* m_cs_y{nullptr}; wxSpinCtrlDouble* m_cs_z{nullptr}; wxButton* m_cs_pick_face{nullptr}; wxStaticText* m_cs_face_lbl{nullptr}; wxButton* m_cs_pick_edge{nullptr}; wxStaticText* m_cs_edge_lbl{nullptr}; diff --git a/src/slic3r/GUI/DesignSketchTool.cpp b/src/slic3r/GUI/DesignSketchTool.cpp index d9b34aad6a..836ff1b28c 100644 --- a/src/slic3r/GUI/DesignSketchTool.cpp +++ b/src/slic3r/GUI/DesignSketchTool.cpp @@ -2847,6 +2847,7 @@ Vec3d DesignSketchTool::body_xform_pt(int body, const Vec3d& p) const bool DesignSketchTool::body_pickable(int b) const { if (b < 0) return false; + if (m_pick_only_body >= 0 && b != m_pick_only_body) return false; // body-focus mode if (m_solid_visible == nullptr || b >= int(m_solid_visible->size())) return true; return (*m_solid_visible)[b]; } diff --git a/src/slic3r/GUI/DesignSketchTool.hpp b/src/slic3r/GUI/DesignSketchTool.hpp index 191f108486..6f0af7d9c7 100644 --- a/src/slic3r/GUI/DesignSketchTool.hpp +++ b/src/slic3r/GUI/DesignSketchTool.hpp @@ -141,6 +141,10 @@ public: const std::vector* tri_face, const std::vector* tri_body, const std::vector* visible = nullptr, const std::vector* xform = nullptr); + // Body-focus picking: >=0 restricts every pick to that one body, so a face behind + // another solid is reachable without hiding anything. -1 = no restriction. + // Survives set_solid_pick() — it is owned by the panel, not by the mesh feed. + void set_pick_only_body(int b) { m_pick_only_body = b; } void clear_solid_selection(); // Select a whole body by index (from the Parts list) — Whole-level highlight, no face/edge. // body < 0 or out of range clears the selection. @@ -941,6 +945,7 @@ private: const std::vector* m_solid_tri_face{nullptr}; const std::vector* m_solid_tri_body{nullptr}; const std::vector* m_solid_visible{nullptr}; // per-body visibility; hidden bodies aren't pickable + int m_pick_only_body{-1}; // >=0: only this body catches clicks (body-focus x-ray for CoordSys picking) const std::vector* m_solid_xform{nullptr}; // per-body display transform (for edge sampling) Vec3d body_xform_pt(int body, const Vec3d& p) const; // map an OCCT-shape point through the body xform bool body_pickable(int b) const; // false when the body is explicitly hidden