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: public:
AnimationTask (Component* c) noexcept : component (c) {} AnimationTask (Component* c) noexcept : component (c) {}
~AnimationTask()
{
masterReference.clear();
}
void reset (const Rectangle<int>& finalBounds, void reset (const Rectangle<int>& finalBounds,
float finalAlpha, float finalAlpha,
int millisecondsToSpendMoving, int millisecondsToSpendMoving,
@@ -63,14 +68,15 @@ public:
bool useTimeslice (const int elapsed) 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; msElapsed += elapsed;
double newProgress = msElapsed / (double) msTotal; double newProgress = msElapsed / (double) msTotal;
if (newProgress >= 0 && newProgress < 1.0) if (newProgress >= 0 && newProgress < 1.0)
{ {
const WeakReference<AnimationTask> weakRef (this);
newProgress = timeToDistance (newProgress); newProgress = timeToDistance (newProgress);
const double delta = (newProgress - lastProgress) / (1.0 - lastProgress); const double delta = (newProgress - lastProgress) / (1.0 - lastProgress);
jassert (newProgress >= 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) if (isChangingAlpha)
{ {
alpha += (destAlpha - alpha) * delta; alpha += (destAlpha - alpha) * delta;
@@ -129,9 +140,8 @@ public:
} }
//============================================================================== //==============================================================================
class ProxyComponent : public Component
struct ProxyComponent : public Component
{ {
public:
ProxyComponent (Component& c) ProxyComponent (Component& c)
{ {
setWantsKeyboardFocus (false); setWantsKeyboardFocus (false);
@@ -140,15 +150,15 @@ public:
setAlpha (c.getAlpha()); setAlpha (c.getAlpha());
setInterceptsMouseClicks (false, false); setInterceptsMouseClicks (false, false);
if (Component* const parent = c.getParentComponent())
if (auto* parent = c.getParentComponent())
parent->addAndMakeVisible (this); parent->addAndMakeVisible (this);
else if (c.isOnDesktop() && c.getPeer() != nullptr) else if (c.isOnDesktop() && c.getPeer() != nullptr)
addToDesktop (c.getPeer()->getStyleFlags() | ComponentPeer::windowIgnoresKeyPresses); addToDesktop (c.getPeer()->getStyleFlags() | ComponentPeer::windowIgnoresKeyPresses);
else else
jassertfalse; // seem to be trying to animate a component that's not visible.. 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); image = c.createComponentSnapshot (c.getLocalBounds(), false, scale);
@@ -169,6 +179,9 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProxyComponent) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProxyComponent)
}; };
WeakReference<AnimationTask>::Master masterReference;
friend class WeakReference<AnimationTask>;
WeakReference<Component> component; WeakReference<Component> component;
ScopedPointer<Component> proxy; ScopedPointer<Component> proxy;
@@ -187,6 +200,8 @@ private:
: 0.5 * (startSpeed + 0.5 * (midSpeed - startSpeed)) : 0.5 * (startSpeed + 0.5 * (midSpeed - startSpeed))
+ (time - 0.5) * (midSpeed + (time - 0.5) * (endSpeed - midSpeed)); + (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) if (component != nullptr)
{ {
AnimationTask* at = findTaskFor (component);
auto* at = findTaskFor (component);
if (at == nullptr) if (at == nullptr)
{ {
@@ -273,7 +288,7 @@ void ComponentAnimator::cancelAllAnimations (const bool moveComponentsToTheirFin
void ComponentAnimator::cancelAnimation (Component* const component, void ComponentAnimator::cancelAnimation (Component* const component,
const bool moveComponentToItsFinalPosition) const bool moveComponentToItsFinalPosition)
{ {
if (AnimationTask* const at = findTaskFor (component))
if (auto* at = findTaskFor (component))
{ {
if (moveComponentToItsFinalPosition) if (moveComponentToItsFinalPosition)
at->moveToFinalDestination(); at->moveToFinalDestination();
@@ -287,7 +302,7 @@ Rectangle<int> ComponentAnimator::getComponentDestination (Component* const comp
{ {
jassert (component != nullptr); jassert (component != nullptr);
if (AnimationTask* const at = findTaskFor (component))
if (auto* at = findTaskFor (component))
return at->destination; return at->destination;
return component->getBounds(); return component->getBounds();
@@ -305,18 +320,18 @@ bool ComponentAnimator::isAnimating() const noexcept
void ComponentAnimator::timerCallback() void ComponentAnimator::timerCallback()
{ {
const uint32 timeNow = Time::getMillisecondCounter();
auto timeNow = Time::getMillisecondCounter();
if (lastTime == 0 || lastTime == timeNow)
if (lastTime == 0)
lastTime = timeNow; 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(); sendChangeMessage();
} }
} }


Loading…
Cancel
Save