Initial release
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "animations.h"
|
||||
#include "../cview.h"
|
||||
#include "../cframe.h"
|
||||
#include "../controls/ccontrol.h"
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
//------------------------------------------------------------------------
|
||||
/*! @defgroup AnimationTargets Animation Targets
|
||||
* @ingroup animation
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
/** @class AlphaValueAnimation
|
||||
see @ref page_animation Support */
|
||||
//-----------------------------------------------------------------------------
|
||||
AlphaValueAnimation::AlphaValueAnimation (float endValue, bool forceEndValueOnFinish)
|
||||
: startValue (0.f)
|
||||
, endValue (endValue)
|
||||
, forceEndValueOnFinish (forceEndValueOnFinish)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void AlphaValueAnimation::animationStart (CView* view, IdStringPtr name)
|
||||
{
|
||||
startValue = view->getAlphaValue ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void AlphaValueAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
float alpha = startValue + (endValue - startValue) * pos;
|
||||
view->setAlphaValue (alpha);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void AlphaValueAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
if (!wasCanceled || forceEndValueOnFinish)
|
||||
view->setAlphaValue (endValue);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** @class ViewSizeAnimation
|
||||
see @ref page_animation Support */
|
||||
//-----------------------------------------------------------------------------
|
||||
ViewSizeAnimation::ViewSizeAnimation (const CRect& inNewRect, bool forceEndValueOnFinish)
|
||||
: newRect (inNewRect)
|
||||
, forceEndValueOnFinish (forceEndValueOnFinish)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ViewSizeAnimation::animationStart (CView* view, IdStringPtr name)
|
||||
{
|
||||
startRect = view->getViewSize ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ViewSizeAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
if (!wasCanceled || forceEndValueOnFinish)
|
||||
{
|
||||
if (view->getViewSize () != newRect)
|
||||
{
|
||||
view->invalid ();
|
||||
view->setViewSize (newRect);
|
||||
view->setMouseableArea (view->getViewSize ());
|
||||
view->invalid ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ViewSizeAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
CRect r;
|
||||
r.left = (int32_t)(startRect.left + ((newRect.left - startRect.left) * pos));
|
||||
r.right = (int32_t)(startRect.right + ((newRect.right - startRect.right) * pos));
|
||||
r.top = (int32_t)(startRect.top + ((newRect.top - startRect.top) * pos));
|
||||
r.bottom = (int32_t)(startRect.bottom + ((newRect.bottom - startRect.bottom) * pos));
|
||||
if (view->getViewSize () != r)
|
||||
{
|
||||
view->invalid ();
|
||||
view->setViewSize (r);
|
||||
view->setMouseableArea (view->getViewSize ());
|
||||
view->invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** @class ExchangeViewAnimation
|
||||
see @ref page_animation Support */
|
||||
//-----------------------------------------------------------------------------
|
||||
ExchangeViewAnimation::ExchangeViewAnimation (CView* oldView, CView* newView, AnimationStyle style)
|
||||
: newView (newView)
|
||||
, viewToRemove (oldView)
|
||||
, style (style)
|
||||
{
|
||||
vstgui_assert (newView->isAttached () == false);
|
||||
vstgui_assert (viewToRemove->isAttached ());
|
||||
|
||||
if (auto parent = viewToRemove->getParentView ()->asViewContainer ())
|
||||
parent->addView (newView);
|
||||
|
||||
init ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ExchangeViewAnimation::~ExchangeViewAnimation () noexcept
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::updateViewSize (CView* view, const CRect& rect)
|
||||
{
|
||||
view->invalid ();
|
||||
view->setViewSize (rect);
|
||||
view->setMouseableArea (rect);
|
||||
view->invalid ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::init ()
|
||||
{
|
||||
if (style == kAlphaValueFade)
|
||||
{
|
||||
oldViewAlphaValueStart = viewToRemove->getAlphaValue ();
|
||||
newViewAlphaValueEnd = newView->getAlphaValue ();
|
||||
newView->setAlphaValue (0.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
destinationRect = viewToRemove->getViewSize ();
|
||||
switch (style)
|
||||
{
|
||||
case kAlphaValueFade: break;
|
||||
case kPushInFromLeft:
|
||||
{
|
||||
doPushInFromLeft (0.f);
|
||||
break;
|
||||
}
|
||||
case kPushInFromRight:
|
||||
{
|
||||
doPushInFromRight (0.f);
|
||||
break;
|
||||
}
|
||||
case kPushInFromTop:
|
||||
{
|
||||
doPushInFromTop (0.f);
|
||||
break;
|
||||
}
|
||||
case kPushInFromBottom:
|
||||
{
|
||||
doPushInFromBottom (0.f);
|
||||
break;
|
||||
}
|
||||
case kPushInOutFromLeft:
|
||||
{
|
||||
doPushInOutFromLeft (0.f);
|
||||
break;
|
||||
}
|
||||
case kPushInOutFromRight:
|
||||
{
|
||||
doPushInOutFromRight (0.f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doAlphaFade (float pos)
|
||||
{
|
||||
float alpha = oldViewAlphaValueStart - (oldViewAlphaValueStart * pos);
|
||||
viewToRemove->setAlphaValue (alpha);
|
||||
alpha = newViewAlphaValueEnd * pos;
|
||||
newView->setAlphaValue (alpha);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInFromLeft (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord leftOrigin = destinationRect.left;
|
||||
CCoord offset = viewSize.getWidth () * (1.f - pos);
|
||||
viewSize.offset (-viewSize.left, 0);
|
||||
viewSize.offset (leftOrigin - offset, 0);
|
||||
updateViewSize (newView, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInFromRight (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord rightOrigin = destinationRect.left + destinationRect.getWidth ();
|
||||
CCoord offset = viewSize.getWidth () * pos;
|
||||
viewSize.offset (-viewSize.left, 0);
|
||||
viewSize.offset (rightOrigin - offset, 0);
|
||||
updateViewSize (newView, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInFromTop (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord topOrigin = destinationRect.top;
|
||||
CCoord offset = viewSize.getHeight () * (1.f - pos);
|
||||
viewSize.offset (0, -viewSize.top);
|
||||
viewSize.offset (0, topOrigin - offset);
|
||||
updateViewSize (newView, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInFromBottom (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord bottomOrigin = destinationRect.top + destinationRect.getHeight ();
|
||||
CCoord offset = viewSize.getHeight () * pos;
|
||||
viewSize.offset (0, -viewSize.top);
|
||||
viewSize.offset (0, bottomOrigin - offset);
|
||||
updateViewSize (newView, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInOutFromLeft (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord offset = viewSize.getWidth () * (1.f - pos);
|
||||
viewSize.offset (-viewSize.left, 0);
|
||||
viewSize.offset (destinationRect.left - offset, 0);
|
||||
updateViewSize (newView, viewSize);
|
||||
|
||||
offset = viewToRemove->getWidth () * pos;
|
||||
viewSize = destinationRect;
|
||||
viewSize.offset (offset, 0);
|
||||
updateViewSize (viewToRemove, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::doPushInOutFromRight (float pos)
|
||||
{
|
||||
CRect viewSize (newView->getViewSize ());
|
||||
CCoord offset = viewSize.getWidth () * pos;
|
||||
viewSize.offset (-viewSize.left, 0);
|
||||
viewSize.offset ((destinationRect.left + destinationRect.getWidth ()) - offset, 0);
|
||||
updateViewSize (newView, viewSize);
|
||||
|
||||
offset = viewToRemove->getWidth () * pos;
|
||||
viewSize = destinationRect;
|
||||
viewSize.offset (-offset, 0);
|
||||
updateViewSize (viewToRemove, viewSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::animationStart (CView* view, IdStringPtr name)
|
||||
{
|
||||
#if DEBUG
|
||||
CViewContainer* parent = viewToRemove->getParentView ()->asViewContainer ();
|
||||
vstgui_assert (view == parent);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case kAlphaValueFade:
|
||||
{
|
||||
doAlphaFade (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInFromLeft:
|
||||
{
|
||||
doPushInFromLeft (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInFromRight:
|
||||
{
|
||||
doPushInFromRight (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInFromTop:
|
||||
{
|
||||
doPushInFromTop (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInFromBottom:
|
||||
{
|
||||
doPushInFromBottom (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInOutFromLeft:
|
||||
{
|
||||
doPushInOutFromLeft (pos);
|
||||
break;
|
||||
}
|
||||
case kPushInOutFromRight:
|
||||
{
|
||||
doPushInOutFromRight (pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ExchangeViewAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
animationTick (nullptr, nullptr, 1.f);
|
||||
if (auto viewContainer = viewToRemove->getParentView ()->asViewContainer ())
|
||||
{
|
||||
viewContainer->removeView (viewToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** @class ControlValueAnimation
|
||||
see @ref page_animation Support */
|
||||
//-----------------------------------------------------------------------------
|
||||
ControlValueAnimation::ControlValueAnimation (float endValue, bool forceEndValueOnFinish)
|
||||
: startValue (0.f)
|
||||
, endValue (endValue)
|
||||
, forceEndValueOnFinish (forceEndValueOnFinish)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ControlValueAnimation::animationStart (CView* view, IdStringPtr name)
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*> (view);
|
||||
if (control)
|
||||
startValue = control->getValue ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ControlValueAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*> (view);
|
||||
if (control)
|
||||
{
|
||||
float value = startValue + (endValue - startValue) * pos;
|
||||
control->setValue (value);
|
||||
if (control->isDirty ())
|
||||
control->invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ControlValueAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*> (view);
|
||||
if (control)
|
||||
{
|
||||
if (!wasCanceled || forceEndValueOnFinish)
|
||||
control->setValue (endValue);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
FuncAnimation::FuncAnimation (StartFunc&& start, TickFunc&& tick, FinishedFunc&& finished)
|
||||
: start (std::move (start)), tick (std::move (tick)), finished (std::move (finished))
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void FuncAnimation::animationStart (CView* view, IdStringPtr name) { start (view, name); }
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void FuncAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
tick (view, name, pos);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void FuncAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
finished (view, name, wasCanceled);
|
||||
}
|
||||
}} // namespaces
|
||||
@@ -0,0 +1,144 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguifwd.h"
|
||||
#include "ianimationtarget.h"
|
||||
#include "../crect.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief animates the alpha value of the view
|
||||
/// @ingroup AnimationTargets
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class AlphaValueAnimation : public IAnimationTarget, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
AlphaValueAnimation (float endValue, bool forceEndValueOnFinish = false);
|
||||
|
||||
void animationStart (CView* view, IdStringPtr name) override;
|
||||
void animationTick (CView* view, IdStringPtr name, float pos) override;
|
||||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override;
|
||||
protected:
|
||||
float startValue;
|
||||
float endValue;
|
||||
bool forceEndValueOnFinish;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief animates the view size of the view
|
||||
/// @ingroup AnimationTargets
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class ViewSizeAnimation : public IAnimationTarget, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
ViewSizeAnimation (const CRect& newRect, bool forceEndValueOnFinish = false);
|
||||
|
||||
void animationStart (CView* view, IdStringPtr name) override;
|
||||
void animationTick (CView* view, IdStringPtr name, float pos) override;
|
||||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override;
|
||||
protected:
|
||||
CRect startRect;
|
||||
CRect newRect;
|
||||
bool forceEndValueOnFinish;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief exchange a view by another view with an animation
|
||||
/// @ingroup AnimationTargets
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class ExchangeViewAnimation : public IAnimationTarget, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
enum AnimationStyle {
|
||||
kAlphaValueFade = 0,
|
||||
kPushInFromLeft,
|
||||
kPushInFromRight,
|
||||
kPushInFromTop,
|
||||
kPushInFromBottom,
|
||||
kPushInOutFromLeft,
|
||||
kPushInOutFromRight
|
||||
};
|
||||
|
||||
/** oldView must be a subview of the animation view */
|
||||
ExchangeViewAnimation (CView* oldView, CView* newView, AnimationStyle style = kAlphaValueFade);
|
||||
~ExchangeViewAnimation () noexcept override;
|
||||
|
||||
void animationStart (CView* view, IdStringPtr name) override;
|
||||
void animationTick (CView* view, IdStringPtr name, float pos) override;
|
||||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override;
|
||||
protected:
|
||||
|
||||
void init ();
|
||||
void doAlphaFade (float pos);
|
||||
void doPushInFromLeft (float pos);
|
||||
void doPushInFromRight (float pos);
|
||||
void doPushInFromTop (float pos);
|
||||
void doPushInFromBottom (float pos);
|
||||
void doPushInOutFromLeft (float pos);
|
||||
void doPushInOutFromRight (float pos);
|
||||
|
||||
void updateViewSize (CView* view, const CRect& rect);
|
||||
|
||||
SharedPointer<CView> newView;
|
||||
SharedPointer<CView> viewToRemove;
|
||||
AnimationStyle style;
|
||||
float newViewAlphaValueEnd;
|
||||
float oldViewAlphaValueStart;
|
||||
CRect destinationRect;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief animates the value of a CControl
|
||||
/// @ingroup AnimationTargets
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class ControlValueAnimation : public IAnimationTarget, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
ControlValueAnimation (float endValue, bool forceEndValueOnFinish = false);
|
||||
|
||||
void animationStart (CView* view, IdStringPtr name) override;
|
||||
void animationTick (CView* view, IdStringPtr name, float pos) override;
|
||||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override;
|
||||
protected:
|
||||
float startValue;
|
||||
float endValue;
|
||||
bool forceEndValueOnFinish;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/// @brief animation via custom functions
|
||||
/// @ingroup AnimationTargets
|
||||
/// @ingroup new_in_4_14
|
||||
//------------------------------------------------------------------------
|
||||
class FuncAnimation : public IAnimationTarget,
|
||||
public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
using StartFunc = std::function<void (CView*, IdStringPtr)>;
|
||||
using TickFunc = std::function<void (CView*, IdStringPtr, float)>;
|
||||
using FinishedFunc = std::function<void (CView*, IdStringPtr, bool)>;
|
||||
|
||||
FuncAnimation (StartFunc&& start, TickFunc&& tick, FinishedFunc&& finished);
|
||||
|
||||
void animationStart (CView* view, IdStringPtr name) override;
|
||||
void animationTick (CView* view, IdStringPtr name, float pos) override;
|
||||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override;
|
||||
|
||||
private:
|
||||
StartFunc start;
|
||||
TickFunc tick;
|
||||
FinishedFunc finished;
|
||||
};
|
||||
|
||||
} // Animation
|
||||
} // VSTGUI
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
/**
|
||||
@page page_animation Animations
|
||||
|
||||
VSTGUI version 4 adds simple to use view animation support.
|
||||
|
||||
The source can be found under /lib/animation/
|
||||
|
||||
@section the_animator The Animator
|
||||
Every @link VSTGUI::CFrame::getAnimator CFrame @endlink object can have one @link VSTGUI::Animation::Animator Animator @endlink object which runs animations at 60 Hz.
|
||||
|
||||
The animator is responsible for running animations.
|
||||
You can add and remove animations.
|
||||
Animations are identified by a view and a name.
|
||||
|
||||
To add an animation you just call @link VSTGUI::CView::addAnimation CView::addAnimation (name, target, timing)@endlink.
|
||||
The animation will start immediately and will automatically be removed if it has finished.
|
||||
If you want to stop it before it has finished you can use @link VSTGUI::CView::removeAnimation CView::removeAnimation (name)@endlink.
|
||||
You can also stop all animations for a view with @link VSTGUI::CView::removeAllAnimations CView::removeAllAnimations ()@endlink.
|
||||
|
||||
The animator is the owner of the target and timing function objects and will destroy these objects when the animation has finished.
|
||||
This means that the animator will call delete on these objects or if they are inherited from CBaseObject it will call forget() on them.
|
||||
|
||||
@section the_animation The Animation
|
||||
|
||||
An animation is made up by an @link VSTGUI::Animation::IAnimationTarget IAnimationTarget @endlink and an @link VSTGUI::Animation::ITimingFunction ITimingFunction @endlink object.
|
||||
|
||||
@subsection animation_target The Animation Target
|
||||
The animation target is responsible for changing the view from one state to another state.
|
||||
|
||||
The animation target interface consists of 3 methods:
|
||||
- @link VSTGUI::Animation::IAnimationTarget::animationStart animationStart (view, name) @endlink
|
||||
- @link VSTGUI::Animation::IAnimationTarget::animationTick animationTick (view, name, pos) @endlink
|
||||
- @link VSTGUI::Animation::IAnimationTarget::animationFinished animationFinished (view, name, wasCanceled) @endlink
|
||||
|
||||
All these methods have the view and the animation name as arguments to identify the animation within the target.
|
||||
The animationTick method in addition has the normalized animation position as argument and the animationFinished method has a bool argument indicating if the animation was canceled.
|
||||
|
||||
see @link AnimationTargets included animation target classes @endlink
|
||||
|
||||
@subsection animation_timing The Animation Timing Function
|
||||
the animation timing function maps elapsed time to a normalized position.
|
||||
|
||||
see @link AnimationTimingFunctions included animation timing function classes @endlink
|
||||
|
||||
@section simple_example Simple Usage Example
|
||||
In this example the custom view animates it's alpha value when the mouse moves inside or outside the view.
|
||||
|
||||
@code
|
||||
|
||||
using namespace VSTGUI::Animation;
|
||||
|
||||
class MyView : public CView
|
||||
{
|
||||
public:
|
||||
MyView (const CRect& r) : CView (r) { setAlphaValue (0.5f); }
|
||||
|
||||
CMouseEventResult onMouseEntered (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
// this adds an animation which takes 200 ms to make a linear alpha fade from the current value to 1
|
||||
addAnimation ("AlphaValueAnimation", new AlphaValueAnimation (1.f), new LinearTimingFunction (200));
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
CMouseEventResult onMouseExited (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
// this adds an animation which takes 200 ms to make a linear alpha fade from the current value to 0.5
|
||||
addAnimation ("AlphaValueAnimation", new AlphaValueAnimation (0.5f), new LinearTimingFunction (200));
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
void draw (CDrawContext* context)
|
||||
{
|
||||
// ... any drawing code here
|
||||
}
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*! @defgroup animation Animation
|
||||
see @ref page_animation
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "animator.h"
|
||||
#include "ianimationtarget.h"
|
||||
#include "itimingfunction.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include "../cview.h"
|
||||
#include "../dispatchlist.h"
|
||||
#include "../platform/platformfactory.h"
|
||||
#include <list>
|
||||
|
||||
#define DEBUG_LOG 0 // DEBUG
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
///@cond ignore
|
||||
namespace Detail {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class Timer : public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
static void addAnimator (Animator* animator)
|
||||
{
|
||||
getInstance ()->animators.emplace_back (animator);
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("Animator added: %p\n", animator);
|
||||
#endif
|
||||
}
|
||||
static void removeAnimator (Animator* animator)
|
||||
{
|
||||
if (gInstance)
|
||||
{
|
||||
if (getInstance ()->inTimer)
|
||||
{
|
||||
gInstance->toRemove.emplace_back (animator);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("Animator removed: %p\n", animator);
|
||||
#endif
|
||||
gInstance->animators.remove (animator);
|
||||
if (gInstance->animators.empty ())
|
||||
{
|
||||
gInstance->forget ();
|
||||
gInstance = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
static Timer* getInstance ()
|
||||
{
|
||||
if (gInstance == nullptr)
|
||||
gInstance = new Timer;
|
||||
return gInstance;
|
||||
}
|
||||
|
||||
Timer ()
|
||||
: inTimer (false)
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("Animation timer started\n");
|
||||
#endif
|
||||
timer = new CVSTGUITimer ([this] (CVSTGUITimer*) {
|
||||
onTimer ();
|
||||
}, 1000/60); // 60 Hz
|
||||
}
|
||||
|
||||
~Timer () noexcept override
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("Animation timer stopped\n");
|
||||
#endif
|
||||
timer->forget ();
|
||||
gInstance = nullptr;
|
||||
}
|
||||
|
||||
void onTimer ()
|
||||
{
|
||||
inTimer = true;
|
||||
auto guard = shared (this);
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("Current Animators : %d\n", animators.size ());
|
||||
#endif
|
||||
for (auto& animator : animators)
|
||||
animator->onTimer ();
|
||||
inTimer = false;
|
||||
for (auto& animator : toRemove)
|
||||
removeAnimator (animator);
|
||||
toRemove.clear ();
|
||||
}
|
||||
|
||||
CVSTGUITimer* timer;
|
||||
|
||||
using Animators = std::list<Animator*>;
|
||||
Animators animators;
|
||||
Animators toRemove;
|
||||
bool inTimer;
|
||||
static Timer* gInstance;
|
||||
};
|
||||
Timer* Timer::gInstance = nullptr;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class Animation : public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
Animation (CView* view, const std::string& name, IAnimationTarget* at, ITimingFunction* t,
|
||||
DoneFunction&& notification, bool notifyOnCancel);
|
||||
~Animation () noexcept override;
|
||||
|
||||
std::string name;
|
||||
SharedPointer<CView> view;
|
||||
IAnimationTarget* animationTarget;
|
||||
ITimingFunction* timingFunction;
|
||||
DoneFunction notification;
|
||||
uint64_t startTime {0};
|
||||
float lastPos {-1.};
|
||||
bool done {false};
|
||||
bool notifyOnCancel;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Animation::Animation (CView* view, const std::string& name, IAnimationTarget* at,
|
||||
ITimingFunction* t, DoneFunction&& notification, bool notifyOnCancel)
|
||||
: name (name)
|
||||
, view (view)
|
||||
, animationTarget (at)
|
||||
, timingFunction (t)
|
||||
, notification (std::move (notification))
|
||||
, notifyOnCancel (notifyOnCancel)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Animation::~Animation () noexcept
|
||||
{
|
||||
if (notification)
|
||||
notification (view, name.c_str (), animationTarget);
|
||||
if (auto obj = dynamic_cast<IReference*> (animationTarget))
|
||||
obj->forget ();
|
||||
else
|
||||
delete animationTarget;
|
||||
if (auto obj = dynamic_cast<IReference*> (timingFunction))
|
||||
obj->forget ();
|
||||
else
|
||||
delete timingFunction;
|
||||
}
|
||||
|
||||
} // Detail
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct Animator::Impl
|
||||
{
|
||||
DispatchList<SharedPointer<Detail::Animation>> animations;
|
||||
};
|
||||
///@endcond
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Animator::Animator ()
|
||||
{
|
||||
pImpl = std::unique_ptr<Impl> (new Impl ());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Animator::~Animator () noexcept
|
||||
{
|
||||
Detail::Timer::removeAnimator (this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Animator::addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target,
|
||||
ITimingFunction* timingFunction, DoneFunction notification,
|
||||
bool notifyOnCancel)
|
||||
{
|
||||
if (pImpl->animations.empty ())
|
||||
Detail::Timer::addAnimator (this);
|
||||
removeAnimation (view, name);
|
||||
pImpl->animations.add (makeOwned<Detail::Animation> (view, name, target, timingFunction,
|
||||
std::move (notification), notifyOnCancel));
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("new animation added: %p - %s\n", view, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//-----------------------------------------------------------------------------
|
||||
void Animator::addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, ITimingFunction* timingFunction, CBaseObject* notificationObject)
|
||||
{
|
||||
DoneFunction notification;
|
||||
if (notificationObject)
|
||||
{
|
||||
SharedPointer<CBaseObject> nObj (notificationObject);
|
||||
notification = [nObj] (CView* view, const IdStringPtr name, IAnimationTarget* target) {
|
||||
FinishedMessage fmsg (view, name, target);
|
||||
nObj->notify (&fmsg, kMsgAnimationFinished);
|
||||
};
|
||||
}
|
||||
addAnimation (view, name, target, timingFunction, std::move (notification));
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Animator::removeAnimation (CView* view, IdStringPtr name)
|
||||
{
|
||||
pImpl->animations.forEach ([&] (const SharedPointer<Detail::Animation>& animation) {
|
||||
if (animation->view == view && animation->name == name)
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("animation removed: %p - %s\n", view, name);
|
||||
#endif
|
||||
if (animation->done == false)
|
||||
{
|
||||
animation->done = true;
|
||||
animation->animationTarget->animationFinished (view, name, true);
|
||||
}
|
||||
if (!animation->notifyOnCancel)
|
||||
animation->notification = nullptr;
|
||||
pImpl->animations.remove (animation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Animator::removeAnimations (CView* view)
|
||||
{
|
||||
pImpl->animations.forEach ([&] (const SharedPointer<Detail::Animation>& animation) {
|
||||
if (animation->view == view)
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("animation removed: %p - %s\n", view, animation->name.data ());
|
||||
#endif
|
||||
if (animation->done == false)
|
||||
{
|
||||
animation->done = true;
|
||||
animation->animationTarget->animationFinished (view, animation->name.data (), true);
|
||||
}
|
||||
pImpl->animations.remove (animation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Animator::onTimer ()
|
||||
{
|
||||
auto selfGuard = shared (this);
|
||||
auto currentTicks = getPlatformFactory ().getTicks ();
|
||||
pImpl->animations.forEach ([&] (SharedPointer<Detail::Animation>& animation) {
|
||||
if (animation->startTime == 0)
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("animation start: %p - %s\n", animation->view.cast<CView>(), animation->name.data ());
|
||||
#endif
|
||||
animation->animationTarget->animationStart (animation->view, animation->name.data ());
|
||||
animation->startTime = currentTicks;
|
||||
}
|
||||
uint32_t time = static_cast<uint32_t> (currentTicks - animation->startTime);
|
||||
float pos = animation->timingFunction->getPosition (time);
|
||||
if (pos != animation->lastPos)
|
||||
{
|
||||
animation->animationTarget->animationTick (animation->view, animation->name.data (), pos);
|
||||
animation->lastPos = pos;
|
||||
}
|
||||
if (animation->timingFunction->isDone (time))
|
||||
{
|
||||
animation->done = true;
|
||||
animation->animationTarget->animationFinished (animation->view, animation->name.data (), false);
|
||||
#if DEBUG_LOG
|
||||
DebugPrint ("animation finished: %p - %s\n", animation->view.cast<CView>(), animation->name.data ());
|
||||
#endif
|
||||
pImpl->animations.remove (animation);
|
||||
}
|
||||
});
|
||||
if (pImpl->animations.empty ())
|
||||
Detail::Timer::removeAnimator (this);
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
IdStringPtr kMsgAnimationFinished = "kMsgAnimationFinished";
|
||||
#endif
|
||||
|
||||
}} // namespaces
|
||||
@@ -0,0 +1,95 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguifwd.h"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Animation runner
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class Animator : public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name Adding and removing Animations
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
VSTGUI_DEPRECATED(
|
||||
/** adds an animation.
|
||||
Animation and timingFunction is now owned by the animator.
|
||||
An already running animation for view with name will be canceled.
|
||||
If a notificationObject is supplied, it will be notified when the animation has finished @see FinishedMessage.
|
||||
*/
|
||||
void addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, ITimingFunction* timingFunction, CBaseObject* notificationObject);)
|
||||
|
||||
/** adds an animation.
|
||||
Animation and timingFunction is now owned by the animator.
|
||||
An already running animation for view with name will be canceled.
|
||||
The notification function will be called when the animation has finished or on cancelation
|
||||
of the animation if notifyOnCancel is true (new in 4.11)
|
||||
*/
|
||||
void addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target,
|
||||
ITimingFunction* timingFunction, DoneFunction notification = nullptr,
|
||||
bool notifyOnCancel = false);
|
||||
|
||||
/** removes an animation.
|
||||
If animation has the IReference interface forget() will be called otherwise it is deleted.
|
||||
The same will be done with the timingFunction.
|
||||
*/
|
||||
void removeAnimation (CView* view, IdStringPtr name);
|
||||
|
||||
/** removes all animations for view */
|
||||
void removeAnimations (CView* view);
|
||||
//@}
|
||||
|
||||
/// @cond ignore
|
||||
|
||||
Animator (); // do not use this, instead use CFrame::getAnimator()
|
||||
void onTimer ();
|
||||
|
||||
protected:
|
||||
~Animator () noexcept override;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pImpl;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
/** message sent to the notificationObject when the animation has finished, the sender parameter will be a FinishedMessage object. */
|
||||
extern IdStringPtr kMsgAnimationFinished;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Animation Finished Message Object
|
||||
///
|
||||
/// The FinishedMessage will be sent to the notificationObject when the animation has finished
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class FinishedMessage : public CBaseObject
|
||||
{
|
||||
public:
|
||||
FinishedMessage (CView* view, const std::string& name, IAnimationTarget* target) : view (view), name (name), target (target) {}
|
||||
|
||||
CView* getView () const { return view; }
|
||||
IdStringPtr getName () const { return name.c_str (); }
|
||||
IAnimationTarget* getTarget () const { return target; }
|
||||
|
||||
CLASS_METHODS_NOCOPY(FinishedMessage, CBaseObject)
|
||||
protected:
|
||||
CView* view;
|
||||
const std::string& name;
|
||||
IAnimationTarget* target;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // Animation
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguifwd.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Animation target interface
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class IAnimationTarget
|
||||
{
|
||||
public:
|
||||
virtual ~IAnimationTarget () noexcept = default;
|
||||
|
||||
/** animation starts */
|
||||
virtual void animationStart (CView* view, IdStringPtr name) = 0;
|
||||
/** pos is a normalized value between zero and one */
|
||||
virtual void animationTick (CView* view, IdStringPtr name, float pos) = 0;
|
||||
/** animation ended */
|
||||
virtual void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) = 0;
|
||||
};
|
||||
|
||||
} // Animation
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,26 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguibase.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Animation timing function interface
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class ITimingFunction
|
||||
{
|
||||
public:
|
||||
virtual ~ITimingFunction () noexcept = default;
|
||||
|
||||
virtual float getPosition (uint32_t milliseconds) = 0;
|
||||
virtual bool isDone (uint32_t milliseconds) = 0;
|
||||
};
|
||||
|
||||
} // Animation
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,219 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "timingfunctions.h"
|
||||
#include "../vstguibase.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*! @defgroup AnimationTimingFunctions Animation Timing Functions
|
||||
* @ingroup animation
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
LinearTimingFunction::LinearTimingFunction (uint32_t length)
|
||||
: TimingFunctionBase (length)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float LinearTimingFunction::getPosition (uint32_t milliseconds)
|
||||
{
|
||||
float pos = ((float)milliseconds) / ((float)length);
|
||||
if (pos > 1.f)
|
||||
pos = 1.f;
|
||||
else if (pos < 0.f)
|
||||
pos = 0.f;
|
||||
return pos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
PowerTimingFunction::PowerTimingFunction (uint32_t length, float factor)
|
||||
: TimingFunctionBase (length)
|
||||
, factor (factor)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float PowerTimingFunction::getPosition (uint32_t milliseconds)
|
||||
{
|
||||
float pos = ((float)milliseconds) / ((float)length);
|
||||
pos = std::pow (pos, factor);
|
||||
if (pos > 1.f)
|
||||
pos = 1.f;
|
||||
else if (pos < 0.f)
|
||||
pos = 0.f;
|
||||
return pos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
InterpolationTimingFunction::InterpolationTimingFunction (uint32_t length, float startPos, float endPos)
|
||||
: TimingFunctionBase (length)
|
||||
{
|
||||
addPoint (0.f, startPos);
|
||||
addPoint (1.f, endPos);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void InterpolationTimingFunction::addPoint (float time, float pos)
|
||||
{
|
||||
points.emplace ((uint32_t)((float)getLength () * time), pos);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float InterpolationTimingFunction::getPosition (uint32_t milliseconds)
|
||||
{
|
||||
uint32_t prevTime = getLength ();
|
||||
float prevPos = points[prevTime];
|
||||
PointMap::reverse_iterator it = points.rbegin ();
|
||||
while (it != points.rend ())
|
||||
{
|
||||
uint32_t time = it->first;
|
||||
float pos = it->second;
|
||||
if (time == milliseconds)
|
||||
return pos;
|
||||
else if (time <= milliseconds && prevTime > milliseconds)
|
||||
{
|
||||
double timePos = (double)(milliseconds - time) / (double)(prevTime - time);
|
||||
return static_cast<float> (static_cast<double> (pos) + ((static_cast<double> (prevPos) - static_cast<double> (pos)) * timePos));
|
||||
}
|
||||
prevTime = time;
|
||||
prevPos = pos;
|
||||
++it;
|
||||
}
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction::CubicBezierTimingFunction (uint32_t milliseconds, CPoint p1, CPoint p2)
|
||||
: TimingFunctionBase (milliseconds), p1 (p1), p2 (p2)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CPoint CubicBezierTimingFunction::lerp (CPoint p1, CPoint p2, float pos)
|
||||
{
|
||||
return p1 * (1.f - pos) + p2 * pos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float CubicBezierTimingFunction::getPosition (uint32_t milliseconds)
|
||||
{
|
||||
constexpr CPoint p0 (0, 0);
|
||||
constexpr CPoint p3 (1, 1);
|
||||
|
||||
auto t = static_cast<float> (milliseconds) / static_cast<float> (length);
|
||||
|
||||
auto a = lerp (p0, p1, t);
|
||||
auto b = lerp (p1, p2, t);
|
||||
auto c = lerp (p2, p3, t);
|
||||
auto d = lerp (a, b, t);
|
||||
auto e = lerp (b, c, t);
|
||||
auto result = lerp (d, e, t).y;
|
||||
return static_cast<float> (result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction CubicBezierTimingFunction::easy (uint32_t time)
|
||||
{
|
||||
return CubicBezierTimingFunction (time, CPoint (0.25, 0.1), CPoint (0.25, 1.));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction CubicBezierTimingFunction::easyIn (uint32_t time)
|
||||
{
|
||||
return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (1., 1.));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction CubicBezierTimingFunction::easyOut (uint32_t time)
|
||||
{
|
||||
return CubicBezierTimingFunction (time, CPoint (0., 0.), CPoint (0.58, 1.));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction CubicBezierTimingFunction::easyInOut (uint32_t time)
|
||||
{
|
||||
return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (0.58, 1.));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CubicBezierTimingFunction* CubicBezierTimingFunction::make (Style style, uint32_t time)
|
||||
{
|
||||
using Func = CubicBezierTimingFunction;
|
||||
switch (style)
|
||||
{
|
||||
case Easy:
|
||||
return new CubicBezierTimingFunction (Func::easy (time));
|
||||
case EasyIn:
|
||||
return new CubicBezierTimingFunction (Func::easyIn (time));
|
||||
case EasyOut:
|
||||
return new CubicBezierTimingFunction (Func::easyOut (time));
|
||||
case EasyInOut:
|
||||
return new CubicBezierTimingFunction (Func::easyInOut (time));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
RepeatTimingFunction::RepeatTimingFunction (TimingFunctionBase* tf, int32_t repeatCount, bool autoReverse)
|
||||
: tf (tf)
|
||||
, repeatCount (repeatCount)
|
||||
, runCounter (0)
|
||||
, autoReverse (autoReverse)
|
||||
, isReverse (false)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
RepeatTimingFunction::~RepeatTimingFunction () noexcept
|
||||
{
|
||||
auto obj = dynamic_cast<IReference*> (tf);
|
||||
if (obj)
|
||||
obj->forget ();
|
||||
else
|
||||
delete tf;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
float RepeatTimingFunction::getPosition (uint32_t milliseconds)
|
||||
{
|
||||
if (runCounter > 0)
|
||||
milliseconds -= tf->getLength () * runCounter;
|
||||
float pos = tf->getPosition (milliseconds);
|
||||
return isReverse ? 1.f - pos : pos;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RepeatTimingFunction::isDone (uint32_t milliseconds)
|
||||
{
|
||||
if (runCounter > 0)
|
||||
milliseconds -= tf->getLength () * runCounter;
|
||||
if (tf->isDone (milliseconds))
|
||||
{
|
||||
runCounter++;
|
||||
if (autoReverse)
|
||||
isReverse = !isReverse;
|
||||
if ((uint64_t)runCounter >= (uint64_t)repeatCount)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "animator.h"
|
||||
#include "itimingfunction.h"
|
||||
#include "../cpoint.h"
|
||||
#include <map>
|
||||
|
||||
namespace VSTGUI {
|
||||
namespace Animation {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class TimingFunctionBase : public ITimingFunction
|
||||
{
|
||||
public:
|
||||
explicit TimingFunctionBase (uint32_t length) : length (length) {}
|
||||
TimingFunctionBase (const TimingFunctionBase&) = default;
|
||||
TimingFunctionBase& operator= (const TimingFunctionBase&) = default;
|
||||
|
||||
uint32_t getLength () const { return length; }
|
||||
bool isDone (uint32_t milliseconds) override { return milliseconds >= length; }
|
||||
|
||||
protected:
|
||||
uint32_t length; // in milliseconds
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class LinearTimingFunction : public TimingFunctionBase
|
||||
{
|
||||
public:
|
||||
explicit LinearTimingFunction (uint32_t length);
|
||||
LinearTimingFunction (const LinearTimingFunction&) = default;
|
||||
LinearTimingFunction& operator= (const LinearTimingFunction&) = default;
|
||||
|
||||
float getPosition (uint32_t milliseconds) override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class PowerTimingFunction : public TimingFunctionBase
|
||||
{
|
||||
public:
|
||||
PowerTimingFunction (uint32_t length, float factor);
|
||||
PowerTimingFunction (const PowerTimingFunction&) = default;
|
||||
PowerTimingFunction& operator= (const PowerTimingFunction&) = default;
|
||||
|
||||
float getPosition (uint32_t milliseconds) override;
|
||||
|
||||
protected:
|
||||
float factor;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class InterpolationTimingFunction : public TimingFunctionBase
|
||||
{
|
||||
public:
|
||||
InterpolationTimingFunction (uint32_t length, float startPos = 0.f, float endPos = 1.f);
|
||||
InterpolationTimingFunction (const InterpolationTimingFunction&) = default;
|
||||
InterpolationTimingFunction& operator= (const InterpolationTimingFunction&) = default;
|
||||
|
||||
/** both values are normalized ones */
|
||||
void addPoint (float time, float pos);
|
||||
|
||||
float getPosition (uint32_t milliseconds) override;
|
||||
|
||||
protected:
|
||||
|
||||
using PointMap = std::map<uint32_t, float>;
|
||||
PointMap points;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_7
|
||||
//-----------------------------------------------------------------------------
|
||||
class CubicBezierTimingFunction : public TimingFunctionBase
|
||||
{
|
||||
public:
|
||||
CubicBezierTimingFunction (uint32_t milliseconds, CPoint p1, CPoint p2);
|
||||
CubicBezierTimingFunction (const CubicBezierTimingFunction&) = default;
|
||||
CubicBezierTimingFunction (CubicBezierTimingFunction&&) = default;
|
||||
CubicBezierTimingFunction& operator= (const CubicBezierTimingFunction&) = default;
|
||||
CubicBezierTimingFunction& operator= (CubicBezierTimingFunction&&) = default;
|
||||
|
||||
float getPosition (uint32_t milliseconds) override;
|
||||
|
||||
// some common timings
|
||||
static CubicBezierTimingFunction easy (uint32_t time);
|
||||
static CubicBezierTimingFunction easyIn (uint32_t time);
|
||||
static CubicBezierTimingFunction easyOut (uint32_t time);
|
||||
static CubicBezierTimingFunction easyInOut (uint32_t time);
|
||||
|
||||
enum Style
|
||||
{
|
||||
Easy,
|
||||
EasyIn,
|
||||
EasyOut,
|
||||
EasyInOut
|
||||
};
|
||||
static CubicBezierTimingFunction* make (Style style, uint32_t time);
|
||||
|
||||
private:
|
||||
static CPoint lerp (CPoint p1, CPoint p2, float pos);
|
||||
|
||||
CPoint p1;
|
||||
CPoint p2;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @ingroup AnimationTimingFunctions
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class RepeatTimingFunction : public ITimingFunction
|
||||
{
|
||||
public:
|
||||
RepeatTimingFunction (TimingFunctionBase* tf, int32_t repeatCount, bool autoReverse = true);
|
||||
~RepeatTimingFunction () noexcept override;
|
||||
|
||||
float getPosition (uint32_t milliseconds) override;
|
||||
bool isDone (uint32_t milliseconds) override;
|
||||
protected:
|
||||
TimingFunctionBase* tf;
|
||||
int32_t repeatCount;
|
||||
uint32_t runCounter;
|
||||
bool autoReverse;
|
||||
bool isReverse;
|
||||
};
|
||||
|
||||
} // Animation
|
||||
} // VSTGUI
|
||||
Reference in New Issue
Block a user