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.
that finishes on its own
The hover delay only finished while the mouse was moving: a pointer resting
on a control produces no events, so nothing redrew the canvas and the wait
never reached its end - the tooltip appeared on the next pixel of movement
instead. It asked for its frames with schedule_extra_frame(), which only
arranges a timer whose event an idle event is assumed to follow, and
on_idle renders nothing unless the canvas was already dirty when it ran.
The wait and the animations now both use request_extra_frame(), which ends
on_idle with evt.RequestMore() and so obliges wx to deliver the next idle;
it is what 3DBed's fade uses. Asking for frames as fast as they come is
safe now that which frame is drawn comes from the clock rather than from
the frame count - a redraw that arrives early draws the same frame again.
Nothing explains a control while the control is being used, so no tooltip
appears while a slider is being dragged, a value typed into one, a combo
open or a layer card dragged. The pointer sits on the very thing being
edited, so a tooltip there covered the model exactly while the user was
watching it change. The full wait comes back afterwards rather than the
short one: having just let go of a slider is not a reason to be shown a
picture of it.
AnimatedTexture::texture_id() loses its time-to-next-frame out-parameter,
which nothing asks for any more.
The animations crawled when left alone and raced while the mouse moved.
They were timed by ImGui::GetTime(), and nothing in OrcaSlicer ever sets
io.DeltaTime, so it keeps imgui's default of 1/60 per frame: imgui's clock
counts frames, not seconds. On a canvas that renders only when something
asks it to, that is not a clock. Playback now reads a steady_clock, so a
frame is due when it is due whatever the canvas is doing.
An animation also restarts when its tooltip opens again, not only when a
different one opens: a gap in the frames it was drawn on is what that
looks like from here.
Tooltips now wait for the pointer to rest on a control for 0.45 s. The
panel is dense and a tooltip lands on the model beside it, so with no wait
a sweep from the top of the panel down to Bake flashed a dozen large panels
over the scene. After one has just been up the wait drops to 0.1 s for 0.7
s, so reading several settings in a row stays quick - but not to zero, or
that same sweep would flash again once one tooltip had been seen. A pointer
resting on a control produces no events, so the wait asks for the frame it
will appear on itself.
rest of the panel
The animations advanced one frame per mouse movement and stood still
whenever the mouse did. schedule_extra_frame() only guarantees an idle
event at the moment the next frame is due; GLCanvas3D::on_idle() returns
without rendering anything unless something marked the canvas dirty by
then, and nothing had. set_dirty() on the gizmo is what on_idle reads,
through GLGizmoBase::update_items_state(), to find out there are frames
still to draw.
Thirty-odd more pictures, covering the paint tools, brush size, the
connected-area fill, the five views, the five projections, subdivision,
feature-adaptive refinement, remeshing, hard edges, slivers, geometry
smoothing, filament mixing and denoise.
The generator grew three more drawing languages beside the shaded relief,
each picked by what the setting is rather than by taste: a flat mesh of
triangles where the subject is the mesh or a tool, a section where the
subject is where the surface sits relative to where it was, and a flat ramp
of greys where the subject is which filament a spot ends up as. Lighting a
colour illustration or looking down on a vertical change would both add a
second thing moving between two pictures meant to differ in one.
Mapping is one ball with the checker laid on it five ways, which is the
whole of what choosing a projection does - except Unwrap, which is not a
projection onto the model and so is drawn as the flat layout it produces.
Ten more tooltips get a picture: Depth, Tile size, Repeat/Mirror, Invert,
Smoothing, Edge fade and Blend as stills, Depth, Rotation and Midlevel as
animations. All drawn by scripts/gen_texture_displacement_tips.py from the
same arithmetic the feature uses, one motif throughout, so that whatever
differs between two of them is the setting and nothing else.
Midlevel is drawn in section instead of as a relief. Shading reads slopes,
so a height field moved up or down as a whole shades exactly as it did
before - and where the relief sits relative to the surface is the entire
meaning of that setting. From the side, against the bare surface, it is the
one thing visible.
A single picture is now capped at 10 em tall and centred in its column,
rather than drawn at the tooltip's full width, where a square one came out
as tall as the text beside it was long.
The panel is pinned to the right edge of the canvas, so a tooltip left to
follow the mouse covers the very control it explains. panel_tooltip()
places every tooltip in the gizmo to the left of the panel instead - or of
the texture picker, while a tooltip is coming from inside that popup - the
same placement the picker itself already uses.
A tooltip can now carry pictures under its text: stills, or GIFs that loop
while it is open. Several settings in this panel describe a shape rather
than a number, and a sentence about a shape is read twice and understood
once. Files live in resources/images/texture_displacement and are named by
a tooltip; one that is missing is skipped, so a tooltip without its art yet
is exactly the text tooltip it was before.
AnimatedTexture decodes a file once and uploads a GL texture per frame -
wxImage for stills, wxGIFDecoder for GIFs, whose frames are composited here
with the disposal method each one asks for. An animation restarts when its
tooltip opens and asks the canvas for a redraw timed to its next frame.
Tile and Rotation are wired up as the first two; scripts/
gen_texture_displacement_tips.py draws their relief from the same
arithmetic the feature uses. docs/HLSD/tooltip-illustrations.md covers the
rest.