diff --git a/drape_frontend/animation_constants.hpp b/drape_frontend/animation_constants.hpp new file mode 100644 index 0000000000..35cf0696a8 --- /dev/null +++ b/drape_frontend/animation_constants.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace df +{ +double const kMaxAnimationTimeSec = 1.5; // in seconds + +} // namespace df diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index e947587be6..cf39651a79 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -113,6 +113,7 @@ HEADERS += \ gui/ruler_helper.hpp \ gui/shape.hpp \ gui/skin.hpp \ + animation_constants.hpp \ apply_feature_functors.hpp \ area_shape.hpp \ arrow3d.hpp \ diff --git a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp index 26da0ab8e8..912fdcfb35 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -37,6 +37,7 @@ public: void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override {} void CorrectGlobalScalePoint(m2::PointD & pt) const override {} void OnScaleEnded() override {} + void OnAnimationStarted(ref_ptr /* anim */) override {} void AddUserEvent(df::TouchEvent const & event) { diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 07da4cb99e..4d78799b29 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1107,6 +1107,11 @@ void FrontendRenderer::OnScaleEnded() m_myPositionController->ScaleEnded(); } +void FrontendRenderer::OnAnimationStarted(ref_ptr anim) +{ + m_myPositionController->AnimationStarted(anim); +} + void FrontendRenderer::ResolveTileKeys(ScreenBase const & screen, TTilesCollection & tiles) { m2::RectD const & clipRect = screen.ClipRect(); diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 352c2744dd..96de9d230c 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -172,6 +172,7 @@ private: void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const override; void CorrectGlobalScalePoint(m2::PointD & pt) const override; void OnScaleEnded() override; + void OnAnimationStarted(ref_ptr anim) override; class Routine : public threads::IRoutine { diff --git a/drape_frontend/kinetic_scroller.cpp b/drape_frontend/kinetic_scroller.cpp index 3739f8a214..745c30dc6a 100644 --- a/drape_frontend/kinetic_scroller.cpp +++ b/drape_frontend/kinetic_scroller.cpp @@ -116,11 +116,11 @@ void KineticScroller::CancelGrab() m_direction = m2::PointD::Zero(); } -unique_ptr KineticScroller::CreateKineticAnimation(ScreenBase const & modelView) +drape_ptr KineticScroller::CreateKineticAnimation(ScreenBase const & modelView) { static double kVelocityThreshold = kKineticThreshold * VisualParams::Instance().GetVisualScale(); if (m_direction.Length() < kVelocityThreshold) - return unique_ptr(); + return drape_ptr(); // Before we start animation we have to convert length(m_direction) from pixel space to mercator space. m2::PointD center = m_lastRect.GlobalCenter(); @@ -129,9 +129,9 @@ unique_ptr KineticScroller::CreateKineticAnimation(Scree m2::PointD const glbDirection = m_direction.Normalize() * glbLength; m2::PointD const targetCenter = center + glbDirection; if (!df::GetWorldRect().IsPointInside(targetCenter)) - return unique_ptr(); + return drape_ptr(); - return unique_ptr(new KineticScrollAnimation(m_lastRect, glbDirection, kKineticDuration)); + return make_unique_dp(m_lastRect, glbDirection, kKineticDuration); } } // namespace df diff --git a/drape_frontend/kinetic_scroller.hpp b/drape_frontend/kinetic_scroller.hpp index 832dcb8d05..2d9de55aed 100644 --- a/drape_frontend/kinetic_scroller.hpp +++ b/drape_frontend/kinetic_scroller.hpp @@ -2,6 +2,8 @@ #include "animation/model_view_animation.hpp" +#include "drape/pointers.hpp" + #include "geometry/any_rect2d.hpp" namespace df @@ -16,7 +18,7 @@ public: bool IsActive() const; void GrabViewRect(ScreenBase const & modelView, double timeStamp); void CancelGrab(); - unique_ptr CreateKineticAnimation(ScreenBase const & modelView); + drape_ptr CreateKineticAnimation(ScreenBase const & modelView); private: double m_lastTimestamp; diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 32e74ba27e..dcdd70a90a 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -1,4 +1,5 @@ #include "my_position_controller.hpp" +#include "animation_constants.hpp" #include "visual_params.hpp" #include "animation/base_interpolator.hpp" #include "animation/interpolations.hpp" @@ -97,7 +98,6 @@ MyPositionController::MyPositionController(location::EMyPositionMode initMode) , m_positionYOffset(POSITION_Y_OFFSET) , m_isVisible(false) , m_isDirtyViewport(false) - , m_needAnimation(false) { if (initMode > location::MODE_UNKNOWN_POSITION) m_afterPendingMode = initMode; @@ -157,8 +157,6 @@ void MyPositionController::DragEnded(m2::PointD const & distance) SetModeInfo(ResetModeBit(m_modeInfo, BlockAnimation)); if (distance.Length() > 0.2 * min(m_pixelRect.SizeX(), m_pixelRect.SizeY())) StopLocationFollow(); - else if (IsModeChangeViewport()) - m_needAnimation = true; Follow(); } @@ -205,10 +203,7 @@ void MyPositionController::ScaleEnded() SetModeInfo(ResetModeBit(m_modeInfo, StopFollowOnActionEnd)); StopLocationFollow(); } - else if (IsModeChangeViewport()) - { - m_needAnimation = true; - } + Follow(); } @@ -333,14 +328,10 @@ void MyPositionController::Render(uint32_t renderMode, ScreenBase const & screen m_isDirtyViewport = false; } - bool const fixedPixelPos = IsModeChangeViewport() && !TestModeBit(m_modeInfo, BlockAnimation) && - !m_needAnimation && !(m_anim != nullptr && m_anim->IsMovingActive()); - - if (fixedPixelPos) - m_shape->SetPosition(screen.PtoG(screen.P3dtoP(GetCurrentPixelBinding()))); - else - m_shape->SetPosition(GetDrawablePosition()); + if (!IsModeChangeViewport()) + m_isPendingAnimation = false; + m_shape->SetPosition(GetDrawablePosition()); m_shape->SetAzimuth(GetDrawableAzimut()); m_shape->SetIsValidAzimuth(IsRotationActive()); m_shape->SetAccuracy(m_errorRadius); @@ -417,11 +408,7 @@ void MyPositionController::Assign(location::GpsInfo const & info, bool isNavigab if (!AlmostCurrentPosition(oldPos) || !AlmostCurrentAzimut(oldAzimut)) { - if (m_needAnimation || !IsModeChangeViewport()) - { - CreateAnim(oldPos, oldAzimut, screen); - m_needAnimation = false; - } + CreateAnim(oldPos, oldAzimut, screen); m_isDirtyViewport = true; } } @@ -561,7 +548,10 @@ m2::PointD MyPositionController::GetDrawablePosition() const if (m_anim && m_anim->IsMovingActive()) return m_anim->GetCurrentPosition(); - return Position(); + if (m_isPendingAnimation) + return m_oldPosition; + + return m_position; } double MyPositionController::GetDrawableAzimut() const @@ -569,6 +559,9 @@ double MyPositionController::GetDrawableAzimut() const if (m_anim && m_anim->IsRotatingActive()) return m_anim->GetCurrentAzimut(); + if (m_isPendingAnimation) + return m_oldDrawDirection; + return m_drawDirection; } @@ -578,14 +571,39 @@ void MyPositionController::CheckAnimFinished() const m_anim.reset(); } +void MyPositionController::AnimationStarted(ref_ptr anim) +{ + if (m_isPendingAnimation && m_animCreator != nullptr && anim != nullptr && + (anim->GetType() == ModelViewAnimationType::FollowAndRotate || + anim->GetType() == ModelViewAnimationType::Default)) + { + m_isPendingAnimation = false; + m_animCreator(); + } +} + void MyPositionController::CreateAnim(m2::PointD const & oldPos, double oldAzimut, ScreenBase const & screen) { double moveDuration = ModelViewAnimation::GetMoveDuration(oldPos, m_position, screen); double rotateDuration = ModelViewAnimation::GetRotateDuration(oldAzimut, m_drawDirection); double maxDuration = max(moveDuration, rotateDuration); - double kMaxMyPositionDuration = 2.0; // in seconds - if (maxDuration > 0.0 && maxDuration < kMaxMyPositionDuration) - m_anim.reset(new MyPositionAnim(oldPos, m_position, moveDuration, oldAzimut, m_drawDirection, rotateDuration)); + if (maxDuration > 0.0 && maxDuration < kMaxAnimationTimeSec) + { + if (IsModeChangeViewport()) + { + m_animCreator = [this, oldPos, moveDuration, oldAzimut, rotateDuration]() + { + m_anim = make_unique_dp(oldPos, m_position, moveDuration, oldAzimut, m_drawDirection, rotateDuration); + }; + m_oldPosition = oldPos; + m_oldDrawDirection = oldAzimut; + m_isPendingAnimation = true; + } + else + { + m_anim = make_unique_dp(oldPos, m_position, moveDuration, oldAzimut, m_drawDirection, rotateDuration); + } + } } void MyPositionController::ActivateRouting() diff --git a/drape_frontend/my_position_controller.hpp b/drape_frontend/my_position_controller.hpp index f139170121..ca2a5ae300 100644 --- a/drape_frontend/my_position_controller.hpp +++ b/drape_frontend/my_position_controller.hpp @@ -11,8 +11,11 @@ #include "base/timer.hpp" +#include "std/function.hpp" + namespace df { +class BaseModelViewAnimation; class MyPositionController { @@ -56,6 +59,7 @@ public: void DragStarted(); void DragEnded(m2::PointD const & distance); + void AnimationStarted(ref_ptr anim); void ScaleStarted(); void Rotated(); void CorrectScalePoint(m2::PointD & pt) const; @@ -137,8 +141,8 @@ private: drape_ptr m_shape; ref_ptr m_listener; - double m_errorRadius; //< error radius in mercator - m2::PointD m_position; //< position in mercator + double m_errorRadius; // error radius in mercator + m2::PointD m_position; // position in mercator double m_drawDirection; my::HighResTimer m_lastGPSBearing; @@ -148,10 +152,16 @@ private: bool m_isVisible; bool m_isDirtyViewport; - bool m_needAnimation; + bool m_isPendingAnimation = false; + + m2::PointD m_oldPosition; // position in mercator + double m_oldDrawDirection; class MyPositionAnim; mutable drape_ptr m_anim; + + using TAnimationCreator = function; + TAnimationCreator m_animCreator; }; } diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 021912a96d..51bde907c1 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -1,4 +1,5 @@ #include "drape_frontend/user_event_stream.hpp" +#include "drape_frontend/animation_constants.hpp" #include "drape_frontend/visual_params.hpp" #include "indexer/scales.hpp" @@ -24,8 +25,6 @@ uint64_t const kDoubleTapPauseMs = 250; uint64_t const kLongTouchMs = 1000; uint64_t const kKineticDelayMs = 500; -double const kMaxAnimationTimeSec = 1.5; // in seconds - float const kForceTapThreshold = 0.75; size_t GetValidTouchesCount(array const & touches) @@ -319,6 +318,8 @@ bool UserEventStream::SetScale(m2::PointD const & pxScaleCenter, double factor, { m_animation.reset(new ScaleAnimation(startRect, endRect, aDuration, mDuration, sDuration, glbScaleCenter, offset)); + if (m_listener) + m_listener->OnAnimationStarted(make_ref(m_animation)); }; ScreenBase screen = GetCurrentScreen(); @@ -429,6 +430,8 @@ bool UserEventStream::SetRect(m2::AnyRectD const & rect, bool isAnim) double aDuration, double mDuration, double sDuration) { m_animation.reset(new ModelViewAnimation(startRect, endRect, aDuration, mDuration, sDuration)); + if (m_listener) + m_listener->OnAnimationStarted(make_ref(m_animation)); }); } @@ -494,6 +497,8 @@ bool UserEventStream::SetFollowAndRotate(m2::PointD const & userPos, m2::PointD { m_animation.reset(new FollowAndRotateAnimation(startRect, targetLocalRect, userPos, screen.GtoP(userPos), pixelPos, azimuth, duration)); + if (m_listener) + m_listener->OnAnimationStarted(make_ref(m_animation)); return false; } } @@ -850,6 +855,8 @@ bool UserEventStream::EndDrag(Touch const & t, bool cancelled) if (m_kineticTimer.TimeElapsedAs().count() >= kKineticDelayMs) { m_animation = m_scroller.CreateKineticAnimation(m_navigator.Screen()); + if (m_listener) + m_listener->OnAnimationStarted(make_ref(m_animation)); m_scroller.CancelGrab(); return false; } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 1327d1e5f2..4b72969bd4 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -256,6 +256,8 @@ public: virtual void CorrectGlobalScalePoint(m2::PointD & pt) const = 0; virtual void CorrectScalePoint(m2::PointD & pt1, m2::PointD & pt2) const = 0; virtual void OnScaleEnded() = 0; + + virtual void OnAnimationStarted(ref_ptr anim) = 0; }; UserEventStream(TIsCountryLoaded const & fn); @@ -363,7 +365,7 @@ private: array m_touches; - unique_ptr m_animation; + drape_ptr m_animation; unique_ptr m_perspectiveAnimation; unique_ptr m_pendingEvent;