ImFusion SDK 4.3
Animations

Animating objects within the ImFusion SDK. More...

+ Collaboration diagram for Animations:

Detailed Description

Animating objects within the ImFusion SDK.

Overview

Any object or parameter within the ImFusionLib can be animated in order to have a smooth transition/appearance to the user. Conceptually, an animation is a function that is called repeatedly for a specified time frame with a progress indicator t interpolated between 0.0 and 1.0 according to the duration and time passed since start. Practically, they are usually used to draw the user's attention to a change and/or to make your program feel more natural. This part of the SDK is implemented in the ImFusion::Animations namespace.

Animations

The Animation class represents a single animation and has a duration, which is the time it takes for the animation to transition from its initial state to its final state. The optimal duration for a UI transition animation is between 200 and 500 milliseconds. An animation of 100 ms seems instantaneous to the user, while an animation exceeding 1 second is disruptive to the user's flow of thought. See here for more information.

The rate of change (acceleration) of the animation's transition is determined by its EasingFunction. Our framework comes with a set of predefined easing functions. However, you can also define custom ones in case you need full flexibility. See here for more details.

The following example shows how you can use an Animation in your application.

#include <ImFusion/GUI/Animations.h>
using namespace std::chrono_literals;
Car car{...};
vec2 start = {0, 0};
vec2 finish = {42, 0};
auto drive = std::make_unique<Animations::Animation>([=, pCar = &car](double t) {
vec2 pos = (1.0 - t)*start + t*finish;
pCar->setPosition(pos);
// finalizing action
if (t == 1.0)
pCar->openDriversDoor();
});
drive->setDuration(800ms); // optional, the default duration is 500 ms
drive->setEasingCurve(Animations::EasingCurve::InOutCubic); // optional, the default easing function is Linear
Animations::runAnimation(std::move(drive));
void runAnimation(std::shared_ptr< Animation > animation, const std::optional< UniqueId > &uniqueId=std::nullopt)
Run the given animation on the globally installed backend.
IMFUSION_GL_API void finish()
Calls glFinish() to block until all OpenGL execution is complete.
T make_unique(T... args)
@ InOutCubic
Cubic function accelerating from zero velocity until halfway, then decelerating to zero velocity.
Definition Animations.h:29

There are a few things to notice in the code snippet above. Most importantly, the object being animated, in this case car, must stay alive for at least the duration of the animation. You will notice the lambda function passed as the argument to Animation 's constructor captures the surrounding variables by value. That is, the lambda makes a copy of the pointer to car and the start and finish positions.

Alternatively, if you don't want to manually take care of the lifetime management, you can connect to the Animation::signalUpdated signal instead of passing a callable directly to the Animation constructor. Using the signal interface enables you to utilize the lifetime management implemented with SignalReceiver. See Signals and Slots for more details.

Both the update function passed to the constructor and the signalUpdated signal are called repeatedly with increasing values from 0.0 to 1.0. In case you need a finalizer of the animation, you can implement that in the update function for the case with t = 1.0. The animation framwork will ensure that all animations will be updated with t = 1.0 as very last step unless canceled.

Animation Backend

Animations are managed by the AnimationBackend interface, which takes care of dispatching and calling the update() function at a regular time interval with the correct progress value t. Since this functionality usually requires some form of event loop it is encapsulated in concrete derived classes of this interface. This enables you to choose an adequate backend for your application environment.

Our SDK currently comes with two available backends: AnimationBackendDummy will not execute any animation but only call its update() function exactly once with t = 1.0. AnimationBackendQt will use the Qt event loop for dispatching the animation updates and is the default for GUI applications based on MainWindowBase.

For convenience, our framework comes with a global backend that you can install through Animations::setBackend() if needed. All free functions in the Animations namespace (such as Animations::runAnimation() or Animations::runLoopedAnimation()) will work on this global backend accessible from everywhere.

The animation backend can be disabled on demand (Animations::enableAnimations(), AnimationBackendBase::setEnabled()). If new animations are run while the backend is disabled the animation will not be dispatched but instead its update functionwill be called once with t = 1.0 so that the animation reaches its final state immediately. It is often convenient to temporarily disable animations and return the enabled status to whatever it was before. This can be achieved with the ScopedEnabler, for example:

void resetWidgetImmediately()
{
Animations::ScopedEnabler guard{false}
m_widget->reset();
}

Furthermore, you can configure a animation speed multiplier for the backend that enables you to change the speed of all animations consistently.

Unique IDs

Normally, when launching multiple animations all of them will run independently until they are finished. However, sometimes you may wish to abort an animation currently in flight when adding a new animation of "the same kind" so that they don't interfere with each other.

You can use the Animations::UniqueId interface to help you in this situation: When you pass an instance of this type when running an animation the backend will cancel any running animations with the same ID before starting the new one. A unique ID can be described by the address of an object (usually you would pass the this pointer of the caller if it was allocated on the heap), by a string identifier of sufficient uniqueness, or the combination of both.

// run an animation while canceling any running animation with the same UniqueId (this pointer)
[this](double t) { ... },
500ms,
this // the `this` pointer is implicitly convertible to a UniqueId
)
@ OutCubic
Cubic function decelerating to zero velocity.
Definition Animations.h:28
Note
Make sure to use a sufficiently unique ID to avoid conflicts with other users of this interface.

A note about threads

Due to the asynchronous nature of animations, the main API of the Animations framework is thread-safe. This means that you can access an Animation object as well as the (global) backend from any thread in a safe fashion. However, this does obviously not include the callback function itself. Thus, it is your responsibility as the creator of an animation to ensure that whatever resources get updated while the Animation runs are not also being accessed or modifed by other threads.

Note
The base interface does not specify on which thread the animation callback is called. This is subject to the concrete implementation of the backend. The default Qt backend will use the thread on which it was orginally instantiated, usually the main Qt GUI thread.

Classes

class  AnimationBackendQt
 Concrete implementation of AnimationBackendBase using the Qt event loop for dispatching the animation updates. More...
 
struct  UniqueId
 Helper struct to uniquely describe a type of annotation. More...
 
class  ScopedEnabler
 A scope guard to set the globally available enabled property for animations. More...
 
class  Animation
 Helper class to define an animation, that is an interpolated transition between two states. More...
 
class  AnimationBackendBase
 Base interface for managing and dispatching animations. More...
 
class  AnimationBackendDummy
 Dummy implementation of the AnimationBackendBase interface that will not execute any animation but only call its update() function exactly once with t=1.0. More...
 

Functions

std::unique_ptr< AnimationBackendBasesetBackend (std::unique_ptr< AnimationBackendBase > backend)
 Install a global animation backend that is used by the set of free functions in this namespace.
 
void runAnimation (std::shared_ptr< Animation > animation, const std::optional< UniqueId > &uniqueId=std::nullopt)
 Run the given animation on the globally installed backend.
 
std::shared_ptr< AnimationrunAnimation (std::function< void(double t)> &&updateFunc, std::chrono::milliseconds duration=std::chrono::milliseconds(500), EasingCurve easingCurve=EasingCurve::InOutCubic, const std::optional< UniqueId > &uniqueId=std::nullopt)
 Create and run a one-shot animation with the given configuration on the globally installed backend.
 
std::shared_ptr< AnimationrunLoopedAnimation (std::function< void(double)> &&updateFunc, std::chrono::milliseconds duration=std::chrono::milliseconds(500), EasingCurve easingCurve=EasingCurve::InOutCubic, const std::optional< UniqueId > &uniqueId=std::nullopt)
 Create and run a looped animation with the given configuration on the globally installed backend.
 
bool animationsEnabled ()
 Check whether the animations are globally enabled within the application.
 
void enableAnimations (bool enabled)
 Globally enable or disable animations within the application.
 
double animationDurationFactor ()
 Returns the duration multiplier for run animations; enables you to change the speed of all animations consistently.
 
void setAnimationDurationFactor (double value)
 Sets the duration multiplier for run animations, must be >= 0; enables you to change the speed of all animations consistently.
 
void cancelAnimation (const UniqueId &id)
 Cancels the animation with the given id.
 
void cancelAllAnimations ()
 Cancels all animations currently in flight.
 

Function Documentation

◆ setBackend()

#include <ImFusion/GUI/Animations.h>

Install a global animation backend that is used by the set of free functions in this namespace.

The provided backend must not be null. Returns the previously installed animation backend.

◆ runAnimation() [1/2]

void runAnimation ( std::shared_ptr< Animation > animation,
const std::optional< UniqueId > & uniqueId = std::nullopt )

#include <ImFusion/GUI/Animations.h>

Run the given animation on the globally installed backend.

Parameters
animationAnimation to execute, must not be null.
uniqueIdOptional identifier for this animation to prevent multiple concurrent animations of the same ID. If not empty, the backend will cancel any running animations with the same ID before starting the new one. Make sure to use a sufficiently unique ID to avoid conflicts with other users of this interface.
Note
If animationsEnabled() is false the animation will not be dispatched but its update function will be called once with t = 1.0 so that the animation reaches its final state immediately.

◆ runAnimation() [2/2]

std::shared_ptr< Animation > runAnimation ( std::function< void(double t)> && updateFunc,
std::chrono::milliseconds duration = std::chrono::milliseconds(500),
EasingCurve easingCurve = EasingCurve::InOutCubic,
const std::optional< UniqueId > & uniqueId = std::nullopt )

#include <ImFusion/GUI/Animations.h>

Create and run a one-shot animation with the given configuration on the globally installed backend.

The created Animation object is returned to enable you to keep track of it or cancel it from the outside.

Parameters
updateFuncCallback function that is called at regular time intervals with t having values interpolated between 0.0 and 1.0 according to the duration and time passed since start.
durationDuration of the animation, will be multiplied with the global animationSpeed().
easingCurveOptional easing curve describing the speed of the interpolation between 0.0 and 1.0.
uniqueIdOptional identifier for this animation to prevent multiple concurrent animations of the same ID. If not empty, the backend will cancel any running animations with the same ID before starting the new one. Make sure to use a sufficiently unique ID to avoid conflicts with other users of this interface.
Note
If animationsEnabled() is false the animation will not be dispatched but its update function will be called once with t = 1.0 so that the animation reaches its final state immediately.

◆ runLoopedAnimation()

std::shared_ptr< Animation > runLoopedAnimation ( std::function< void(double)> && updateFunc,
std::chrono::milliseconds duration = std::chrono::milliseconds(500),
EasingCurve easingCurve = EasingCurve::InOutCubic,
const std::optional< UniqueId > & uniqueId = std::nullopt )

#include <ImFusion/GUI/Animations.h>

Create and run a looped animation with the given configuration on the globally installed backend.

The created Animation object is returned to enable you to keep track of it or cancel it from the outside.

Parameters
updateFuncCallback function that is called at regular time intervals with t having values interpolated between 0.0 and 1.0 according to the duration and time passed since start.
durationDuration of the animation, will be multiplied with the global animationSpeed().
easingCurveOptional easing curve describing the speed of the interpolation between 0.0 and 1.0.
uniqueIdOptional identifier for this animation to prevent multiple concurrent animations of the same ID. If not empty, the backend will cancel any running animations with the same ID before starting the new one. Make sure to use a sufficiently unique ID to avoid conflicts with other users of this interface.
Note
If animationsEnabled() is false the animation will not be dispatched but its update function will be called once with t = 1.0 so that the animation reaches its final state immediately.
Search Tab / S to search, Esc to close