diff --git a/drape_frontend/animation_system.cpp b/drape_frontend/animation_system.cpp index d1c47db21f..a76ba7c12e 100644 --- a/drape_frontend/animation_system.cpp +++ b/drape_frontend/animation_system.cpp @@ -724,10 +724,15 @@ void ParallelAnimation::Finish() Animation::Finish(); } +SequenceAnimation::SequenceAnimation() + : Animation(false /* couldBeInterrupted */, false /* couldBeMixed */) +{ + +} + Animation::TAnimObjects const & SequenceAnimation::GetObjects() const { - ASSERT(!m_animations.empty(), ()); - return m_animations.front()->GetObjects(); + return m_objects; } bool SequenceAnimation::HasObject(TObject object) const @@ -738,8 +743,8 @@ bool SequenceAnimation::HasObject(TObject object) const Animation::TObjectProperties const & SequenceAnimation::GetProperties(TObject object) const { - ASSERT(!m_animations.empty(), ()); - return m_animations.front()->GetProperties(object); + ASSERT(HasObject(object), ()); + return m_properties.find(object)->second; } bool SequenceAnimation::HasProperty(TObject object, TProperty property) const @@ -748,8 +753,46 @@ bool SequenceAnimation::HasProperty(TObject object, TProperty property) const return m_animations.front()->HasProperty(object, property); } +void SequenceAnimation::SetMaxDuration(double maxDuration) +{ + ASSERT(!"Not implemented", ()); +} + +double SequenceAnimation::GetDuration() const +{ + double duration = 0.0; + for (auto const & anim : m_animations) + { + duration += anim->GetDuration(); + } + return duration; +} + +bool SequenceAnimation::IsFinished() const +{ + return m_animations.empty(); +} + +bool SequenceAnimation::GetProperty(TObject object, TProperty property, PropertyValue &value) const +{ + for (auto const & anim : m_animations) + { + if (anim->HasProperty(object, property)) + return anim->GetProperty(object, property, value); + } + return false; +} + void SequenceAnimation::AddAnimation(drape_ptr && animation) { + // TODO: Add only current animation's properties. + 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)); } @@ -773,7 +816,25 @@ void SequenceAnimation::Advance(double elapsedSeconds) if (m_animations.front()->IsFinished()) { m_animations.front()->OnFinish(); + AnimationSystem::Instance().SaveAnimationResult(*m_animations.front()); m_animations.pop_front(); + CalculateObjectProperties(); + } +} + +void SequenceAnimation::CalculateObjectProperties() +{ + m_objects.clear(); + m_properties.clear(); + for (auto const & anim : m_animations) + { + TAnimObjects const & objects = anim->GetObjects(); + m_objects.insert(objects.begin(), objects.end()); + for (auto const & object : objects) + { + TObjectProperties const & properties = anim->GetProperties(object); + m_properties[object].insert(properties.begin(), properties.end()); + } } } diff --git a/drape_frontend/animation_system.h b/drape_frontend/animation_system.h index 0323647659..7f5b4b6a44 100644 --- a/drape_frontend/animation_system.h +++ b/drape_frontend/animation_system.h @@ -441,12 +441,19 @@ private: class SequenceAnimation : public Animation { public: + SequenceAnimation(); Animation::Type GetType() const override { return Animation::Sequence; } 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 SetMaxDuration(double maxDuration) override; + double GetDuration() const override; + bool IsFinished() const override; + + bool GetProperty(TObject object, TProperty property, PropertyValue &value) const override; + void AddAnimation(drape_ptr && animation); void OnStart() override; @@ -455,7 +462,11 @@ public: void Advance(double elapsedSeconds) override; private: + void CalculateObjectProperties(); + deque> m_animations; + TAnimObjects m_objects; + map m_properties; }; class ParallelAnimation : public Animation @@ -508,10 +519,10 @@ public: void Advance(double elapsedSeconds); ScreenBase const & GetLastScreen() { return m_lastScreen; } + void SaveAnimationResult(Animation const & animation); private: bool GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue & value) const; - void SaveAnimationResult(Animation const & animation); void StartNextAnimations(); AnimationSystem(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 425d5766d2..a4aeea8aa1 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -448,14 +448,14 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) m2::AnyRectD const startRect = GetCurrentRect(); m2::RectD const pixelRect = screen.PixelRect(); + double const startScale = max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), + startRect.GetLocalRect().SizeY() / pixelRect.SizeY()); + double const endScale = max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), + rect.GetLocalRect().SizeY() / pixelRect.SizeY()); drape_ptr anim = make_unique_dp(); anim->SetRotate(startRect.Angle().val(), rect.Angle().val()); anim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); - - anim->SetScale(max(startRect.GetLocalRect().SizeX() / pixelRect.SizeX(), - startRect.GetLocalRect().SizeY() / pixelRect.SizeY()), - max(rect.GetLocalRect().SizeX() / pixelRect.SizeX(), - rect.GetLocalRect().SizeY() / pixelRect.SizeY())); + anim->SetScale(startScale, endScale); if (df::IsAnimationAllowed(anim->GetDuration(), screen)) { @@ -464,9 +464,39 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) m_listener->OnAnimationStarted(nullptr); return false; } + else + { + double const moveDuration = PositionInterpolator::GetMoveDuration(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + if (moveDuration > kMaxAnimationTimeSec) + { + double const scaleFactor = moveDuration / kMaxAnimationTimeSec * 2.0; + + drape_ptr sequenceAnim = make_unique_dp(); + drape_ptr zoomOutAnim = make_unique_dp(); + zoomOutAnim->SetScale(startScale, startScale * scaleFactor); + zoomOutAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); + + // TODO: Pass fixed duration instead of screen. + drape_ptr moveAnim = make_unique_dp(); + moveAnim->SetMove(startRect.GlobalCenter(), rect.GlobalCenter(), screen); + moveAnim->SetMaxDuration(kMaxAnimationTimeSec); + + drape_ptr zoomInAnim = make_unique_dp(); + zoomInAnim->SetScale(startScale * scaleFactor, endScale); + zoomInAnim->SetMaxDuration(kMaxAnimationTimeSec / 2.0); + + sequenceAnim->AddAnimation(move(zoomOutAnim)); + sequenceAnim->AddAnimation(move(moveAnim)); + sequenceAnim->AddAnimation(move(zoomInAnim)); + AnimationSystem::Instance().AddAnimation(move(sequenceAnim), true /* force */); + if (m_listener) + m_listener->OnAnimationStarted(nullptr); + return false; + } + } + } - m_animation.reset(); m_navigator.SetFromRect(rect); return true; }