FR: ComponentAnimator lambda callbacks


#1

Right now, ComponentAnimator relies on sendChangeMessage() to notify listeners when it starts animating, and when it stops animating.

it would be pretty useful if we could attach a lambda callback for each component that is being animated.

the AnimationTask class can just have one member added and initialized in the constructor:

class ComponentAnimator::AnimationTask
{
public:
    AnimationTask (Component* c, std::function<void()> stopCallback) noexcept  : 
        component (c), 
        stopAnimationCallback( std::move(stopCallback) )
        {}
//...snip
    std::function<void()> stopAnimationCallback;

and for when it starts:

void ComponentAnimator::animateComponent (Component* const component,
                                          const Rectangle<int>& finalBounds,
                                          const float finalAlpha,
                                          const int millisecondsToSpendMoving,
                                          const bool useProxyComponent,
                                          const double startSpeed,
                                          const double endSpeed,
                                          std::function<void()> startAnimationCallback,
                                          std::function<void()> stopAnimationCallback)
{
    // the speeds must be 0 or greater!
    jassert (startSpeed >= 0 && endSpeed >= 0);

    if (component != nullptr)
    {
        auto* at = findTaskFor (component);

        if (at == nullptr)
        {
            at = new AnimationTask (component, stopAnimationCallback);
            tasks.add (at);
            sendChangeMessage();

            if( startAnimationCallback ) startAnimationCallback();
        }

        at->reset (finalBounds, finalAlpha, millisecondsToSpendMoving,
                   useProxyComponent, startSpeed, endSpeed);

        if (! isTimerRunning())
        {
            lastTime = Time::getMillisecondCounter();
            startTimerHz (50);
        }
    }
}

something like this for when it stops being animated:

void ComponentAnimator::timerCallback()
{
    auto timeNow = Time::getMillisecondCounter();

    if (lastTime == 0)
        lastTime = timeNow;

    auto elapsed = (int) (timeNow - lastTime);

    for (auto* task : Array<AnimationTask*> (tasks.begin(), tasks.size()))
    {
        if (tasks.contains (task) && ! task->useTimeslice (elapsed))
        {
            std::function<void()> callback;
            if( task->stopAnimationCallback ) callback = task->stopAnimationCallback;

            tasks.removeObject (task);          
            sendChangeMessage();
            if( callback ) callback();
        }
    }

    lastTime = timeNow;

    if (tasks.size() == 0)
        stopTimer();
}

This would be a much cleaner way to do stuff when animations start or end, compared to inheriting from ChangeListener, and checking if the ChangeBroadcaster was the Desktop::getInstance().getAnimator() in the changeListenerCallback.


#2

There are a few places the API could be updated to use newer C++ features now that our set of supported platforms is slowly getting younger. This is one of them! We’ll be doing a tidy up sometime after the next big release.