Browse Source

Added some safety checks to ComponentAnimator to avoid problems when cancelling animations during resize callbacks

tags/2021-05-28
jules 8 years ago
parent
commit
c8f9fdc023
1 changed files with 31 additions and 16 deletions
  1. +31
    -16
      modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp

+ 31
- 16
modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp View File

@@ -27,6 +27,11 @@ class ComponentAnimator::AnimationTask
public:
AnimationTask (Component* c) noexcept : component (c) {}
~AnimationTask()
{
masterReference.clear();
}
void reset (const Rectangle<int>& finalBounds,
float finalAlpha,
int millisecondsToSpendMoving,
@@ -63,14 +68,15 @@ public:
bool useTimeslice (const int elapsed)
{
if (Component* const c = proxy != nullptr ? static_cast<Component*> (proxy)
: static_cast<Component*> (component))
if (auto* c = proxy != nullptr ? static_cast<Component*> (proxy)
: static_cast<Component*> (component))
{
msElapsed += elapsed;
double newProgress = msElapsed / (double) msTotal;
if (newProgress >= 0 && newProgress < 1.0)
{
const WeakReference<AnimationTask> weakRef (this);
newProgress = timeToDistance (newProgress);
const double delta = (newProgress - lastProgress) / (1.0 - lastProgress);
jassert (newProgress >= lastProgress);
@@ -99,6 +105,11 @@ public:
}
}
// Check whether the animation was cancelled/deleted during
// a callback during the setBounds method
if (weakRef.wasObjectDeleted())
return false;
if (isChangingAlpha)
{
alpha += (destAlpha - alpha) * delta;
@@ -129,9 +140,8 @@ public:
}
//==============================================================================
class ProxyComponent : public Component
struct ProxyComponent : public Component
{
public:
ProxyComponent (Component& c)
{
setWantsKeyboardFocus (false);
@@ -140,15 +150,15 @@ public:
setAlpha (c.getAlpha());
setInterceptsMouseClicks (false, false);
if (Component* const parent = c.getParentComponent())
if (auto* parent = c.getParentComponent())
parent->addAndMakeVisible (this);
else if (c.isOnDesktop() && c.getPeer() != nullptr)
addToDesktop (c.getPeer()->getStyleFlags() | ComponentPeer::windowIgnoresKeyPresses);
else
jassertfalse; // seem to be trying to animate a component that's not visible..
const float scale = (float) Desktop::getInstance().getDisplays()
.getDisplayContaining (getScreenBounds().getCentre()).scale;
auto scale = (float) Desktop::getInstance().getDisplays()
.getDisplayContaining (getScreenBounds().getCentre()).scale;
image = c.createComponentSnapshot (c.getLocalBounds(), false, scale);
@@ -169,6 +179,9 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProxyComponent)
};
WeakReference<AnimationTask>::Master masterReference;
friend class WeakReference<AnimationTask>;
WeakReference<Component> component;
ScopedPointer<Component> proxy;
@@ -187,6 +200,8 @@ private:
: 0.5 * (startSpeed + 0.5 * (midSpeed - startSpeed))
+ (time - 0.5) * (midSpeed + (time - 0.5) * (endSpeed - midSpeed));
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimationTask)
};
//==============================================================================
@@ -216,7 +231,7 @@ void ComponentAnimator::animateComponent (Component* const component,
if (component != nullptr)
{
AnimationTask* at = findTaskFor (component);
auto* at = findTaskFor (component);
if (at == nullptr)
{
@@ -273,7 +288,7 @@ void ComponentAnimator::cancelAllAnimations (const bool moveComponentsToTheirFin
void ComponentAnimator::cancelAnimation (Component* const component,
const bool moveComponentToItsFinalPosition)
{
if (AnimationTask* const at = findTaskFor (component))
if (auto* at = findTaskFor (component))
{
if (moveComponentToItsFinalPosition)
at->moveToFinalDestination();
@@ -287,7 +302,7 @@ Rectangle<int> ComponentAnimator::getComponentDestination (Component* const comp
{
jassert (component != nullptr);
if (AnimationTask* const at = findTaskFor (component))
if (auto* at = findTaskFor (component))
return at->destination;
return component->getBounds();
@@ -305,18 +320,18 @@ bool ComponentAnimator::isAnimating() const noexcept
void ComponentAnimator::timerCallback()
{
const uint32 timeNow = Time::getMillisecondCounter();
auto timeNow = Time::getMillisecondCounter();
if (lastTime == 0 || lastTime == timeNow)
if (lastTime == 0)
lastTime = timeNow;
const int elapsed = (int) (timeNow - lastTime);
auto elapsed = (int) (timeNow - lastTime);
for (int i = tasks.size(); --i >= 0;)
for (auto* task : Array<AnimationTask*> (tasks.begin(), tasks.size()))
{
if (! tasks.getUnchecked(i)->useTimeslice (elapsed))
if (tasks.contains (task) && ! task->useTimeslice (elapsed))
{
tasks.remove (i);
tasks.removeObject (task);
sendChangeMessage();
}
}


Loading…
Cancel
Save