gfx/animated_position.h
AnimatedPosition: a position that a finger throws, and that carries on moving after it lets go -- and ViewportDragScroller, which uses two of them to scroll a Viewport by dragging its content.
#include <sonore/gfx/animated_position.h>- 4types
- Guides: The native editor
On this page
Design notes
Why the application has to integrate a flick
A wheel or a precision trackpad arrives already smoothed: the operating system turns a flick into a decelerating stream of scroll events, and the Viewport only has to follow them. A finger on a touch screen, or a pen, arrives as a DRAG -- positions, and then a release. Nothing after the release says the list should keep moving; the momentum has to be worked out from how fast the finger was going when it left, and then integrated, frame by frame, against friction. That is this.
Behaviours
The reference's two, with its defaults:
ContinuousWithMomentum coasts at the release velocity, losing a fraction
of it to friction every 60th of a second, and
stops once slower than a minimum. The friction is
integrated exactly over the elapsed time rather
than applied per call, so a flick goes the same
distance at 30, 60 or 144 Hz.
SnapToPageBoundaries settles on the nearest whole number -- a page --
or the next one in the direction of a fast flick.
A behaviour is any type with releasedWithVelocity(position, velocity), getNextPosition(old, elapsed) and isStopped(position): write a third for a detent, a rubber band, a carousel.
The clock
As everywhere in this SDK, time is an argument or an injectable function, so the decay and the snap are exact tests. ViewportDragScroller ticks itself from a VBlankAttachment while it coasts -- once per display refresh, which is what makes the motion smooth -- unless told to leave the ticking to its owner.
Types 4
Keeps moving after release, slowing under friction.
Settles on a whole number: page boundaries, when one unit is one page.
template <typename Behaviour> class AnimatedPosition
A one-dimensional position that can be dragged and then let go of.
beginDrag / drag(deltaFromStart) / endDrag follow a gesture, measuring its velocity as it goes; on endDrag the behaviour takes over and update(now) moves the position until the behaviour says it has stopped.
class ViewportDragScroller : private MouseListener
Scroll a Viewport by dragging its content, with momentum -- the reference's Viewport::setScrollOnDragMode, as an object attached to the viewport.
Listens to everything inside the viewed component, so a drag that starts on a row, a label or a button still scrolls. It does not start until the pointer has moved a few pixels, so a tap is still a tap. Drags on the viewport's own scroll bars, and on any component given to setIgnoresDragsFrom, are left alone -- a slider in a scrolling list must move its value, not the list.