diff --git a/src/slic3r/GUI/CAD/DesignCanvas.cpp b/src/slic3r/GUI/CAD/DesignCanvas.cpp index b967273444..4dbff59959 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.cpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.cpp @@ -189,6 +189,15 @@ DesignCanvas::DesignCanvas(wxWindow* parent) refresh_bed(); + // The view this canvas opens on. Built lazily, on the way into the Design tab, so this + // is the view the user is looking at right now. + m_parked_camera = wxGetApp().plater()->get_camera(); + + // Before any of this class's own Binds below: wx calls dynamically bound handlers in + // reverse order of binding, and GLCanvas3D::on_mouse takes wxEVT_RIGHT_UP / ENTER_WINDOW + // without skipping them — so whatever is bound last is the only handler that sees them. + // The context menu, the focus-follows-mouse and the status-chip re-anchor all depend on + // running first, which is only true while this call stays ahead of them. m_canvas->bind_event_handlers(); // The Design GL canvas only receives key events (Esc to exit/enter Select, Ctrl+Z undo) @@ -268,6 +277,24 @@ void DesignCanvas::request_repaint() } } +void DesignCanvas::enter_viewport() +{ + if (!m_camera_swapped) swap_camera(); +} + +void DesignCanvas::leave_viewport() +{ + if (m_camera_swapped) swap_camera(); +} + +void DesignCanvas::swap_camera() +{ + Plater* plater = wxGetApp().plater(); + if (plater == nullptr) return; + std::swap(plater->get_camera(), m_parked_camera); + m_camera_swapped = !m_camera_swapped; +} + void DesignCanvas::force_repaint() { if (m_canvas == nullptr || m_canvas_widget == nullptr) diff --git a/src/slic3r/GUI/CAD/DesignCanvas.hpp b/src/slic3r/GUI/CAD/DesignCanvas.hpp index 43357dd5e6..2b4c4ff009 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.hpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.hpp @@ -9,6 +9,7 @@ #include #include "slic3r/GUI/3DBed.hpp" +#include "slic3r/GUI/Camera.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/CAD/SketchEngine.hpp" #include "slic3r/GUI/CAD/DesignSketchTool.hpp" @@ -69,6 +70,13 @@ public: void finish_sketch(); bool is_sketching() const; void refresh_bed(); // re-sync the bed to the current printer (call on tab activation) + // The Camera is Plater-owned and shared with Prepare/Preview/Assemble; GLCanvas3D has no + // per-canvas camera, so every orbit here would otherwise overwrite what the editor tabs + // show. Exactly one of the two views is live at a time, so entering and leaving are the + // same operation: trade the live camera for the parked one. That also keeps this canvas's + // own view across a tab switch. + void enter_viewport(); + void leave_viewport(); void set_show_bed(bool b); // view option: draw the printer bed + plate grid, or not void cancel_sketch(); void set_on_sketch_commit(std::function cb); @@ -324,6 +332,7 @@ public: private: void reload(bool keep_view); + void swap_camera(); // enter_viewport / leave_viewport, in the one direction they share wxGLCanvas* m_canvas_widget{nullptr}; GLCanvas3D* m_canvas{nullptr}; @@ -334,6 +343,11 @@ private: wxPoint m_ctx_press{0, 0}; // right-press origin: a right-DRAG pans, it must not offer Bed3D m_bed; + // The half of the camera swap above that is NOT on screen: the editor tabs' view while + // Design is up, this canvas's view while it is not. Seeded in the constructor so the first + // entry inherits the view the user was already looking at. + Camera m_parked_camera; + bool m_camera_swapped{false}; // guards a leave without an enter, and the reverse Model m_model; bool m_first_frame{true}; bool m_body_selected{false}; // tree selected a body feature → tint the solid diff --git a/src/slic3r/GUI/CAD/DesignPanel.cpp b/src/slic3r/GUI/CAD/DesignPanel.cpp index 619f795697..44e32c574f 100644 --- a/src/slic3r/GUI/CAD/DesignPanel.cpp +++ b/src/slic3r/GUI/CAD/DesignPanel.cpp @@ -6937,12 +6937,18 @@ wxString DesignPanel::idle_hint() const // Nothing else in the panel needs to know: the popup keeps its text and comes straight back. void DesignPanel::on_tab_hidden() { - if (m_viewport) m_viewport->show_status_hud(false); + if (m_viewport) { + m_viewport->show_status_hud(false); + m_viewport->leave_viewport(); // hand the shared camera back to the editor tabs + } } void DesignPanel::on_tab_shown() { - if (m_viewport) m_viewport->show_status_hud(true); // ...and back on the way in + if (m_viewport) { + m_viewport->show_status_hud(true); // ...and back on the way in + m_viewport->enter_viewport(); // borrow the shared camera; on_tab_hidden gives it back + } if (m_active == Tool::None && m_doc.display_mesh.its.indices.empty()) set_status(idle_hint()); // first paint: the tab has never been edited