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.
This commit is contained in:
ExPikaPaka
2026-10-13 14:30:53 +02:00
parent 5cfd91a309
commit 4bc300933e
3 changed files with 19 additions and 1 deletions
+4 -1
View File
@@ -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
@@ -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);
@@ -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