class ComponentAnimator::AnimationTask
{
public:
AnimationTask (Component* c) noexcept : component (c) {}
void reset (const Rectangle<int>& finalBounds,
float finalAlpha,
int millisecondsToSpendMoving,
bool useProxyComponent,
double startSpd, double endSpd)
{
msElapsed = 0;
msTotal = jmax (1, millisecondsToSpendMoving);
lastProgress = 0;
destination = finalBounds;
destAlpha = finalAlpha;
isMoving = (finalBounds != component->getBounds());
isChangingAlpha = (finalAlpha != component->getAlpha());
left = component->getX();
top = component->getY();
right = component->getRight();
bottom = component->getBottom();
alpha = component->getAlpha();
const double invTotalDistance = 4.0 / (startSpd + endSpd + 2.0);
startSpeed = jmax (0.0, startSpd * invTotalDistance);
midSpeed = invTotalDistance;
endSpeed = jmax (0.0, endSpd * invTotalDistance);
if (useProxyComponent)
proxy = new ProxyComponent (*component);
else
proxy = nullptr;
component->setVisible (! useProxyComponent);
}
//这个函数就是进行位置和透明度的变化
bool useTimeslice (const int elapsed)
{
if (Component* const c = proxy != nullptr ? static_cast<Component*> (proxy): static_cast<Component*> (component))
{
msElapsed += elapsed;
double newProgress = msElapsed / (double) msTotal;
if (newProgress >= 0 && newProgress < 1.0)
{
newProgress = timeToDistance (newProgress);
const double delta = (newProgress - lastProgress) / (1.0 - lastProgress);
jassert (newProgress >= lastProgress);
lastProgress = newProgress;
if (delta < 1.0)
{
bool stillBusy = false;
if (isMoving)
{
//偏移位置
left += (destination.getX() - left) * delta;
top += (destination.getY() - top) * delta;
right += (destination.getRight() - right) * delta;
bottom += (destination.getBottom() - bottom) * delta;
const Rectangle<int> newBounds (roundToInt (left),
roundToInt (top),
roundToInt (right - left),
roundToInt (bottom - top));
if (newBounds != destination)
{
c->setBounds (newBounds);
stillBusy = true;
}
}
//偏移透明度
if (isChangingAlpha)
{
alpha += (destAlpha - alpha) * delta;
c->setAlpha ((float) alpha);
stillBusy = true;
}
if (stillBusy)
return true;
}
}
}
moveToFinalDestination();
return false;
}
//移动到结束位置
void moveToFinalDestination()
{
if (component != nullptr)
{
component->setAlpha ((float) destAlpha);
component->setBounds (destination);
if (proxy != nullptr)
component->setVisible (destAlpha > 0);
}
}
//==============================================================================
class ProxyComponent : public Component
{
public:
ProxyComponent (Component& c)
{
setWantsKeyboardFocus (false);
setBounds (c.getBounds());
setTransform (c.getTransform());
setAlpha (c.getAlpha());
setInterceptsMouseClicks (false, false);
if (Component* const 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;
image = c.createComponentSnapshot (c.getLocalBounds(), false, scale);
setVisible (true);
toBehind (&c);
}
void paint (Graphics& g) override
{
g.setOpacity (1.0f);
g.drawImageTransformed (image, AffineTransform::scale (getWidth() / (float) image.getWidth(),
getHeight() / (float) image.getHeight()), false);
}
private:
Image image;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProxyComponent)
};
WeakReference<Component> component;//移动的控件
ScopedPointer<Component> proxy; //代理,也就是用一张图来显示控件内容
Rectangle<int> destination; //目标位置
double destAlpha; //透明度
int msElapsed, msTotal; //使用了多少时间
double startSpeed, midSpeed, endSpeed, lastProgress; //计算得到的几个速度
double left, top, right, bottom, alpha;
bool isMoving, isChangingAlpha;
private:
//这里的时间是限制在0到1之间?
double timeToDistance (const double time) const noexcept
{
return (time < 0.5) ? time * (startSpeed + time * (midSpeed - startSpeed))
: 0.5 * (startSpeed + 0.5 * (midSpeed - startSpeed))
+ (time - 0.5) * (midSpeed + (time - 0.5) * (endSpeed - midSpeed));
}
};