diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index 178f5b5ea1..6a1649f963 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -1,6 +1,11 @@ #include "animation_system.h" #include "animation/interpolations.hpp" +#include "base/logging.hpp" + +#include "boost/variant/variant.hpp" +#include "boost/variant/get.hpp" + namespace df { @@ -19,6 +24,35 @@ double CalcAnimSpeedDuration(double pxDiff, double pxSpeed) } +bool Animation::CouldBeMixedWith(TObject object, TObjectProperties const & properties) +{ + if (!m_couldBeMixed) + return false; + ASSERT(HasObject(object), ()); + + TObjectProperties const & selfProperties = GetProperties(object); + TObjectProperties intersection; + set_intersection(selfProperties.begin(), selfProperties.end(), + properties.begin(), properties.end(), + inserter(intersection, intersection.end())); + return intersection.empty(); +} + +bool Animation::CouldBeMixedWith(Animation const & animation) +{ + if (!m_couldBeMixed || animation.m_couldBeMixed) + return false; + + for (auto const & object : animation.GetObjects()) + { + if (!HasObject(object)) + continue; + if (!CouldBeMixedWith(object, animation.GetProperties(object))) + return false; + } + return true; +} + Interpolator::Interpolator(double duration, double delay) : m_elapsedTime(0.0) , m_duration(duration) @@ -102,7 +136,7 @@ PositionInterpolator::PositionInterpolator(double delay, m2::PointD const & star void PositionInterpolator::Advance(double elapsedSeconds) { TBase::Advance(elapsedSeconds); - InterpolatePoint(m_startPosition, m_endPosition, GetT()); + m_position = InterpolatePoint(m_startPosition, m_endPosition, GetT()); } // static @@ -164,35 +198,57 @@ void ScaleInterpolator::Advance(double elapsedSeconds) FollowAnimation::FollowAnimation(m2::PointD const & startPos, m2::PointD const & endPos, double startAngle, double endAngle, double startScale, double endScale, ScreenBase const & convertor) - : Animation(false, false) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) { + m_objects.insert(Animation::MapPlane); SetMove(startPos, endPos, convertor); SetRotate(startAngle, endAngle); SetScale(startScale, endScale); } FollowAnimation::FollowAnimation() - : Animation(false, false) + : Animation(true /* couldBeInterrupted */, false /* couldBeMixed */) { + m_objects.insert(Animation::MapPlane); } void FollowAnimation::SetMove(m2::PointD const & startPos, m2::PointD const & endPos, ScreenBase const & convertor) { if (startPos != endPos) + { m_positionInterpolator = make_unique_dp(startPos, endPos, convertor); + m_properties.insert(Animation::Position); + } } void FollowAnimation::SetRotate(double startAngle, double endAngle) { if (startAngle != endAngle) + { m_angleInterpolator = make_unique_dp(startAngle, endAngle); + m_properties.insert(Animation::Angle); + } } void FollowAnimation::SetScale(double startScale, double endScale) { if (startScale != endScale) + { m_scaleInterpolator = make_unique_dp(startScale, endScale); + m_properties.insert(Animation::Scale); + } +} + +Animation::TObjectProperties const & FollowAnimation::GetProperties(TObject object) const +{ + ASSERT(object == Animation::MapPlane, ()); + return m_properties; +} + +bool FollowAnimation::HasProperty(TObject object, TProperty property) const +{ + return HasObject(object) && m_properties.find(property) != m_properties.end(); } void FollowAnimation::Advance(double elapsedSeconds) @@ -234,58 +290,58 @@ bool FollowAnimation::IsFinished() const && (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished())); } -double FollowAnimation::GetScale(uint32_t object) const +Animation::TPropValue FollowAnimation::GetProperty(TObject object, TProperty property) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_scaleInterpolator != nullptr, ()); + ASSERT(object == Animation::MapPlane, ()); - if (m_scaleInterpolator != nullptr) - return m_scaleInterpolator->GetScale(); + switch (property) + { + case Animation::Position: + ASSERT(m_positionInterpolator != nullptr, ()); + if (m_positionInterpolator != nullptr) + return m_positionInterpolator->GetPosition(); + break; + case Animation::Scale: + ASSERT(m_scaleInterpolator != nullptr, ()); + if (m_scaleInterpolator != nullptr) + return m_scaleInterpolator->GetScale(); + break; + case Animation::Angle: + ASSERT(m_angleInterpolator != nullptr, ()); + if (m_angleInterpolator != nullptr) + return m_angleInterpolator->GetAngle(); + break; + default: + ASSERT(!"Wrong property", ()); + } return 0.0; } -double FollowAnimation::GetAngle(uint32_t object) const +Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_angleInterpolator != nullptr, ()); - - if (m_angleInterpolator != nullptr) - return m_angleInterpolator->GetAngle(); - - return 0.0; + ASSERT(HasObject(object), ()); + return m_properties.find(object)->second; } -m2::PointD FollowAnimation::GetPosition(uint32_t object) const +bool ParallelAnimation::HasProperty(TObject object, TProperty property) const { - ASSERT(object & GetObjects(), ()); - ASSERT(m_positionInterpolator != nullptr, ()); - - if (m_positionInterpolator != nullptr) - return m_positionInterpolator->GetPosition(); - - return m2::PointD(); + if (!HasObject(object)) + return false; + TObjectProperties properties = GetProperties(object); + return properties.find(property) != properties.end(); } -uint32_t ParallelAnimation::GetMask(uint32_t object) const +void ParallelAnimation::AddAnimation(drape_ptr && animation) { - int mask = 0; - for (auto const & anim : m_animations) - mask |= anim->GetMask(object); - return mask; -} - -uint32_t ParallelAnimation::GetObjects() const -{ - int objects = 0; - for (auto const & anim : m_animations) - objects |= anim->GetObjects(); - return objects; -} - -void ParallelAnimation::AddAnimation(ref_ptr animation) -{ - m_animations.push_back(animation); + TAnimObjects const & objects = animation->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) + { + TObjectProperties const & properties = animation->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); + } + m_animations.push_back(move(animation)); } void ParallelAnimation::OnStart() @@ -315,25 +371,33 @@ void ParallelAnimation::Advance(double elapsedSeconds) } } -uint32_t SequenceAnimation::GetMask(uint32_t object) const +Animation::TAnimObjects const & SequenceAnimation::GetObjects() const { - int mask = 0; - if (!m_animations.empty()) - mask = m_animations.front()->GetMask(object); - return mask; + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->GetObjects(); } -uint32_t SequenceAnimation::GetObjects() const +bool SequenceAnimation::HasObject(TObject object) const { - int objects = 0; - if (!m_animations.empty()) - objects = m_animations.front()->GetObjects(); - return objects; + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->HasObject(object); } -void SequenceAnimation::AddAnimation(ref_ptr animation) +Animation::TObjectProperties const & SequenceAnimation::GetProperties(TObject object) const { - m_animations.push_back(animation); + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->GetProperties(object); +} + +bool SequenceAnimation::HasProperty(TObject object, TProperty property) const +{ + ASSERT(!m_animations.empty(), ()); + return m_animations.front()->HasProperty(object, property); +} + +void SequenceAnimation::AddAnimation(drape_ptr && animation) +{ + m_animations.push_back(move(animation)); } void SequenceAnimation::OnStart() @@ -360,35 +424,38 @@ void SequenceAnimation::Advance(double elapsedSeconds) } } +AnimationSystem::AnimationSystem() +{ + +} + m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen) { - double scale = currentScreen.GetScale(); - double angle = currentScreen.GetAngle(); - m2::PointD pos = currentScreen.GlobalRect().GlobalZero(); - for (auto const & anim : m_animations) - { - if (anim->GetObjects() & kPlaneAnimObjBit) - { - int mask = anim->GetMask(kPlaneAnimObjBit); - if (mask & kScaleAnimationBit) - scale = anim->GetScale(kPlaneAnimObjBit); - if (mask & kMoveAnimationBit) - pos = anim->GetPosition(kPlaneAnimObjBit); - if (mask & kRotateAnimationBit) - angle = anim->GetAngle(kPlaneAnimObjBit); - } - } + const Animation::TObject obj = Animation::MapPlane; + double scale = boost::get( + GetProperty(obj, Animation::Scale, currentScreen.GetScale())); + double angle = boost::get( + GetProperty(obj, Animation::Angle, currentScreen.GetAngle())); + m2::PointD pos = boost::get( + GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero())); m2::RectD rect = currentScreen.PixelRect(); rect.Offset(-rect.Center()); rect.Scale(scale); return m2::AnyRectD(pos, angle, rect); } -bool AnimationSystem::AnimationExists(Animation::Object object) +bool AnimationSystem::AnimationExists(Animation::TObject object) const { - for (auto const & anim : m_animations) + if (m_animationChain.empty()) + return false; + for (auto const & anim : m_animationChain.front()) { - if (anim->GetObjects() & (1 << object)) + if (anim->HasObject(object)) + return true; + } + for (auto it = m_propertyCache.begin(); it != m_propertyCache.end(); ++it) + { + if (it->first.first == object) return true; } return false; @@ -400,25 +467,101 @@ AnimationSystem & AnimationSystem::Instance() return animSystem; } -void AnimationSystem::AddAnimation(drape_ptr && animation) +void AnimationSystem::AddAnimation(drape_ptr && animation, bool force) +{ + for (auto & lst : m_animationChain) + { + bool couldBeMixed = true; + for (auto it = lst.begin(); it != lst.end();) + { + auto & anim = *it; + if (!anim->CouldBeMixedWith(*animation)) + { + if (!force || !anim->CouldBeInterrupted()) + { + couldBeMixed = false; + break; + } + // TODO: do not interrupt anything until it's not clear that we can mix + anim->Interrupt(); + SaveAnimationResult(*anim); + it = lst.erase(it); + } + else + { + ++it; + } + } + if (couldBeMixed) + { + animation->OnStart(); + lst.emplace_back(move(animation)); + return; + } + } + + PushAnimation(move(animation)); +} + +void AnimationSystem::PushAnimation(drape_ptr && animation) { animation->OnStart(); - m_animations.insert(move(animation)); + TAnimationList list; + list.emplace_back(move(animation)); + m_animationChain.emplace_back(move(list)); } void AnimationSystem::Advance(double elapsedSeconds) { - auto iter = m_animations.begin(); - while (iter != m_animations.end()) + if (m_animationChain.empty()) + return; + + TAnimationList & frontList = m_animationChain.front(); + for (auto it = frontList.begin(); it != frontList.end();) { - (*iter)->Advance(elapsedSeconds); - if ((*iter)->IsFinished()) + auto & anim = *it; + anim->Advance(elapsedSeconds); + if (anim->IsFinished()) { - (*iter)->OnFinish(); - iter = m_animations.erase(iter); + anim->OnFinish(); + SaveAnimationResult(*anim); + it = frontList.erase(it); } else - ++iter; + { + ++it; + } + } +} + +Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const +{ + if (!m_animationChain.empty()) + { + for (auto const & anim : m_animationChain.front()) + { + if (anim->HasProperty(object, property)) + return anim->GetProperty(object, property); + } + } + auto it = m_propertyCache.find(make_pair(object, property)); + if (it != m_propertyCache.end()) + { + Animation::TPropValue value(it->second); + m_propertyCache.erase(it); + return value; + } + return current; +} + +void AnimationSystem::SaveAnimationResult(Animation const & animation) +{ + for (auto const & object : animation.GetObjects()) + { + for (auto const & property : animation.GetProperties(object)) + { + m_propertyCache[make_pair(object, property)] = animation.GetProperty(object, property); + } } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 6018020a16..1d5370bcd0 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -6,21 +6,15 @@ #include "geometry/screenbase.hpp" +#include "std/set.hpp" #include "std/deque.hpp" #include "std/noncopyable.hpp" +#include "boost/variant/variant_fwd.hpp" + namespace df { -uint32_t constexpr kMoveAnimationBit = 1; -uint32_t constexpr kScaleAnimationBit = 1 << 1; -uint32_t constexpr kRotateAnimationBit = 1 << 2; -uint32_t constexpr kPerspectiveAnimationBit = 1 << 3; - -uint32_t constexpr kArrowAnimObjBit = 1; -uint32_t constexpr kPlaneAnimObjBit = 1 << 1; -uint32_t constexpr kSelectionAnimBit = 1 << 2; - class Animation { public: @@ -40,6 +34,19 @@ public: Selection }; + enum ObjectProperty + { + Position, + Scale, + Angle + }; + + using TObject = uint32_t; + using TProperty = uint32_t; + using TPropValue = boost::variant; + using TAnimObjects = set; + using TObjectProperties = set; + Animation(bool couldBeInterrupted, bool couldBeMixed) : m_couldBeInterrupted(couldBeInterrupted) , m_couldBeMixed(couldBeMixed) @@ -47,11 +54,14 @@ public: virtual void OnStart() {} virtual void OnFinish() {} + virtual void Interrupt() {} virtual Type GetType() const = 0; - virtual uint32_t GetMask(uint32_t object) const = 0; - virtual uint32_t GetObjects() const = 0; + virtual TAnimObjects const & GetObjects() const = 0; + virtual bool HasObject(TObject object) const = 0; + virtual TObjectProperties const & GetProperties(TObject object) const = 0; + virtual bool HasProperty(TObject object, TProperty property) const = 0; virtual void SetMaxDuration(double maxDuration) = 0; virtual double GetDuration() const = 0; @@ -59,16 +69,12 @@ public: virtual void Advance(double elapsedSeconds) = 0; - virtual double GetScale(uint32_t object) const = 0; - virtual double GetAngle(uint32_t object) const = 0; - virtual m2::PointD GetPosition(uint32_t object) const = 0; + virtual TPropValue GetProperty(TObject object, TProperty property) const = 0; bool CouldBeInterrupted() const { return m_couldBeInterrupted; } bool CouldBeMixed() const { return m_couldBeMixed; } - bool CouldBeMixedWith(uint32_t object, int mask) - { - return m_couldBeMixed && !(mask & GetMask(object)); - } + bool CouldBeMixedWith(TObject object, TObjectProperties const & properties); + bool CouldBeMixedWith(Animation const & animation); protected: bool m_couldBeInterrupted; @@ -163,27 +169,31 @@ public: { m_positionInterpolator.reset(new PositionInterpolator(startPos, endPos, convertor)); m_angleInterpolator.reset(new AngleInterpolator(startAngle, endAngle)); + m_objects.insert(Animation::MyPositionArrow); + m_properties.insert(Animation::Position); + m_properties.insert(Animation::Angle); } Animation::Type GetType() const override { return Animation::Arrow; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kArrowAnimObjBit) && - ((m_angleInterpolator != nullptr ? kRotateAnimationBit : 0) | - (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0)); + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kArrowAnimObjBit; + return object == Animation::MyPositionArrow; } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; private: drape_ptr m_positionInterpolator; drape_ptr m_angleInterpolator; + TAnimObjects m_objects; + TObjectProperties m_properties; }; class PerspectiveSwitchAnimation : public Animation @@ -194,21 +204,23 @@ class PerspectiveSwitchAnimation : public Animation Animation::Type GetType() const override { return Animation::Perspective; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kPlaneAnimObjBit) && - (m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0); + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kPlaneAnimObjBit; + return m_objects.find(object) != m_objects.end(); } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; private: drape_ptr m_angleInterpolator; + TAnimObjects m_objects; + TObjectProperties m_properties; }; class FollowAnimation : public Animation @@ -225,18 +237,16 @@ public: Animation::Type GetType() const override { return Animation::ModelView; } - uint32_t GetMask(uint32_t object) const override + TAnimObjects const & GetObjects() const override { - return (object & kPlaneAnimObjBit) ? - ((m_angleInterpolator != nullptr ? kPerspectiveAnimationBit : 0) | - (m_positionInterpolator != nullptr ? kMoveAnimationBit : 0) | - (m_scaleInterpolator != nullptr ? kScaleAnimationBit : 0)) : 0; + return m_objects; } - - uint32_t GetObjects() const override + bool HasObject(TObject object) const override { - return kPlaneAnimObjBit; + return object == Animation::MapPlane; } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; void Advance(double elapsedSeconds) override; @@ -244,26 +254,26 @@ public: double GetDuration() const override; bool IsFinished() const override; - double GetScale(uint32_t object) const override; - double GetAngle(uint32_t object) const override; - m2::PointD GetPosition(uint32_t object) const override; + TPropValue GetProperty(TObject object, TProperty property) const override; private: drape_ptr m_angleInterpolator; drape_ptr m_positionInterpolator; drape_ptr m_scaleInterpolator; + TObjectProperties m_properties; + TAnimObjects m_objects; }; -using TAnimations = vector>; - class SequenceAnimation : public Animation { public: Animation::Type GetType() const override { return Animation::Sequence; } - uint32_t GetMask(uint32_t object) const override; - uint32_t GetObjects() const override; + TAnimObjects const & GetObjects() const override; + bool HasObject(TObject object) const override; + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; - void AddAnimation(ref_ptr animation); + void AddAnimation(drape_ptr && animation); void OnStart() override; void OnFinish() override; @@ -271,17 +281,25 @@ public: void Advance(double elapsedSeconds) override; private: - deque> m_animations; + deque> m_animations; }; class ParallelAnimation : public Animation { public: Animation::Type GetType() const override { return Animation::Parallel; } - uint32_t GetMask(uint32_t object) const override; - uint32_t GetObjects() const override; + TAnimObjects const & GetObjects() const override + { + return m_objects; + } + bool HasObject(TObject object) const override + { + return m_objects.find(object) != m_objects.end(); + } + TObjectProperties const & GetProperties(TObject object) const override; + bool HasProperty(TObject object, TProperty property) const override; - void AddAnimation(ref_ptr animation); + void AddAnimation(drape_ptr && animation); void OnStart() override; void OnFinish() override; @@ -289,7 +307,9 @@ public: void Advance(double elapsedSeconds) override; private: - TAnimations m_animations; + list> m_animations; + TAnimObjects m_objects; + map m_properties; }; class AnimationSystem : private noncopyable @@ -299,18 +319,25 @@ public: m2::AnyRectD GetRect(ScreenBase const & currentScreen); - bool AnimationExists(Animation::Object object); + bool AnimationExists(Animation::TObject object) const; - void AddAnimation(drape_ptr && animation); + void AddAnimation(drape_ptr && animation, bool force); + void PushAnimation(drape_ptr && animation); void Advance(double elapsedSeconds); private: - AnimationSystem() {} + Animation::TPropValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const; + void SaveAnimationResult(Animation const & animation); + + AnimationSystem(); private: - - set> m_animations; + using TAnimationList = list>; + using TAnimationChain = deque; + using TPropertyCache = map, Animation::TPropValue>; + TAnimationChain m_animationChain; + mutable TPropertyCache m_propertyCache; }; } diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 27992cf31c..4c79521a90 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -568,9 +568,9 @@ void MyPositionController::CheckAnimFinished() const void MyPositionController::AnimationStarted(ref_ptr anim) { - if (m_isPendingAnimation && m_animCreator != nullptr && anim != nullptr && - (anim->GetType() == ModelViewAnimationType::FollowAndRotate || - anim->GetType() == ModelViewAnimationType::Default)) + if (m_isPendingAnimation && m_animCreator != nullptr)// && anim != nullptr && + // (anim->GetType() == ModelViewAnimationType::FollowAndRotate || + // anim->GetType() == ModelViewAnimationType::Default)) { m_isPendingAnimation = false; m_animCreator(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 8ca230b11a..fda9f13b2d 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -340,7 +340,7 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, anim->SetMaxDuration(kMaxAnimationTimeSec); if (df::IsAnimationAllowed(anim->GetDuration(), startScreen)) { - AnimationSystem::Instance().AddAnimation(move(anim)); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); return false; } @@ -463,7 +463,16 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) return SetRect(rect, isAnim, [this](m2::AnyRectD const & startRect, m2::AnyRectD const & endRect, double aDuration, double mDuration, double sDuration) { - m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); + drape_ptr anim = make_unique_dp(); + anim->SetRotate(startRect.Angle().val(), endRect.Angle().val()); + anim->SetMove(startRect.GlobalCenter(), endRect.GlobalCenter(), GetCurrentScreen()); + m2::RectD pixelRect = GetCurrentScreen().PixelRect(); + anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), + max(endRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + endRect.GetLocalRect().SizeY() / pixelRect.SizeY())); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + //m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); if (m_listener) m_listener->OnAnimationStarted(make_ref(m_animation)); }); @@ -525,15 +534,21 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD m2::PointD const newCenter = FollowAndRotateAnimation::CalculateCenter(screen, userPos, pixelPos, -azimuth); m2::AnyRectD const startRect = GetCurrentRect(); - double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), -azimuth); - double const moveDuration = ModelViewAnimation::GetMoveDuration(startRect.GlobalZero(), newCenter, screen); - double const duration = max(angleDuration, moveDuration); - if (df::IsAnimationAllowed(duration, screen)) + //double const angleDuration = ModelViewAnimation::GetRotateDuration(startRect.Angle().val(), -azimuth); + //double const moveDuration = ModelViewAnimation::GetMoveDuration(startRect.GlobalZero(), newCenter, screen); + //double const duration = max(angleDuration, moveDuration); + + drape_ptr anim = make_unique_dp(); + anim->SetRotate(startRect.Angle().val(), -azimuth); + anim->SetMove(startRect.GlobalZero(), newCenter, screen); + + if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { - m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, - screen.GtoP(userPos), pixelPos, azimuth, duration)); + AnimationSystem::Instance().AddAnimation(move(anim), true /* force */); + //m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, + // screen.GtoP(userPos), pixelPos, azimuth, duration)); if (m_listener) - m_listener->OnAnimationStarted(make_ref(m_animation)); + m_listener->OnAnimationStarted(make_ref(nullptr/*m_animation*/)); return false; } }