Give the Design tab its own camera view

The Camera is Plater-owned and shared by every canvas, and Design sits
outside the panel switch that saves and restores it for Prepare,
Preview and Assemble — so orbiting in Design moved what the editor
tabs showed, and Design lost its own view on every switch. Trade the
live camera for a parked one on the way in and back on the way out, so
Design keeps its view the way Assemble already does.
This commit is contained in:
SoftFever
2026-08-28 01:05:01 +08:00
parent ba1df32e88
commit 806db473de
3 changed files with 49 additions and 2 deletions
+27
View File
@@ -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)
+14
View File
@@ -9,6 +9,7 @@
#include <string>
#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<void(const SketchProfile&, const SketchPlane&)> 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
+8 -2
View File
@@ -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