First Commit
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class Animator::Impl
|
||||
{
|
||||
public:
|
||||
virtual ~Impl() = default;
|
||||
|
||||
virtual double getDurationMs() const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
shouldStart = true;
|
||||
shouldComplete = false;
|
||||
}
|
||||
|
||||
void complete()
|
||||
{
|
||||
shouldComplete = true;
|
||||
}
|
||||
|
||||
Animator::Status update (double timestampMs)
|
||||
{
|
||||
if (std::exchange (shouldStart, false))
|
||||
{
|
||||
onStart (timestampMs);
|
||||
running = true;
|
||||
}
|
||||
|
||||
if (! running)
|
||||
return Animator::Status::idle;
|
||||
|
||||
const auto status = internalUpdate (timestampMs);
|
||||
|
||||
if (status != Animator::Status::finished && ! shouldComplete)
|
||||
return status;
|
||||
|
||||
shouldComplete = false;
|
||||
running = false;
|
||||
onComplete();
|
||||
return Animator::Status::finished;
|
||||
}
|
||||
|
||||
virtual bool isComplete() const { return shouldComplete; }
|
||||
|
||||
virtual void onStart (double timeStampMs) = 0;
|
||||
virtual void onComplete() = 0;
|
||||
virtual Animator::Status internalUpdate (double timestampMs) = 0;
|
||||
|
||||
bool shouldStart = false, shouldComplete = false, running = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Animator::Animator (std::shared_ptr<Impl> ai)
|
||||
: ptr (std::move (ai))
|
||||
{
|
||||
jassert (ptr != nullptr);
|
||||
}
|
||||
|
||||
double Animator::getDurationMs() const
|
||||
{
|
||||
return ptr->getDurationMs();
|
||||
}
|
||||
|
||||
void Animator::start() const
|
||||
{
|
||||
ptr->start();
|
||||
}
|
||||
|
||||
void Animator::complete() const
|
||||
{
|
||||
ptr->complete();
|
||||
}
|
||||
|
||||
Animator::Status Animator::update (double timestampMs) const
|
||||
{
|
||||
return ptr->update (timestampMs);
|
||||
}
|
||||
|
||||
bool Animator::isComplete() const
|
||||
{
|
||||
return ptr->isComplete();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
struct AnimatorTests : public UnitTest
|
||||
{
|
||||
AnimatorTests()
|
||||
: UnitTest ("Animator", UnitTestCategories::gui)
|
||||
{
|
||||
}
|
||||
|
||||
struct TestEvents
|
||||
{
|
||||
enum class TestEventType
|
||||
{
|
||||
animatorStarted,
|
||||
animatorEnded
|
||||
};
|
||||
|
||||
struct TestEvent
|
||||
{
|
||||
TestEvent (TestEventType e, int a) : eventType (e), animatorId (a) {}
|
||||
|
||||
TestEventType eventType;
|
||||
int animatorId;
|
||||
};
|
||||
|
||||
void started (int animatorId)
|
||||
{
|
||||
events.emplace_back (TestEventType::animatorStarted, animatorId);
|
||||
}
|
||||
|
||||
void ended (int animatorId)
|
||||
{
|
||||
events.emplace_back (TestEventType::animatorEnded, animatorId);
|
||||
}
|
||||
|
||||
bool animatorStartedBeforeAnotherStarted (int animator, int before)
|
||||
{
|
||||
for (const auto& event : events)
|
||||
{
|
||||
if (event.animatorId == before && event.eventType == TestEventType::animatorStarted)
|
||||
return false;
|
||||
|
||||
if (event.animatorId == animator && event.eventType == TestEventType::animatorStarted)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool animatorStartedBeforeAnotherEnded (int animator, int before)
|
||||
{
|
||||
for (const auto& event : events)
|
||||
{
|
||||
if (event.animatorId == before && event.eventType == TestEventType::animatorEnded)
|
||||
return false;
|
||||
|
||||
if (event.animatorId == animator && event.eventType == TestEventType::animatorStarted)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<TestEvent> events;
|
||||
};
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("AnimatorSet starts end ends Animators in the right order");
|
||||
{
|
||||
TestEvents events;
|
||||
|
||||
auto createTestAnimator = [&events] (int animatorId)
|
||||
{
|
||||
return ValueAnimatorBuilder {}
|
||||
.withOnStartCallback ([&events, animatorId]
|
||||
{
|
||||
events.started (animatorId);
|
||||
return [] (auto) {};
|
||||
})
|
||||
.withOnCompleteCallback ([&events, animatorId]
|
||||
{
|
||||
events.ended (animatorId);
|
||||
})
|
||||
.build();
|
||||
};
|
||||
|
||||
auto stage1 = AnimatorSetBuilder { createTestAnimator (1) };
|
||||
stage1.followedBy (createTestAnimator (2));
|
||||
stage1.togetherWith (createTestAnimator (3));
|
||||
|
||||
Animator animator = stage1.build();
|
||||
animator.start();
|
||||
|
||||
for (double timeMs = 0.0; animator.update (timeMs) != Animator::Status::finished; timeMs += 16.667)
|
||||
;
|
||||
|
||||
expect (events.animatorStartedBeforeAnotherEnded (1, 2));
|
||||
expect (! events.animatorStartedBeforeAnotherEnded (2, 1));
|
||||
expect (events.animatorStartedBeforeAnotherEnded (3, 1));
|
||||
expect (events.animatorStartedBeforeAnotherStarted (3, 2));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static AnimatorTests animatorTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Wrapper class for managing the lifetime of all the different animator kinds created through the
|
||||
builder classes.
|
||||
|
||||
It uses reference counting. If you copy an Animator the resulting object will refer to the same
|
||||
underlying instance, and the underlying instance is guaranteed to remain valid for as long as
|
||||
you have an Animator object referencing it.
|
||||
|
||||
An Animator object can be registered with the AnimatorUpdater, which only stores a weak
|
||||
reference to the underlying instance. If an AnimatorUpdater references the underlying instance
|
||||
and it becomes deleted due to all Animator objects being deleted, the updater will automatically
|
||||
remove it from its queue, so manually removing it is not required.
|
||||
|
||||
@see ValueAnimatorBuilder, AnimatorSetBuilder, AnimatorUpdater, VBlankAnimatorUpdater
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class JUCE_API Animator
|
||||
{
|
||||
public:
|
||||
class Impl;
|
||||
|
||||
/** The state of an Animator that determines how AnimatorUpdaters and other Animators will
|
||||
interact with it.
|
||||
*/
|
||||
enum class Status
|
||||
{
|
||||
/** The Animator is idle and its state is not progressing even if it is attached to an
|
||||
AnimatorUpdater.
|
||||
*/
|
||||
idle,
|
||||
|
||||
/** The Animator is active and its state is progressing whenever its update function is
|
||||
called.
|
||||
*/
|
||||
inProgress,
|
||||
|
||||
/** The Animator finished its run and its onCompletion callback may be called. It requires
|
||||
no further calls to its update function.
|
||||
*/
|
||||
finished
|
||||
};
|
||||
|
||||
/** @internal
|
||||
|
||||
Constructor. Used by the builder classes.
|
||||
|
||||
@see ValueAnimatorBuilder, AnimatorSetBuilder
|
||||
*/
|
||||
explicit Animator (std::shared_ptr<Impl>);
|
||||
|
||||
/** Returns the total animation duration in milliseconds. */
|
||||
double getDurationMs() const;
|
||||
|
||||
/** Marks the Animator ready for starting. You must call this function to allow the Animator to
|
||||
move out of the idle state.
|
||||
|
||||
After calling this function the Animator's on start callback will be executed at the next
|
||||
update immediately followed by the first call to it's update function.
|
||||
|
||||
You can call this function before or after adding the Animator to an AnimatorUpdater. Until
|
||||
start() is called the Animator will just sit idly in the updater's queue.
|
||||
*/
|
||||
void start() const;
|
||||
|
||||
/** Marks the Animator ready to be completed. ValueAnimators will be completed automatically
|
||||
when they reach a progress >= 1.0 unless they are infinitely running. AnimatorSets will also
|
||||
complete on their own when all of their constituent Animators complete.
|
||||
|
||||
Using this function you can fast track the completion of an Animator. After calling this
|
||||
function isComplete will return true, and it's guaranteed that you will receive an update
|
||||
callback with a progress value of 1.0. After this the onComplete callback will be executed.
|
||||
*/
|
||||
void complete() const;
|
||||
|
||||
/** Called periodically for active Animators by the AnimatorUpdater classes. The passed in
|
||||
timestamp must be monotonically increasing. This allows the underlying Animator
|
||||
to follow its progression towards completion.
|
||||
|
||||
While you can call this function in special circumstances, you will generally want an
|
||||
AnimatorUpdater to do it. Using the VBlankAnimatorUpdater ensures that update is called in
|
||||
sync with the monitor's vertical refresh resulting in smooth animations.
|
||||
|
||||
@see AnimatorUpdater, VBlankAnimatorUpdater
|
||||
*/
|
||||
Status update (double timestampMs) const;
|
||||
|
||||
/** Returns true if the Animator has reached the point of completion either because complete()
|
||||
has been called on it, or in case of the ValueAnimator, if it reached a progress of >= 1.0.
|
||||
|
||||
You typically don't need to call this function, because in any case a completed Animator
|
||||
will receive an update callback with a progress value of 1.0 and following that the
|
||||
on complete callback will be called.
|
||||
*/
|
||||
bool isComplete() const;
|
||||
|
||||
/** Comparison function used by the implementation to store Animators in ordered collections.
|
||||
It can also be used to determine equality of Animator objects based on whether they
|
||||
reference the same underlying implementation.
|
||||
*/
|
||||
struct JUCE_API Compare
|
||||
{
|
||||
/** Comparison function. */
|
||||
bool operator() (const Animator& a, const Animator& b) const { return a.ptr < b.ptr; }
|
||||
};
|
||||
|
||||
/** @internal
|
||||
|
||||
Stores a weak reference to the Animator's underlying implementation. Animator objects store
|
||||
a strong reference to the implementation, so it won't be deleted as long as an Animator
|
||||
object references it. Instead of copying the Animator, you can use makeWeak() to create a
|
||||
weak reference, which will not prevent deletion of the underlying implementation, but allows
|
||||
you to create a strong reference using the lock function for as long as the underlying
|
||||
object is alive.
|
||||
|
||||
This class is used by the AnimatorUpdater, and it's unlikely you will need to use it
|
||||
directly.
|
||||
|
||||
@see AnimatorUpdater, VBlankAnimatorUpdater
|
||||
*/
|
||||
class JUCE_API Weak
|
||||
{
|
||||
public:
|
||||
/** Constructor used by the Animator implementation. To obtain a weak reference use
|
||||
Animator::makeWeak().
|
||||
*/
|
||||
Weak() = default;
|
||||
|
||||
/** Constructor used by the Animator implementation. To obtain a weak reference use
|
||||
Animator::makeWeak().
|
||||
*/
|
||||
explicit Weak (std::shared_ptr<Impl> p) : ptr (p), originalPtr (p.get()) {}
|
||||
|
||||
/** If the referenced Animator implementation object still exists it returns an Animator
|
||||
object storing a strong reference to it.
|
||||
|
||||
If the implementation object was deleted it returns a nullopt.
|
||||
*/
|
||||
std::optional<Animator> lock() const
|
||||
{
|
||||
if (const auto l = ptr.lock())
|
||||
return Animator { l };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/** @internal
|
||||
|
||||
Used internally for storing the reference in a std::map.
|
||||
*/
|
||||
void* getKey() const
|
||||
{
|
||||
return originalPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::weak_ptr<Impl> ptr;
|
||||
Impl* originalPtr{};
|
||||
};
|
||||
|
||||
/** @internal
|
||||
|
||||
Returns a weak reference to the underlying implementation. You can use Weak::lock() to
|
||||
obtain a strong reference as long as the underlying object has not been deleted.
|
||||
*/
|
||||
Weak makeWeak() const { return Weak { ptr }; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Impl> ptr;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class DelayAnimator : public Animator::Impl
|
||||
{
|
||||
public:
|
||||
double getDurationMs() const override { return delayMs; }
|
||||
|
||||
static Animator build (double delayMsIn, std::function<void()> callbackIn = nullptr)
|
||||
{
|
||||
return Animator { rawToUniquePtr (new DelayAnimator (delayMsIn, std::move (callbackIn))) };
|
||||
}
|
||||
|
||||
private:
|
||||
DelayAnimator (double delayMsIn, std::function<void()> callbackIn)
|
||||
: onCompletion (std::move (callbackIn)),
|
||||
delayMs (delayMsIn)
|
||||
{
|
||||
}
|
||||
|
||||
Animator::Status internalUpdate (double timestampMs) override
|
||||
{
|
||||
if (timestampMs - startedAtMs >= delayMs)
|
||||
return Animator::Status::finished;
|
||||
|
||||
return Animator::Status::inProgress;
|
||||
}
|
||||
|
||||
void onStart (double timeMs) override { startedAtMs = timeMs; }
|
||||
|
||||
void onComplete() override { NullCheckedInvocation::invoke (onCompletion); }
|
||||
|
||||
std::function<void()> onCompletion;
|
||||
double startedAtMs = 0.0, delayMs = 0.0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct AnimatorSetData
|
||||
{
|
||||
explicit AnimatorSetData (Animator root)
|
||||
: roots { root }, entries { { root, {} } } {}
|
||||
|
||||
struct Entry
|
||||
{
|
||||
std::optional<Animator> parent; // If no parent, this is the root node
|
||||
std::set<Animator, Animator::Compare> children;
|
||||
};
|
||||
|
||||
auto getRoots() const { return roots; }
|
||||
|
||||
auto getChildren (const Animator& a) const
|
||||
{
|
||||
if (const auto iter = entries.find (a); iter != entries.end())
|
||||
return iter->second.children;
|
||||
|
||||
return std::set<Animator, Animator::Compare>();
|
||||
}
|
||||
|
||||
std::set<Animator, Animator::Compare> roots;
|
||||
std::map<Animator, Entry, Animator::Compare> entries;
|
||||
std::function<double (double)> timeTransform;
|
||||
};
|
||||
|
||||
class AnimatorSet : public Animator::Impl
|
||||
{
|
||||
public:
|
||||
explicit AnimatorSet (AnimatorSetData dataIn) : data (std::move (dataIn)) {}
|
||||
|
||||
double getDurationMs() const override
|
||||
{
|
||||
const auto roots = data.getRoots();
|
||||
return getMaxDuration (roots.begin(), roots.end());
|
||||
}
|
||||
|
||||
private:
|
||||
void onStart (double timestampMs) override
|
||||
{
|
||||
startedAtMs = timestampMs;
|
||||
active = data.getRoots();
|
||||
|
||||
for (const auto& i : active)
|
||||
i.start();
|
||||
}
|
||||
|
||||
void onComplete() override {}
|
||||
|
||||
Animator::Status internalUpdate (double timestampMs) override
|
||||
{
|
||||
const auto internalTimestampMs = [&]
|
||||
{
|
||||
if (data.timeTransform == nullptr)
|
||||
return timestampMs;
|
||||
|
||||
return data.timeTransform (timestampMs - startedAtMs);
|
||||
}();
|
||||
|
||||
if (isComplete())
|
||||
{
|
||||
for (auto i : active)
|
||||
i.complete();
|
||||
|
||||
while (updateAnimatorSet (internalTimestampMs) != Animator::Status::finished)
|
||||
{
|
||||
}
|
||||
|
||||
return Animator::Status::finished;
|
||||
}
|
||||
|
||||
return updateAnimatorSet (internalTimestampMs);
|
||||
}
|
||||
|
||||
Animator::Status updateAnimatorSet (double timestampMs)
|
||||
{
|
||||
std::set<Animator, Animator::Compare> animatorsToRemove;
|
||||
const auto currentlyActive = active;
|
||||
|
||||
for (const auto& animator : currentlyActive)
|
||||
{
|
||||
const auto status = animator.update (timestampMs);
|
||||
|
||||
if (status == Animator::Status::finished)
|
||||
{
|
||||
animatorsToRemove.insert (animator);
|
||||
|
||||
for (const auto& j : data.getChildren (animator))
|
||||
{
|
||||
j.start();
|
||||
|
||||
if (isComplete())
|
||||
j.complete();
|
||||
|
||||
active.insert (j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i : animatorsToRemove)
|
||||
active.erase (i);
|
||||
|
||||
return active.empty() ? Animator::Status::finished : Animator::Status::inProgress;
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
double getMaxDuration (It begin, It end) const
|
||||
{
|
||||
return std::accumulate (begin, end, 0.0, [this] (const auto acc, const auto& anim)
|
||||
{
|
||||
const auto children = data.getChildren (anim);
|
||||
return std::max (acc, anim.getDurationMs() + getMaxDuration (children.begin(), children.end()));
|
||||
});
|
||||
}
|
||||
|
||||
const AnimatorSetData data;
|
||||
std::set<Animator, Animator::Compare> active;
|
||||
double startedAtMs = 0.0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct AnimatorSetBuilder::AnimatorSetBuilderState
|
||||
{
|
||||
explicit AnimatorSetBuilderState (Animator animator)
|
||||
: data (std::move (animator)) {}
|
||||
|
||||
bool valid = true;
|
||||
AnimatorSetData data;
|
||||
};
|
||||
|
||||
AnimatorSetBuilder::AnimatorSetBuilder (Animator startingAnimator)
|
||||
: AnimatorSetBuilder (startingAnimator,
|
||||
std::make_shared<AnimatorSetBuilderState> (startingAnimator))
|
||||
{}
|
||||
|
||||
AnimatorSetBuilder::AnimatorSetBuilder (double delayMs)
|
||||
: AnimatorSetBuilder (DelayAnimator::build (delayMs, nullptr))
|
||||
{}
|
||||
|
||||
AnimatorSetBuilder::AnimatorSetBuilder (std::function<void()> cb)
|
||||
: AnimatorSetBuilder (DelayAnimator::build (0.0, std::move (cb)))
|
||||
{}
|
||||
|
||||
AnimatorSetBuilder::AnimatorSetBuilder (std::shared_ptr<AnimatorSetBuilderState> dataIn)
|
||||
: cursor (*dataIn->data.getRoots().begin()), state (std::move (dataIn))
|
||||
{}
|
||||
|
||||
AnimatorSetBuilder::AnimatorSetBuilder (Animator cursorIn, std::shared_ptr<AnimatorSetBuilderState> dataIn)
|
||||
: cursor (cursorIn), state (std::move (dataIn))
|
||||
{}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::togetherWith (Animator animator)
|
||||
{
|
||||
add (state->data.entries.at (cursor).parent, animator);
|
||||
return { animator, state };
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::followedBy (Animator animator)
|
||||
{
|
||||
add (cursor, animator);
|
||||
return { animator, state };
|
||||
}
|
||||
|
||||
void AnimatorSetBuilder::add (std::optional<Animator> parent, Animator child)
|
||||
{
|
||||
state->data.entries.emplace (child, AnimatorSetData::Entry { parent, {} });
|
||||
|
||||
if (parent.has_value())
|
||||
state->data.entries.at (*parent).children.insert (child);
|
||||
else
|
||||
state->data.roots.insert (child);
|
||||
}
|
||||
|
||||
Animator AnimatorSetBuilder::build()
|
||||
{
|
||||
if (state == nullptr)
|
||||
{
|
||||
/* If you're hitting this assertion, you've already used this AnimatorSetBuilder to build an
|
||||
AnimatorSet.
|
||||
|
||||
To create another AnimatorSet you need to use another AnimatorSetBuilder independently
|
||||
created with the AnimatorSetBuilder (Animator) constructor.
|
||||
*/
|
||||
jassertfalse;
|
||||
return ValueAnimatorBuilder{}.build();
|
||||
}
|
||||
|
||||
auto animator = Animator { std::make_unique<AnimatorSet> (std::move (state->data)) };
|
||||
state = nullptr;
|
||||
return animator;
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::followedBy (double delayMs)
|
||||
{
|
||||
return followedBy (DelayAnimator::build (delayMs, nullptr));
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::followedBy (std::function<void()> cb)
|
||||
{
|
||||
return followedBy (DelayAnimator::build (0.0, std::move (cb)));
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::togetherWith (double delayMs)
|
||||
{
|
||||
return togetherWith (DelayAnimator::build (delayMs, nullptr));
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::togetherWith (std::function<void()> cb)
|
||||
{
|
||||
return togetherWith (DelayAnimator::build (0.0, std::move (cb)));
|
||||
}
|
||||
|
||||
AnimatorSetBuilder AnimatorSetBuilder::withTimeTransform (std::function<double (double)> timeTransformIn)
|
||||
{
|
||||
state->data.timeTransform = std::move (timeTransformIn);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A builder class that can be used to construct an Animator wrapping an AnimatorSet
|
||||
implementation. It allows you to compose larger, complex animations by executing multiple
|
||||
constituent Animator instances in a coordinated manner. It essentially builds an Animator
|
||||
with an execution graph referencing other Animators.
|
||||
|
||||
Unlike ValueAnimatorBuilder, objects of AnimatorSetBuilder returned by its member functions
|
||||
reference the same underlying, modifiable builder instance. For this reason build() can be
|
||||
called only once on an underlying builder instance. This is to allow you to attach Animators to
|
||||
different points of the execution graph.
|
||||
|
||||
E.g. to have two functions followed by different amounts of delay, each followed by another
|
||||
function you would write the following.
|
||||
|
||||
@code
|
||||
// Both objects reference the same execution graph, but also refer to different Animators in it
|
||||
auto builderReferencingFirst = AnimatorSetBuilder { firstFunction };
|
||||
auto builderReferencingSecond = builderReferencingFirst.togetherWith (secondFunction);
|
||||
|
||||
builderReferencingFirst.followedBy (200).followedBy (thirdFunction);
|
||||
builderReferencingSecond.followedBy (500).followedBy (fourthFunction);
|
||||
|
||||
// You could use any one of the builder objects that refer to the same execution graph
|
||||
auto animator = builderReferencingFirst.build();
|
||||
@endcode
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class JUCE_API AnimatorSetBuilder
|
||||
{
|
||||
public:
|
||||
/** Creates a new builder instance specifying the startingAnimator as the first Animator that is
|
||||
started.
|
||||
*/
|
||||
explicit AnimatorSetBuilder (Animator startingAnimator);
|
||||
|
||||
/** Creates a builder with an empty starting animation that completes after delayMs.
|
||||
*/
|
||||
explicit AnimatorSetBuilder (double delayMs);
|
||||
|
||||
/** Creates a builder with a starting animation that completes at the first update and executes
|
||||
the provided callback function.
|
||||
*/
|
||||
explicit AnimatorSetBuilder (std::function<void()> cb);
|
||||
|
||||
/** Adds an Animator to the execution graph that will start executing at the same time as the
|
||||
Animator provided last to this builder object.
|
||||
*/
|
||||
AnimatorSetBuilder togetherWith (Animator animator);
|
||||
|
||||
/** Adds an empty Animator to the execution graph that will start executing at the same time as
|
||||
the Animator provided last to this builder object, and completes in delayMs.
|
||||
*/
|
||||
AnimatorSetBuilder togetherWith (double delayMs);
|
||||
|
||||
/** Adds an empty Animator to the execution graph that will start executing at the same time as
|
||||
the Animator provided last to this builder object, completes upon its first update, and
|
||||
executes the provided callback.
|
||||
*/
|
||||
AnimatorSetBuilder togetherWith (std::function<void()> cb);
|
||||
|
||||
/** Adds an Animator to the execution graph that will start executing after the Animator
|
||||
provided last to this builder object completes.
|
||||
*/
|
||||
AnimatorSetBuilder followedBy (Animator animator);
|
||||
|
||||
/** Adds an empty Animator to the execution graph that will start executing after the Animator
|
||||
provided last to this builder object
|
||||
*/
|
||||
AnimatorSetBuilder followedBy (double delayMs);
|
||||
|
||||
/** Adds an empty Animator to the execution graph that will start executing after the Animator
|
||||
provided last to this builder object, completes upon its first update, and executes the
|
||||
provided callback.
|
||||
*/
|
||||
AnimatorSetBuilder followedBy (std::function<void()> cb);
|
||||
|
||||
/** Specifies a time transformation function that the built Animator should utilise, allowing
|
||||
accelerating and decelerating the entire set of Animators.
|
||||
|
||||
The provided function should be monotonically increasing.
|
||||
*/
|
||||
AnimatorSetBuilder withTimeTransform (std::function<double (double)> transform);
|
||||
|
||||
/** Builds an Animator that executes the previously described and parameterised execution graph.
|
||||
|
||||
This function should only be called once for every AnimatorSetBuilder created by its public
|
||||
constructor.
|
||||
*/
|
||||
Animator build();
|
||||
|
||||
private:
|
||||
struct AnimatorSetBuilderState;
|
||||
|
||||
explicit AnimatorSetBuilder (std::shared_ptr<AnimatorSetBuilderState> dataIn);
|
||||
|
||||
AnimatorSetBuilder (Animator cursorIn, std::shared_ptr<AnimatorSetBuilderState> dataIn);
|
||||
|
||||
void add (std::optional<Animator> parent, Animator child);
|
||||
|
||||
Animator cursor;
|
||||
std::shared_ptr<AnimatorSetBuilderState> state;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
void AnimatorUpdater::addAnimator (const Animator& animator)
|
||||
{
|
||||
addAnimator (animator, nullptr);
|
||||
}
|
||||
|
||||
void AnimatorUpdater::addAnimator (const Animator& animator, std::function<void()> onComplete)
|
||||
{
|
||||
Entry entry { animator.makeWeak(), std::move (onComplete) };
|
||||
animators[entry.animator.getKey()] = std::move (entry);
|
||||
}
|
||||
|
||||
void AnimatorUpdater::removeAnimator (const Animator& animator)
|
||||
{
|
||||
if (auto it = animators.find (animator.makeWeak().getKey()); it != animators.end())
|
||||
{
|
||||
if (it == currentIterator)
|
||||
{
|
||||
++currentIterator;
|
||||
iteratorServiced = false;
|
||||
}
|
||||
|
||||
animators.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatorUpdater::update()
|
||||
{
|
||||
update (Time::getMillisecondCounterHiRes());
|
||||
}
|
||||
|
||||
void AnimatorUpdater::update (double timestampMs)
|
||||
{
|
||||
if (reentrancyGuard)
|
||||
{
|
||||
// If this is hit, one of the animators is trying to update itself
|
||||
// recursively. This is a bad idea! Inspect the callstack to find the
|
||||
// cause of the problem.
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
const ScopedValueSetter setter { reentrancyGuard, true };
|
||||
|
||||
for (currentIterator = animators.begin(); currentIterator != animators.end();)
|
||||
{
|
||||
auto& current = *currentIterator;
|
||||
|
||||
if (const auto locked = current.second.animator.lock())
|
||||
{
|
||||
iteratorServiced = true;
|
||||
|
||||
if (locked->update (timestampMs) == Animator::Status::finished)
|
||||
NullCheckedInvocation::invoke (current.second.onComplete);
|
||||
|
||||
if (iteratorServiced && currentIterator != animators.end())
|
||||
++currentIterator;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentIterator = animators.erase (currentIterator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helper class to update several animators at once, without owning or otherwise extending the
|
||||
lifetimes of those animators.
|
||||
|
||||
The intended use case is to register Animators with an updater as opposed to separately calling
|
||||
Animator::update() on each of them. Calling update() then will update all registered Animators.
|
||||
In case an Animator's underlying implementation is deleted (all Animator objects that were
|
||||
strongly referencing it were deleted) it is automatically removed by the AnimatorUpdater.
|
||||
|
||||
If you want to update all your Animators in sync with the display refresh you will probably want
|
||||
to use the VBlankAnimatorUpdater.
|
||||
|
||||
The order in which Animator::update() functions are called for registered Animators is not
|
||||
specified, as Animators should be implemented in a way where it doesn't matter.
|
||||
|
||||
@see VBlankAnimatorUpdater
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class JUCE_API AnimatorUpdater
|
||||
{
|
||||
public:
|
||||
/** Registers an Animator with the updater.
|
||||
*/
|
||||
void addAnimator (const Animator& animator);
|
||||
|
||||
/** Registers an Animator with the updater and specifies a callback to be called upon the
|
||||
completion of the Animator.
|
||||
|
||||
This callback can be used for cleanup purposes e.g.
|
||||
|
||||
@code
|
||||
animatorUpdater.addAnimator (someComponentPtr->getAnimator(),
|
||||
[&someComponentPtr] { someComponentPtr.reset(); });
|
||||
@endcode
|
||||
*/
|
||||
void addAnimator (const Animator& animator, std::function<void()> onComplete);
|
||||
|
||||
/** Removes an Animator
|
||||
*/
|
||||
void removeAnimator (const Animator& animator);
|
||||
|
||||
/** Calls Animator::update() for all registered Animators that are still alive. References to
|
||||
deleted Animators are removed.
|
||||
|
||||
Uses Time::getMillisecondCounterHiRes() to calculate the necessary timestamp. Consider using
|
||||
a VBlankAnimatorUpdater instead for using timestamps that are synchronised across all
|
||||
VBlankAnimatorUpdater instances.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/** Calls Animator::update() for all registered Animators that are still alive. References to
|
||||
deleted Animators are removed.
|
||||
|
||||
The supplied timestamp should be monotonically increasing for correct behaviour. Ideally
|
||||
this should be a timestamp supplied by a VBlankAttachment. Consider using the
|
||||
VBlankAnimatorUpdater class, which takes care of supplying the right timestamp.
|
||||
|
||||
@see VBlankAnimatorUpdater
|
||||
*/
|
||||
void update (double timestampMs);
|
||||
|
||||
private:
|
||||
struct JUCE_API Entry
|
||||
{
|
||||
Entry() = default;
|
||||
|
||||
Entry(Animator::Weak animatorIn, std::function<void()> onCompleteIn)
|
||||
: animator (animatorIn),
|
||||
onComplete (std::move (onCompleteIn))
|
||||
{}
|
||||
|
||||
Animator::Weak animator;
|
||||
std::function<void()> onComplete;
|
||||
};
|
||||
|
||||
std::map<void*, Entry> animators;
|
||||
std::map<void*, Entry>::iterator currentIterator;
|
||||
|
||||
bool iteratorServiced = false;
|
||||
bool reentrancyGuard = false;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
std::function<float (float)> Easings::createCubicBezier (float x1, float y1, float x2, float y2)
|
||||
{
|
||||
// The x axis represents time, it's important this always stays in the range 0 - 1
|
||||
jassert (isPositiveAndNotGreaterThan (x1, 1.0f));
|
||||
jassert (isPositiveAndNotGreaterThan (x2, 1.0f));
|
||||
|
||||
chromium::gfx::CubicBezier cubicBezier { (double) x1, (double) y1, (double) x2, (double) y2 };
|
||||
return [bezier = std::move (cubicBezier)] (float v) { return (float) bezier.Solve (v); };
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createCubicBezier (Point<float> controlPoint1,
|
||||
Point<float> controlPoint2)
|
||||
{
|
||||
return createCubicBezier (controlPoint1.getX(),
|
||||
controlPoint1.getY(),
|
||||
controlPoint2.getX(),
|
||||
controlPoint2.getY());
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEase()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.25f, 0.1f, 0.25f, 1.0f);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEaseIn()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.42f, 0.0f, 1.0f, 1.0f);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEaseOut()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.0f, 0.0f, 0.58f, 1.0f);;
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEaseInOut()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.42f, 0.0f, 0.58f, 1.0f);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createLinear()
|
||||
{
|
||||
return [] (auto x){ return x; };
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEaseOutBack()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.34f, 1.56f, 0.64f, 1.0f);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createEaseInOutCubic()
|
||||
{
|
||||
const static auto f = createCubicBezier (0.65f, 0.0f, 0.35f, 1.0f);
|
||||
return f;
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createSpring (const SpringEasingOptions& options)
|
||||
{
|
||||
return [=] (float v)
|
||||
{
|
||||
const auto t = std::clamp (v, 0.0f, 1.0f);
|
||||
const auto omega = 2.0f * MathConstants<float>::pi * options.getFrequency();
|
||||
const auto physicalValue = 1.0f - std::exp (-options.getAttenuation() * t) * std::cos (omega * t);
|
||||
const auto squish = 1.0f / options.getExtraAttenuationRange();
|
||||
const auto shift = 1.0f - options.getExtraAttenuationRange();
|
||||
const auto weight = std::clamp (std::pow (squish * (std::max (t - shift, 0.0f)), 2.0f), 0.0f, 1.0f);
|
||||
return weight + (1.0f - weight) * physicalValue;
|
||||
};
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createBounce (int numBounces)
|
||||
{
|
||||
jassert (numBounces >= 0);
|
||||
numBounces = std::max (0, numBounces);
|
||||
|
||||
const auto alpha = std::pow (0.05f, 1.0f / (float) numBounces);
|
||||
|
||||
const auto fallTime = [] (float h)
|
||||
{
|
||||
return std::sqrt (2.0f * h);
|
||||
};
|
||||
|
||||
std::vector<float> bounceTimes;
|
||||
bounceTimes.reserve ((size_t) (numBounces + 1));
|
||||
bounceTimes.push_back (fallTime (1.0f));
|
||||
|
||||
for (int i = 1; i < numBounces + 1; ++i)
|
||||
bounceTimes.push_back (bounceTimes.back() + 2.0f * fallTime (std::pow (alpha, (float) i)));
|
||||
|
||||
for (auto& bounce : bounceTimes)
|
||||
bounce /= bounceTimes.back();
|
||||
|
||||
return [alpha, times = std::move (bounceTimes)] (float v)
|
||||
{
|
||||
v = std::clamp (v, 0.0f, 1.0f);
|
||||
|
||||
const auto boundIt = std::lower_bound (times.begin(), times.end(), v);
|
||||
|
||||
if (boundIt == times.end())
|
||||
return 1.0f;
|
||||
|
||||
const auto i = (size_t) std::distance (times.begin(), boundIt);
|
||||
const auto height = i == 0 ? 1.0f : std::pow (alpha, (float) i);
|
||||
const auto center = i == 0 ? 0.0f : (times[i] + times[i - 1]) / 2.0f;
|
||||
const auto distToZero = i == 0 ? times[i] : (times[i] - times[i - 1]) / 2.0f;
|
||||
return 1.0f - height * (1.0f - std::pow (1.0f / distToZero * (v - center), 2.0f));
|
||||
};
|
||||
}
|
||||
|
||||
std::function<float (float)> Easings::createOnOffRamp()
|
||||
{
|
||||
return [] (float x) { return 1.0f - std::abs (2.0f * (x - 0.5f)); };
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** A selection of options available for customising a spring style easing function.
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class SpringEasingOptions
|
||||
{
|
||||
public:
|
||||
/** Specifies the number of oscillations the easing would undergo.
|
||||
|
||||
This also affects the speed of the movement.
|
||||
|
||||
@see getFrequency, withAttenuation, withExtraAttenuationRange
|
||||
*/
|
||||
[[nodiscard]] auto withFrequency (float newFrequency) const
|
||||
{
|
||||
return withMember (*this, &SpringEasingOptions::frequency, newFrequency);
|
||||
}
|
||||
|
||||
/** Affects how quickly the oscillations die down.
|
||||
|
||||
@see getAttenuation, withFrequency, withExtraAttenuationRange
|
||||
*/
|
||||
[[nodiscard]] auto withAttenuation (float newAttenuation) const
|
||||
{
|
||||
return withMember (*this, &SpringEasingOptions::attenuation, newAttenuation);
|
||||
}
|
||||
|
||||
/** Specifies the input value at which an extra non-physical attenuation begins to be applied.
|
||||
The value must be in the range [0.05f, 0.98f].
|
||||
|
||||
This ensures that the easing always reaches an output value of 1.0f when the input value is
|
||||
1.0f. If the attenuation is set sufficiently high this won't have a visible effect.
|
||||
|
||||
@see getExtraAttenuationRange, withFrequency, withAttenuation
|
||||
*/
|
||||
[[nodiscard]] auto withExtraAttenuationRange (float newExtraAttenuationRange) const
|
||||
{
|
||||
return withMember (*this, &SpringEasingOptions::extraAttenuationRange, std::clamp (newExtraAttenuationRange, 0.05f, 0.98f));
|
||||
}
|
||||
|
||||
/** Returns the value specified by withFrequency.
|
||||
|
||||
If no value was specified the default value is 3.0f.
|
||||
|
||||
@see withFrequency
|
||||
*/
|
||||
[[nodiscard]] auto getFrequency() const { return frequency; }
|
||||
|
||||
/** Returns the value specified by withAttenuation.
|
||||
|
||||
If no value was specified the default value is 3.0f.
|
||||
|
||||
@see withAttenuation
|
||||
*/
|
||||
[[nodiscard]] auto getAttenuation() const { return attenuation; }
|
||||
|
||||
/** Returns the value specified by withExtraAttenuationRange
|
||||
|
||||
If no value was specified the default value is 0.25f.
|
||||
|
||||
@see withExtraAttenuationRange
|
||||
*/
|
||||
[[nodiscard]] auto getExtraAttenuationRange() const { return extraAttenuationRange; }
|
||||
|
||||
private:
|
||||
float frequency = 3.0f;
|
||||
float attenuation = 3.0f;
|
||||
float extraAttenuationRange = 0.25f;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a number of easing functions that you can pass into ValueAnimatorBuilder::withEasing to
|
||||
transform the linear progression of animations.
|
||||
|
||||
Using createSpring() for example would transform a rigid movement into one that is reminiscent
|
||||
of a weight attached to a spring.
|
||||
|
||||
For examples of all the easing functions see the AnimationEasingDemo in the DemoRunner.
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
struct Easings
|
||||
{
|
||||
/** Returns a cubic Bezier function with the control points (x1, y1), (x2, y2). These points are
|
||||
the two middle points of a cubic Bezier function's four control points, the first and last
|
||||
being (0, 0), and (1, 1).
|
||||
*/
|
||||
static std::function<float (float)> createCubicBezier (float x1, float y1, float x2, float y2);
|
||||
|
||||
/** Returns a cubic Bezier function with two control points. These points are the two middle
|
||||
points of a cubic Bezier function's four control points, the first and last being (0, 0),
|
||||
and (1, 1).
|
||||
*/
|
||||
static std::function<float (float)> createCubicBezier (Point<float> controlPoint1,
|
||||
Point<float> controlPoint2);
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.25f, 0.1f, 0.25f, 1.0f). This indicates
|
||||
that the interpolation starts slowly, accelerates sharply, and then slows gradually towards
|
||||
the end. It is similar to createEaseInOut(), though it accelerates more sharply at the
|
||||
beginning.
|
||||
|
||||
This is equivalent to using the "ease" keyword when specifying a timing-function in CSS.
|
||||
|
||||
This is the default easing used by the ValueAnimatorBuilder class if no other easing
|
||||
function is specified.
|
||||
|
||||
@see createCubicBezier, createEaseIn, createEaseOut, createEaseInOut
|
||||
*/
|
||||
static std::function<float (float)> createEase();
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.42f, 0.0f, 1.0f, 1.0f). This indicates that
|
||||
the interpolation starts slowly, then progressively speeds up until the end, at which point
|
||||
it stops abruptly.
|
||||
|
||||
This is equivalent to using the "ease-in" keyword when specifying a timing-function in CSS.
|
||||
|
||||
@see createCubicBezier, createEase, createEaseOut, createEaseInOut
|
||||
*/
|
||||
static std::function<float (float)> createEaseIn();
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.0f, 0.0f, 0.58f, 1.0f). This indicates that
|
||||
the interpolation starts abruptly and then progressively slows down towards the end.
|
||||
|
||||
This is equivalent to using the "ease-out" keyword when specifying a timing-function in CSS.
|
||||
|
||||
@see createCubicBezier, createEase, createEaseIn, createEaseInOut, createEaseOutBack
|
||||
*/
|
||||
static std::function<float (float)> createEaseOut();
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.34f, 1.56f, 0.64f, 1.0f). This indicates
|
||||
that the interpolation starts abruptly, quickly decelerating before overshooting the target
|
||||
value by approximately 10% and changing direction to slowly head back towards the target
|
||||
value.
|
||||
|
||||
Like createSpring() this will overshoot causing it to return float values exceeding 1.0f.
|
||||
|
||||
This is equivalent to easeOutBack as specified on https://easings.net/#easeOutBack.
|
||||
|
||||
@see createCubicBezier, createEaseOutBack, createSpring
|
||||
*/
|
||||
static std::function<float (float)> createEaseOutBack();
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.42f, 0.0f, 0.58f, 1.0f). This indicates
|
||||
that the interpolation starts slowly, speeds up, and then slows down towards the end. At the
|
||||
beginning, it behaves like createEaseIn(); at the end, it behaves like createEaseOut().
|
||||
|
||||
This is equivalent to using the "ease-in-out" keyword when specifying a timing-function in
|
||||
CSS.
|
||||
|
||||
@see createCubicBezier, createEase, createEaseIn, createEaseInOut
|
||||
*/
|
||||
static std::function<float (float)> createEaseInOut();
|
||||
|
||||
/** Returns the easing function createCubicBezier (0.65f, 0.0f, 0.35f, 1.0f). This indicates
|
||||
that the interpolation starts slowly, speeds up, and then slows down towards the end. It
|
||||
behaves similar to createEaseInOut() but is more exaggerated and has a more symmetrical
|
||||
curve.
|
||||
|
||||
This is equivalent to easeInOutCubic as specified on https://easings.net/#easeInOutCubic.
|
||||
|
||||
@see createCubicBezier, createEaseInOut
|
||||
*/
|
||||
static std::function<float (float)> createEaseInOutCubic();
|
||||
|
||||
/** Returns an easing function with a constant rate of interpolation, with no change in the rate
|
||||
of progress throughout the duration (that is, no acceleration or deceleration).
|
||||
*/
|
||||
static std::function<float (float)> createLinear();
|
||||
|
||||
/** Returns an easing function that behaves like a spring with a weight attached.
|
||||
|
||||
Like createEaseOutBack() this might overshoot causing it to return float values exceeding
|
||||
1.0f.
|
||||
|
||||
@see createEaseOutBack
|
||||
*/
|
||||
static std::function<float (float)> createSpring (const SpringEasingOptions& options = {});
|
||||
|
||||
/** Returns an easing function that behaves like a bouncy ball dropped on the ground.
|
||||
|
||||
The function will bounce numBounces times on the input range of [0, 1] before coming to
|
||||
stop, each bounce is less pronounced than the previous.
|
||||
|
||||
This is equivalent to easeInOutCubic as specified on https://easings.net/#easeOutBounce.
|
||||
*/
|
||||
static std::function<float (float)> createBounce (int numBounces = 3);
|
||||
|
||||
/** Returns an easing function that reaches 1.0f when the input value is 0.5f, before returning
|
||||
to 0.0f when the input values reaches 1.0f.
|
||||
|
||||
This is useful for making a repeating pulsation.
|
||||
*/
|
||||
static std::function<float (float)> createOnOffRamp();
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Helper class for using linear interpolation between a begin and an end value.
|
||||
|
||||
The ValueType could be any numerical type, or a std::tuple containing numerical types. This
|
||||
class is mainly intended to be used with the latter.
|
||||
|
||||
This way you can interpolate multiple values by supplying a single float value, which you can
|
||||
access in an Animator's value change callback.
|
||||
|
||||
E.g.
|
||||
@code
|
||||
const auto boundsToTuple = [] (auto b)
|
||||
{
|
||||
return std::make_tuple (b.getX(), b.getY(), b.getWidth(), b.getHeight());
|
||||
};
|
||||
|
||||
const auto begin = boundsToTuple (component.getBoundsInParent());
|
||||
const auto end = boundsToTuple (targetBounds);
|
||||
const auto limits = makeAnimationLimits (begin, end);
|
||||
|
||||
// This is the value change callback of an Animator, where you will transition a Component from
|
||||
// one bounds to the next. See the AnimatorsDemo for a more detailed example.
|
||||
const auto valueChanged = [&component, limits] (auto v)
|
||||
{
|
||||
const auto [x, y, w, h] = limits.lerp (v);
|
||||
component.setBounds (x, y, w, h);
|
||||
};
|
||||
@endcode
|
||||
|
||||
@see ValueAnimatorBuilder::ValueChangedCallback
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
template <typename ValueType>
|
||||
class JUCE_API StaticAnimationLimits
|
||||
{
|
||||
public:
|
||||
/** Constructor. You can use it to interpolate between a 0 initialised numerical value or tuple
|
||||
and the provided end state.
|
||||
*/
|
||||
explicit StaticAnimationLimits (const ValueType& endIn)
|
||||
: StaticAnimationLimits ({}, endIn) {}
|
||||
|
||||
/** Constructor. Creates an object that will interpolate between the two provided beginning and
|
||||
end states. The ValueType can be a numerical type or a std::tuple containing numerical
|
||||
types.
|
||||
*/
|
||||
StaticAnimationLimits (const ValueType& beginIn, const ValueType& endIn)
|
||||
: begin (beginIn), end (endIn) {}
|
||||
|
||||
/** Evaluation operator. Returns a value that is a linear interpolation of the beginning and end
|
||||
state. It's a shorthand for the lerp() function.
|
||||
*/
|
||||
ValueType operator() (float value) const
|
||||
{
|
||||
return lerp (value);
|
||||
}
|
||||
|
||||
/** Returns a value that is a linear interpolation of the beginning and end state.
|
||||
*/
|
||||
ValueType lerp (float value) const
|
||||
{
|
||||
using namespace detail::ArrayAndTupleOps;
|
||||
|
||||
if constexpr (std::is_integral_v<ValueType>)
|
||||
return (ValueType) std::round ((float) begin + ((float) (end - begin) * value));
|
||||
else
|
||||
return (ValueType) (begin + ((end - begin) * value));
|
||||
}
|
||||
|
||||
private:
|
||||
ValueType begin{}, end{};
|
||||
};
|
||||
|
||||
/** Creates an instance of StaticAnimationLimits, deducing ValueType from
|
||||
the function argument.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
StaticAnimationLimits<ValueType> makeAnimationLimits (const ValueType& end)
|
||||
{
|
||||
return StaticAnimationLimits<ValueType> (end);
|
||||
}
|
||||
|
||||
/** Creates an instance of StaticAnimationLimits, deducing ValueType from
|
||||
the function arguments.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
StaticAnimationLimits<ValueType> makeAnimationLimits (const ValueType& begin, const ValueType& end)
|
||||
{
|
||||
return StaticAnimationLimits<ValueType> (begin, end);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/**
|
||||
Similar to AnimatorUpdater, but automatically calls update() whenever the screen refreshes.
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class JUCE_API VBlankAnimatorUpdater : private AnimatorUpdater
|
||||
{
|
||||
public:
|
||||
/** Constructs a VBlankAnimatorUpdater that is synchronised to the refresh rate of the monitor
|
||||
that the provided Component is being displayed on.
|
||||
*/
|
||||
explicit VBlankAnimatorUpdater (Component* c)
|
||||
: vBlankAttachment (c, [this] (double timestampSec)
|
||||
{
|
||||
update (timestampSec * 1000.0);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
using AnimatorUpdater::addAnimator, AnimatorUpdater::removeAnimator;
|
||||
|
||||
private:
|
||||
VBlankAttachment vBlankAttachment;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class ValueAnimator : public Animator::Impl
|
||||
{
|
||||
public:
|
||||
explicit ValueAnimator (ValueAnimatorBuilder optionsIn) : options (std::move (optionsIn)) {}
|
||||
|
||||
auto getValue() const
|
||||
{
|
||||
using namespace detail::ArrayAndTupleOps;
|
||||
|
||||
return options.getEasing() == nullptr ? getProgress() : options.getEasing() (getProgress());
|
||||
}
|
||||
|
||||
float getProgress() const
|
||||
{
|
||||
if (isComplete())
|
||||
return 1.0f;
|
||||
|
||||
return timeBasedProgress;
|
||||
}
|
||||
|
||||
/** Returns the time in milliseconds that it takes for the progress to go from 0.0 to 1.0.
|
||||
|
||||
This is the value returned even if the Animator is infinitely running.
|
||||
*/
|
||||
double getDurationMs() const override
|
||||
{
|
||||
return options.getDurationMs();
|
||||
}
|
||||
|
||||
bool isComplete() const override
|
||||
{
|
||||
return Animator::Impl::isComplete()
|
||||
|| (! options.isInfinitelyRunning() && timeBasedProgress >= 1.0f);
|
||||
}
|
||||
|
||||
private:
|
||||
Animator::Status internalUpdate (double timestampMs) override
|
||||
{
|
||||
timeBasedProgress = (float) ((timestampMs - startedAtMs) / options.getDurationMs());
|
||||
|
||||
NullCheckedInvocation::invoke (onValueChanged, getValue());
|
||||
|
||||
if (! options.isInfinitelyRunning())
|
||||
return getProgress() >= 1.0 ? Animator::Status::finished : Animator::Status::inProgress;
|
||||
|
||||
return Animator::Status::inProgress;
|
||||
}
|
||||
|
||||
void onStart (double timeMs) override
|
||||
{
|
||||
startedAtMs = timeMs;
|
||||
timeBasedProgress = 0.0f;
|
||||
|
||||
if (auto fn = options.getOnStartWithValueChanged())
|
||||
onValueChanged = fn();
|
||||
}
|
||||
|
||||
void onComplete() override
|
||||
{
|
||||
NullCheckedInvocation::invoke (options.getOnComplete());
|
||||
}
|
||||
|
||||
double startedAtMs = 0.0;
|
||||
float timeBasedProgress = 0.0f;
|
||||
|
||||
const ValueAnimatorBuilder options;
|
||||
ValueAnimatorBuilder::ValueChangedCallback onValueChanged;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
Animator ValueAnimatorBuilder::build() const& { return Animator { std::make_unique<ValueAnimator> (*this) }; }
|
||||
Animator ValueAnimatorBuilder::build() && { return Animator { std::make_unique<ValueAnimator> (std::move (*this)) }; }
|
||||
|
||||
} // namespace juce
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A builder class that can be used to construct an Animator wrapping a ValueAnimator
|
||||
implementation.
|
||||
|
||||
Every ValueAnimatorBuilder object is immutable, and every "with..." function returns a new
|
||||
object. Each object can be used independently and as many times as required to build an Animator
|
||||
object.
|
||||
|
||||
Calling build() multiple times will return an independent Animator object referencing a new
|
||||
instance of the underlying implementation. Such Animator objects don't affect each other's
|
||||
lifetime. The copy of an Animator object however shares ownership with the object that it was
|
||||
copied from.
|
||||
|
||||
You can treat ValueAnimatorBuilder instances as disposable objects that are only needed until
|
||||
you call build() on them. You can then store only the returned Animator object, which can be
|
||||
started and completed multiple times as needed.
|
||||
|
||||
All functions beginning with "with..." are optional and can be used to affect the created
|
||||
Animator's behaviour by overriding defaults.
|
||||
|
||||
@tags{Animations}
|
||||
*/
|
||||
class JUCE_API ValueAnimatorBuilder
|
||||
{
|
||||
public:
|
||||
/** The type of the value change callback. The float parameter is related to the time parameter
|
||||
passed to Animator::update(). The update function is typically called by an AnimatorUpdater.
|
||||
The parameter will have a value of 0.0 during the first call of the value change callback,
|
||||
and it will reach 1.0 when the time passed equals the duration of the Animator. This however
|
||||
can be changed if an EasingFn is also specified. Correctly written easing functions should
|
||||
preserve the 0.0 and 1.0 start and end values, but intermittent values can fall outside the
|
||||
range of [0.0, 1.0].
|
||||
|
||||
After a call with a progress value of 1.0, the on complete callback will be called and the
|
||||
updates will stop, unless the Animator is infinitely running, in which case the progress
|
||||
will go beyond 1.0 and on complete will not be called until after Animator::complete() has
|
||||
been called.
|
||||
|
||||
A value change callback is optional. If you want to use one, you need to create it inside
|
||||
your on start callback that you must pass to withOnStartCallback().
|
||||
|
||||
@see withOnStartCallback, withDurationMs, withEasing, runningInfinitely
|
||||
*/
|
||||
using ValueChangedCallback = std::function<void (float)>;
|
||||
|
||||
/** The type of the on start callback. It can be used to do any initialisation necessary at the
|
||||
start of an animation, then it must return a ValueChangedCallback.
|
||||
|
||||
The ValueChangedCallback is called during every update of the Animator after the on start
|
||||
callback and before the on complete callback.
|
||||
|
||||
The on start callback is called during the first update that the Animator receives after
|
||||
Animator::start() has been called. Immediately after the on start callback the first call to
|
||||
the value changed callback is made.
|
||||
|
||||
@see ValueChangedCallback
|
||||
*/
|
||||
using OnStartReturningValueChangedCallback = std::function<ValueChangedCallback()>;
|
||||
|
||||
/** The type of an optional easing function that can be passed to the withEasing() builder
|
||||
function.
|
||||
|
||||
If this function is specified it will be called with the progress value going from 0.0 to
|
||||
1.0 (and beyond in case of an infinitely running Animator), that would otherwise be passed
|
||||
directly to the value change callback. The return value is then passed to the on value
|
||||
change callback instead.
|
||||
|
||||
This function can be used to change the linear progression of the animation and create
|
||||
effects like rubber band like motion.
|
||||
|
||||
@see ValueChangedCallback
|
||||
*/
|
||||
using EasingFn = std::function<float (float)>;
|
||||
|
||||
/** Use this function to specify an optional on start callback.
|
||||
|
||||
Alternatively you can use the withOnStartReturningValueChangedCallback function that allows
|
||||
you to return the ValueChangedCallback from inside your on start callback.
|
||||
|
||||
You can only use either withOnStartCallback() or withOnStartReturningValueChangedCallback().
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withOnStartCallback (std::function<void()> onStartCallback) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::onStartReturningValueChanged,
|
||||
[start = std::move (onStartCallback), previous = onStartReturningValueChanged]
|
||||
{
|
||||
NullCheckedInvocation::invoke (start);
|
||||
return previous != nullptr ? previous() : nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
/** Use this function to specify an optional on change callback.
|
||||
|
||||
Alternatively you can use the withOnStartReturningValueChangedCallback function that allows
|
||||
you to return the ValueChangedCallback from inside your on start callback.
|
||||
|
||||
You can only use either withValueChangedCallback or withOnStartReturningValueChangedCallback.
|
||||
|
||||
@see OnStartReturningValueChangedCallback
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withValueChangedCallback (ValueChangedCallback valueChangedCallback) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::onStartReturningValueChanged,
|
||||
[changed = std::move (valueChangedCallback), previous = onStartReturningValueChanged]
|
||||
{
|
||||
return [changed, previousChanged = previous != nullptr ? previous() : nullptr] (float x)
|
||||
{
|
||||
NullCheckedInvocation::invoke (previousChanged, x);
|
||||
NullCheckedInvocation::invoke (changed, x);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** Use this function to specify an optional on start callback.
|
||||
|
||||
The return value of the provided function is a ValueChangedCallback. This allows you to
|
||||
construct a new ValueChangedCallback on every on start event, capturing state that is also
|
||||
constructed at the time of starting.
|
||||
|
||||
If you don't need to return a new ValueChangedCallback on every animation start, you can use
|
||||
the simpler variants withOnStartCallback and withValueChangedCallback. However you cannot
|
||||
use those functions together with this one.
|
||||
|
||||
@see OnStartReturningValueChangedCallback, withOnStartCallback, withValueChangedCallback
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withOnStartReturningValueChangedCallback (OnStartReturningValueChangedCallback value) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::onStartReturningValueChanged, std::move (value));
|
||||
}
|
||||
|
||||
/** Use this function to optionally specify an on complete callback. This function will be
|
||||
called after the Animator reached a progress value >= 1.0, or in the case of an
|
||||
infinitely running animation, if Animator::complete() has been called.
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withOnCompleteCallback (std::function<void()> value) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::onComplete, std::move (value));
|
||||
}
|
||||
|
||||
/** Use this function to specify the time it takes for the Animator to reach a progress of 1.0.
|
||||
|
||||
The default value is 300 ms.
|
||||
|
||||
A progress of 1.0 will be reached after this time elapses even if the Animator is infinitely
|
||||
running.
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withDurationMs (double durationMsIn) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::durationMs, durationMsIn);
|
||||
}
|
||||
|
||||
/** Supply a function that transforms the linear progression of time.
|
||||
|
||||
@see EasingFn
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder withEasing (EasingFn fn) const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::easing, std::move (fn));
|
||||
}
|
||||
|
||||
/** This function specifies that the Animator will keep running even after its progress > 1.0
|
||||
and its on complete function will not be called until Animator::complete() is called.
|
||||
*/
|
||||
[[nodiscard]] ValueAnimatorBuilder runningInfinitely() const
|
||||
{
|
||||
return with (&ValueAnimatorBuilder::infinitelyRunning, true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Getter function used by the corresponding Animator implementation.
|
||||
*/
|
||||
auto& getOnComplete() const
|
||||
{
|
||||
return onComplete;
|
||||
}
|
||||
|
||||
/** Getter function used by the corresponding Animator implementation.
|
||||
*/
|
||||
auto& getOnStartWithValueChanged() const
|
||||
{
|
||||
return onStartReturningValueChanged;
|
||||
}
|
||||
|
||||
/** Getter function used by the corresponding Animator implementation.
|
||||
*/
|
||||
auto getDurationMs() const
|
||||
{
|
||||
return durationMs;
|
||||
}
|
||||
|
||||
/** Getter function used by the corresponding Animator implementation.
|
||||
*/
|
||||
auto isInfinitelyRunning() const
|
||||
{
|
||||
return infinitelyRunning;
|
||||
}
|
||||
|
||||
/** Getter function used by the corresponding Animator implementation.
|
||||
*/
|
||||
auto& getEasing() const
|
||||
{
|
||||
return easing;
|
||||
}
|
||||
|
||||
/** The build() function will instantiate a new underlying implementation with the specified
|
||||
parameters and return an Animator object referencing it. Calling build() multiple times
|
||||
will return unrelated Animator objects, that reference separate underlying implementation
|
||||
instances.
|
||||
*/
|
||||
Animator build() const&;
|
||||
|
||||
/** The build() function will instantiate a new underlying implementation with the specified
|
||||
parameters and return an Animator object referencing it. Calling build() multiple times
|
||||
will return unrelated Animator objects, that reference separate underlying implementation
|
||||
instances.
|
||||
|
||||
This overload will be called on rvalue handles.
|
||||
*/
|
||||
Animator build() &&;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
template <typename Member, typename Value>
|
||||
ValueAnimatorBuilder with (Member&& member, Value&& value) const noexcept
|
||||
{
|
||||
auto copy = *this;
|
||||
copy.*member = std::forward<Value> (value);
|
||||
return copy;
|
||||
}
|
||||
|
||||
OnStartReturningValueChangedCallback onStartReturningValueChanged;
|
||||
std::function<void()> onComplete;
|
||||
double durationMs = 300.0;
|
||||
bool infinitelyRunning = false;
|
||||
EasingFn easing = Easings::createEase();
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Reference in New Issue
Block a user