From 6d9368276c6732a3771ed155d54f140283da449d Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Tue, 14 Jul 2026 23:26:23 +0200 Subject: [PATCH] Fix Design tab not painting on hardware GL after a page switch request_repaint() only invalidates the canvas (Refresh()) on the hardware-GL path and relies on a wxEVT_PAINT to follow. When the notebook re-shows the Design page, that invalidation is issued mid-show and dropped: no paint event arrives, the canvas never renders, and the pane stays blank until another tab switch forces an expose. Software GL renders directly, so it never showed there. force_repaint() defers past the show, then Refresh() + Update() for a synchronous paint. Called from on_tab_shown(). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q --- src/slic3r/GUI/DesignCanvas.cpp | 14 ++++++++++++++ src/slic3r/GUI/DesignCanvas.hpp | 5 +++++ src/slic3r/GUI/DesignPanel.cpp | 1 + 3 files changed, 20 insertions(+) diff --git a/src/slic3r/GUI/DesignCanvas.cpp b/src/slic3r/GUI/DesignCanvas.cpp index 7c2e02bc4d..c995c3cc04 100644 --- a/src/slic3r/GUI/DesignCanvas.cpp +++ b/src/slic3r/GUI/DesignCanvas.cpp @@ -193,6 +193,20 @@ void DesignCanvas::request_repaint() } } +void DesignCanvas::force_repaint() +{ + if (m_canvas == nullptr || m_canvas_widget == nullptr) + return; + + CallAfter([this]() { + if (m_canvas == nullptr || m_canvas_widget == nullptr) + return; + m_canvas->set_as_dirty(); + m_canvas_widget->Refresh(); + m_canvas_widget->Update(); // synchronous: an expose may never come after a page show + }); +} + void DesignCanvas::reload(bool keep_view) { m_canvas->reset_volumes(); diff --git a/src/slic3r/GUI/DesignCanvas.hpp b/src/slic3r/GUI/DesignCanvas.hpp index f01726fb92..27c172d723 100644 --- a/src/slic3r/GUI/DesignCanvas.hpp +++ b/src/slic3r/GUI/DesignCanvas.hpp @@ -245,6 +245,11 @@ public: // scheduled Refresh() is frequently dropped there. Backend cached on first use. // Public: DesignPanel calls it after a tree edit to force a frame on software GL. void request_repaint(); + // Repaint synchronously, once the pending show/resize has settled. Needed when the + // notebook re-shows the Design page: an invalidation issued while the page is still + // being shown is dropped on hardware GL and no wxEVT_PAINT ever follows, leaving the + // canvas blank until another tab switch forces an expose. + void force_repaint(); private: void reload(bool keep_view); diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index b874aa80b6..fcabd05561 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -3196,6 +3196,7 @@ void DesignPanel::on_tab_shown() } } update_reference_planes(); // entering the Design tab: show the XY/XZ/YZ planes if no object yet + if (m_viewport) m_viewport->force_repaint(); // the page was just re-shown: paint it for real } void DesignPanel::load_recipe(const std::string& blob)