Magnum::Ui::GenericDataAnimator class new in Git master

Generic animator with animations attached to layer data.

Each animation is a function that gets called with an associated node handle and an animation factor in the $ [0, 1] $ range. The function can then call arbitrary data-related setters on the UI instance, on layers or elsewhere. Use GenericNodeAnimator for animations associated with just nodes, GenericAnimator is then for animations not tied to either.

Setting up an animator instance

The animator doesn't have any shared state or configuration, so it's just about constructing it from a fresh AbstractUserInterface::createAnimator() handle and passing it to setGenericAnimatorInstance(). After that, use setLayer() to register the animator with a concrete layer instance. Then, assuming AbstractUserInterface::advanceAnimations() is called in an appropriate place, the animator is ready to use.

Ui::AbstractLayer& layer = ;

Ui::GenericDataAnimator& animator = ui.setGenericAnimatorInstance(
    Containers::pointer<Ui::GenericDataAnimator>(ui.createAnimator()));
animator.setLayer(layer);

Unlike builtin layers or layouters, the default UserInterface implementation doesn't implicitly provide a GenericDataAnimator instance.

Creating animations

An animation is created by calling create() with an appropriate function taking the data handle and interpolation factor as arguments, an easing function from Animation::Easing or a custom one, time at which it's meant to start, its duration and the DataHandle it's attached to. For example, animating a progress bar change, where the value is visualized using custom BaseLayer padding on the left side:

Ui::BaseLayer& baseLayer = ;
Ui::DataHandle progressbar = ;

Float from = ;
Float to = ;
animator.create([&baseLayer, from, to](Ui::DataHandle progressbar, Float factor) {
    baseLayer.setPadding(progressbar, {Math::lerp(from, to, factor), 0.0f, 0.0f, 0.0f});
}, Animation::Easing::cubicIn, now, 0.5_sec, progressbar);

If the function performs easing on its own, pass Animation::Easing::linear as the easing function to have the animation factor passed unchanged. There's also an overload taking an extra GenericAnimationStates parameter to perform an action exactly once at animation start and stop. For example, assuming a custom style, setting a different one for the active and completion state:

animator.create([&baseLayer, from, to](Ui::DataHandle progressbar, Float factor,
                                       Ui::GenericAnimationStates state) {
    if(state & Ui::GenericAnimationState::Started)
        baseLayer.setStyle(progressbar, Style::ProgressBarActive);
    baseLayer.setPadding(progressbar, {Math::lerp(from, to, factor), 0.0f, 0.0f, 0.0f});
    if(state & Ui::GenericAnimationState::Stopped)
        baseLayer.setStyle(progressbar, Style::ProgressBarComplete);
}, Animation::Easing::cubicIn, now, 0.5_sec, progressbar);

The animation function is free to do anything except for touching state related to the animations or associated data or nodes, such as playing or stopping the animations, or creating, removing animations, data or nodes. This isn't checked or enforced in any way, but the behavior of doing so is undefined.

Calling a function once at specified time

The callOnce() function is a special case of create() that causes given function to be called exactly once at specified time, which is useful for triggering delayed operations. Internally this is an animation with a zero duration, so you can pause or restart it like any other animation. For example, updating a label after a ten-second timeout:

Ui::TextLayer& textLayer = ;
Ui::DataHandle label = ;

animator.callOnce([&textLayer](Ui::DataHandle label) {
    textLayer.setText(label, "Timed out.", {});
}, now + 10.0_sec, label);

Animation lifetime and data attachment

As with all other animations, they're implicitly removed once they're played. Pass AnimationFlag::KeepOncePlayed to create() or addFlags() to disable this behavior.

As the animations are associated with data they animate, when the data the animation is attached to, or the node the data is attached to, is removed, the animation gets removed as well. If you want to preserve the animation when the data is removed, call attach(AnimationHandle, DataHandle) with DataHandle::Null to detach it from the data before removing. After that, or if you call create() with DataHandle::Null in the first place, the animation will still play, but the animation function will get a null handle.

Base classes

class AbstractGenericAnimator new in Git master
Base for generic animators.

Constructors, destructors, conversion operators

GenericDataAnimator(AnimatorHandle handle) explicit
Constructor.
GenericDataAnimator(const GenericDataAnimator&) deleted
Copying is not allowed.
GenericDataAnimator(GenericDataAnimator&&) noexcept
Move constructor.

Public functions

auto operator=(const GenericDataAnimator&) -> GenericDataAnimator& deleted
Copying is not allowed.
auto operator=(GenericDataAnimator&&) -> GenericDataAnimator& noexcept
Move assignment.
void setLayer(const AbstractLayer& layer)
Set a layer associated with this animator.
auto usedAllocatedAnimationCount() const -> UnsignedInt
Count of allocated animation functions.
auto create(Containers::Function<void(DataHandle data, Float factor)>&& animation, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, DataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {}) -> AnimationHandle
Create an animation.
auto create(Containers::Function<void(DataHandle data, Float factor, GenericAnimationStates state)>&& animation, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, DataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {}) -> AnimationHandle
Create an animation with an extra state input.
auto create(Containers::Function<void(DataHandle data, Float factor)>&& animator, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, LayerDataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {}) -> AnimationHandle
Create an animation assuming the data it's attached to belongs to the layer the animator is registered with.
auto create(Containers::Function<void(DataHandle data, Float factor, GenericAnimationStates state)>&& animator, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, LayerDataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {}) -> AnimationHandle
Create an animation assuming the data it's attached to belongs to the layer the animator is registered with, with an extra state input.
auto callOnce(Containers::Function<void(DataHandle data)>&& callback, Nanoseconds at, DataHandle data, AnimationFlags flags = {}) -> AnimationHandle
Call a function once at specified time.
auto callOnce(Containers::Function<void(DataHandle data)>&& callback, Nanoseconds at, LayerDataHandle data, AnimationFlags flags = {}) -> AnimationHandle
Call a function once at specified time assuming the data it's attached to belongs to the layer the animator is registered with.
void remove(AnimationHandle handle)
Remove an animation.
void remove(AnimatorDataHandle handle)
Remove an animation assuming it belongs to this animator.
auto easing(AnimationHandle handle) -> auto
Animation easing function.
auto easing(AnimatorDataHandle handle) -> auto
Animation easing function assuming it belongs to this animator.

Function documentation

Magnum::Ui::GenericDataAnimator::GenericDataAnimator(AnimatorHandle handle) explicit

Constructor.

Parameters
handle Handle returned by AbstractUserInterface::createAnimator()

Magnum::Ui::GenericDataAnimator::GenericDataAnimator(GenericDataAnimator&&) noexcept

Move constructor.

Performs a destructive move, i.e. the original object isn't usable afterwards anymore.

void Magnum::Ui::GenericDataAnimator::setLayer(const AbstractLayer& layer)

Set a layer associated with this animator.

Expects that this function hasn't been called yet. The associated layer handle is subsequently available in layer() const.

UnsignedInt Magnum::Ui::GenericDataAnimator::usedAllocatedAnimationCount() const

Count of allocated animation functions.

Always at most usedCount(). Counts all animation functions that capture non-trivially-destructible state or state that's too large to be stored in-place. The operation is done with a $ \mathcal{O}(n) $ complexity where $ n $ is capacity().

AnimationHandle Magnum::Ui::GenericDataAnimator::create(Containers::Function<void(DataHandle data, Float factor)>&& animation, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, DataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {})

Create an animation.

Parameters
animation Animation function
easing Easing function between 0.0f and 1.0f, applied to the factor passed to animation. Pick one from Animation::Easing or supply a custom one.
start Time at which the animation starts. Use Nanoseconds::max() for creating a stopped animation.
duration Duration of a single play of the animation
data Data the animation is attached to. Use DataHandle::Null to create an animation that isn't attached to any data.
repeatCount Repeat count. Use 0 for an indefinitely repeating animation.
flags Flags

Expects that setLayer() has been already called and that both animation and easing are not nullptr. Delegates to AbstractAnimator::create(Nanoseconds, Nanoseconds, DataHandle, UnsignedInt, AnimationFlags), see its documentation for more information.

Unless data is DataHandle::Null or the animation is subsequently detached from the data, the layer portion of the DataHandle passed to animator is matching the layer handle passed to setLayer().

Assuming the easing function correctly maps 0.0f and 1.0f to themselves, the animation function is guaranteed to be called with factor being exactly 1.0f once the animation is stopped. Other than that, it may be an arbitrary value based on how the easing function is implemented. You can also use the GenericAnimationStates overload below to hook directly to the start and stop.

AnimationHandle Magnum::Ui::GenericDataAnimator::create(Containers::Function<void(DataHandle data, Float factor, GenericAnimationStates state)>&& animation, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, DataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {})

Create an animation with an extra state input.

Like create(Containers::Function<void(DataHandle, Float)>&&, Float(*)(Float), Nanoseconds, Nanoseconds, DataHandle, UnsignedInt, AnimationFlags) but with an extra state argument that you can use to perform an operation exactly once at animation start or stop. See documentation of particular GenericAnimationState values for detailed behavior description.

AnimationHandle Magnum::Ui::GenericDataAnimator::create(Containers::Function<void(DataHandle data, Float factor)>&& animator, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, LayerDataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {})

Create an animation assuming the data it's attached to belongs to the layer the animator is registered with.

Compared to create(Containers::Function<void(DataHandle, Float)>&&, Float(*)(Float), Nanoseconds, Nanoseconds, DataHandle, UnsignedInt, AnimationFlags) delegates to AbstractAnimator::create(Nanoseconds, Nanoseconds, LayerDataHandle, UnsignedInt, AnimationFlags) instead.

Unless data is LayerDataHandle::Null or the animation is subsequently detached from the data, the layer portion of the DataHandle passed to animator is matching the layer handle passed to setLayer().

AnimationHandle Magnum::Ui::GenericDataAnimator::create(Containers::Function<void(DataHandle data, Float factor, GenericAnimationStates state)>&& animator, Float(*)(Float) easing, Nanoseconds start, Nanoseconds duration, LayerDataHandle data, UnsignedInt repeatCount = 1, AnimationFlags flags = {})

Create an animation assuming the data it's attached to belongs to the layer the animator is registered with, with an extra state input.

Like create(Containers::Function<void(DataHandle, Float)>&&, Float(*)(Float), Nanoseconds, Nanoseconds, LayerDataHandle, UnsignedInt, AnimationFlags) but with an extra state argument that you can use to perform an operation exactly once at animation start or stop. See documentation of particular GenericAnimationState values for detailed behavior description.

AnimationHandle Magnum::Ui::GenericDataAnimator::callOnce(Containers::Function<void(DataHandle data)>&& callback, Nanoseconds at, DataHandle data, AnimationFlags flags = {})

Call a function once at specified time.

Parameters
callback Function to call
at Time at which the callback gets called. Use Nanoseconds::max() for creating a stopped animation.
data Data the animation is attached to. Use DataHandle::Null to create an animation that isn't attached to any data.
flags Flags

Expects that callback is not nullptr. Delegates to AbstractAnimator::create(Nanoseconds, Nanoseconds, DataHandle, UnsignedInt, AnimationFlags) with duration set to 0_nsec, see its documentation for more information.

AnimationHandle Magnum::Ui::GenericDataAnimator::callOnce(Containers::Function<void(DataHandle data)>&& callback, Nanoseconds at, LayerDataHandle data, AnimationFlags flags = {})

Call a function once at specified time assuming the data it's attached to belongs to the layer the animator is registered with.

Compared to callOnce(Containers::Function<void(DataHandle data)>&&, Nanoseconds, DataHandle, AnimationFlags) delegates to AbstractAnimator::create(Nanoseconds, Nanoseconds, LayerDataHandle, UnsignedInt, AnimationFlags) instead.

Unless data is LayerDataHandle::Null or the animation is subsequently detached from the data, the layer portion of the DataHandle passed to animator is matching the layer handle passed to setLayer().

void Magnum::Ui::GenericDataAnimator::remove(AnimationHandle handle)

Remove an animation.

Expects that handle is valid. Delegates to AbstractAnimator::remove(AnimationHandle), see its documentation for more information.

void Magnum::Ui::GenericDataAnimator::remove(AnimatorDataHandle handle)

Remove an animation assuming it belongs to this animator.

Compared to remove(AnimationHandle) delegates to AbstractAnimator::remove(AnimatorDataHandle) instead.

auto Magnum::Ui::GenericDataAnimator::easing(AnimationHandle handle)

Animation easing function.

Expects that handle is valid. The returned pointer is never nullptr for animations created with create(), and always nullptr for animations created with callOnce().

auto Magnum::Ui::GenericDataAnimator::easing(AnimatorDataHandle handle)

Animation easing function assuming it belongs to this animator.

Like easing(AnimationHandle) const but without checking that handle indeed belongs to this animator. See its documentation for more information.