From 4bc300933e3eac4591cd09c7370d8a7a17826b5b Mon Sep 17 00:00:00 2001 From: ExPikaPaka Date: Tue, 13 Oct 2026 14:30:53 +0200 Subject: [PATCH] Texture displacement: keep a tooltip on screen long enough to be seen A tooltip appeared only on the next pixel of mouse movement after its wait had finished. ImGui hides a window on the first frame it is submitted, to measure it before showing it, and does so every time a tooltip reappears because those windows are recycled (the Popup|Tooltip branch of Begin()). So the frame a tooltip is decided on is never the frame it is seen on, and one carrying no animation asked for nothing further - leaving it in its hidden measuring frame until some other event happened to produce the next one. Before the hover delay this never showed, because the tooltip was submitted on every mouse-move frame and the movement supplied the second. It now asks for frames until it has been drawn twice in a row. --- docs/HLSD/tooltip-illustrations.md | 5 ++++- src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp | 11 +++++++++++ src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/HLSD/tooltip-illustrations.md b/docs/HLSD/tooltip-illustrations.md index 1189c89c3f..dc52e9ac93 100644 --- a/docs/HLSD/tooltip-illustrations.md +++ b/docs/HLSD/tooltip-illustrations.md @@ -57,7 +57,10 @@ afterwards rather than the short one: having just let go of a slider is not a re picture of it. A pointer resting on a control produces no events, and the canvas only renders when something asks it -to, so the wait has to ask for its own frames, and so does an animation once one is on screen. Both use +to, so the wait has to ask for its own frames, and so does an animation once one is on screen. So does +a tooltip that has just appeared, animated or not: ImGui hides a window on the first frame it is +submitted while it measures it, and does so every time a tooltip reappears because those windows are +recycled, so the frame a tooltip is decided on is never the frame it is seen on. Both use `GLCanvas3D::request_extra_frame()`, which ends `on_idle()` with `evt.RequestMore()` and so obliges wx to deliver the next idle. `schedule_extra_frame()` is not enough on its own: it only arranges a timer whose event an idle event is assumed to follow, and on_idle renders nothing unless the canvas was diff --git a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp index 2b04e0eef7..c513077ebd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp @@ -3764,6 +3764,17 @@ void GLGizmoTextureDisplacement::panel_tooltip(const std::string &text, const st } m_tip_last_shown = now; + // ImGui hides a window on the first frame it is submitted, to measure it before showing it - and + // for a tooltip it does so every time one reappears, because the windows are recycled (see the + // Popup|Tooltip branch of Begin()). So the frame on which a tooltip is decided is never the frame + // on which it is seen, and one that then asks for nothing more stays invisible until the next pixel + // of mouse movement happens to produce another frame. Keep frames coming until it has settled. + const int shown_frame = ImGui::GetFrameCount(); + m_tip_settled = (shown_frame == m_tip_shown_frame + 1) ? m_tip_settled + 1 : 0; + m_tip_shown_frame = shown_frame; + if (m_tip_settled < 2) + m_parent.request_extra_frame(); + const ImGuiStyle &style = ImGui::GetStyle(); const float gap = m_imgui->scaled(0.5f); const float wrap = m_imgui->scaled(20.f); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp index 7762b95e3e..c99d7dcee4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp @@ -1066,6 +1066,10 @@ private: ImVec2 m_tip_item{-1.f, -1.f}; double m_tip_hover_since = 0.; double m_tip_last_shown = -1e9; + // The frame a tooltip was last drawn on, and how many it has been drawn on in a row: ImGui hides + // one on its first frame while it measures it, so it has to be kept on screen to be seen at all. + int m_tip_shown_frame = -2; + int m_tip_settled = 0; }; } // namespace Slic3r::GUI