diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 2dec5eb700..83cd8e6bc8 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1168,4 +1168,10 @@ Java_com_mapswithme_maps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv return jni::ToJavaString(env, g_framework->GetPlacePageInfo().FormatCuisines()); } +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, jint right, jint bottom) +{ + frm()->SetVisibleViewport(m2::RectD(left, top, right, bottom)); +} + } // extern "C" diff --git a/android/src/com/mapswithme/maps/Framework.java b/android/src/com/mapswithme/maps/Framework.java index baac6d2441..016dcd5bd5 100644 --- a/android/src/com/mapswithme/maps/Framework.java +++ b/android/src/com/mapswithme/maps/Framework.java @@ -256,4 +256,6 @@ public class Framework public static native boolean nativeIsInChoosePositionMode(); public static native boolean nativeIsDownloadedMapAtScreenCenter(); public static native String nativeGetActiveObjectFormattedCuisine(); + + public static native void nativeSetVisibleRect(int left, int top, int right, int bottom); } diff --git a/android/src/com/mapswithme/maps/MwmActivity.java b/android/src/com/mapswithme/maps/MwmActivity.java index 027f1ccaa1..fbabf108f9 100644 --- a/android/src/com/mapswithme/maps/MwmActivity.java +++ b/android/src/com/mapswithme/maps/MwmActivity.java @@ -3,6 +3,8 @@ package com.mapswithme.maps; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Rect; import android.location.Location; import android.os.Build; import android.os.Bundle; @@ -14,6 +16,7 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; @@ -157,6 +160,83 @@ public class MwmActivity extends BaseMwmFragmentActivity void onTrackLeftAnimation(float offset); } + public interface VisibleRectListener + { + void onVisibleRectChanged(Rect rect); + } + + class VisibleRectMeasurer implements View.OnLayoutChangeListener + { + private VisibleRectListener m_listener; + private Rect mScreenFullRect = null; + private Rect mLastVisibleRect = null; + private boolean mPlacePageVisible = false; + + public VisibleRectMeasurer(VisibleRectListener listener) + { + m_listener = listener; + } + + public void setPlacePageVisible(boolean visible) + { + int orientation = MwmActivity.this.getResources().getConfiguration().orientation; + if(orientation == Configuration.ORIENTATION_LANDSCAPE) + { + mPlacePageVisible = visible; + recalculateVisibleRect(mScreenFullRect); + } + } + + public void setPreviewVisible(boolean visible) + { + int orientation = MwmActivity.this.getResources().getConfiguration().orientation; + if(orientation == Configuration.ORIENTATION_PORTRAIT) + { + mPlacePageVisible = visible; + recalculateVisibleRect(mScreenFullRect); + } + } + + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) + { + mScreenFullRect = new Rect(left, top, right, bottom); + if (mPlacePageVisible && mPlacePage.GetPreview().getVisibility() != View.VISIBLE) + mPlacePageVisible = false; + recalculateVisibleRect(mScreenFullRect); + } + + private void recalculateVisibleRect(Rect r) + { + if (r == null) + return; + + int orientation = MwmActivity.this.getResources().getConfiguration().orientation; + + Rect rect = new Rect(r.left, r.top, r.right, r.bottom); + if (mPlacePageVisible) + { + int[] loc = new int[2]; + mPlacePage.GetPreview().getLocationOnScreen(loc); + + if(orientation == Configuration.ORIENTATION_PORTRAIT) + rect.bottom = loc[1]; + else + rect.left = mPlacePage.GetPreview().getWidth() + loc[0]; + } + + if (mLastVisibleRect == null || !mLastVisibleRect.equals(rect)) + { + mLastVisibleRect = new Rect(rect.left, rect.top, rect.right, rect.bottom); + if (m_listener != null) + m_listener.onVisibleRectChanged(rect); + } + } + } + + private VisibleRectMeasurer mVisibleRectMeasurer; + public static Intent createShowMapIntent(Context context, String countryId, boolean doAutoDownload) { return new Intent(context, DownloadResourcesActivity.class) @@ -338,6 +418,14 @@ public class MwmActivity extends BaseMwmFragmentActivity mSearchController = new FloatingSearchToolbarController(this); processIntent(getIntent()); SharingHelper.prepare(); + + mVisibleRectMeasurer = new VisibleRectMeasurer(new VisibleRectListener() { + @Override + public void onVisibleRectChanged(Rect rect) { + Framework.nativeSetVisibleRect(rect.left, rect.top, rect.right, rect.bottom); + } + }); + getWindow().getDecorView().addOnLayoutChangeListener(mVisibleRectMeasurer); } private void initViews() @@ -1070,6 +1158,8 @@ public class MwmActivity extends BaseMwmFragmentActivity @Override public void onPreviewVisibilityChanged(boolean isVisible) { + mVisibleRectMeasurer.setPreviewVisible(isVisible); + if (isVisible) { if (mMainMenu.isAnimating() || mMainMenu.isOpen()) @@ -1093,6 +1183,8 @@ public class MwmActivity extends BaseMwmFragmentActivity @Override public void onPlacePageVisibilityChanged(boolean isVisible) { + mVisibleRectMeasurer.setPlacePageVisible(isVisible); + Statistics.INSTANCE.trackEvent(isVisible ? Statistics.EventName.PP_OPEN : Statistics.EventName.PP_CLOSE); AlohaHelper.logClick(isVisible ? AlohaHelper.PP_OPEN diff --git a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java index 250000d8b0..bd14f2a079 100644 --- a/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java +++ b/android/src/com/mapswithme/maps/widget/placepage/PlacePageView.java @@ -202,6 +202,8 @@ public class PlacePageView extends RelativeLayout init(attrs, defStyleAttr); } + public ViewGroup GetPreview() { return mPreview; } + private void initViews() { LayoutInflater.from(getContext()).inflate(R.layout.place_page, this); diff --git a/drape/overlay_tree.cpp b/drape/overlay_tree.cpp index 9daf1e229a..275df08525 100644 --- a/drape/overlay_tree.cpp +++ b/drape/overlay_tree.cpp @@ -367,6 +367,23 @@ void OverlayTree::DeleteHandle(ref_ptr const & handle) Erase(handle); } +bool OverlayTree::GetSelectedFeatureRect(ScreenBase const & screen, m2::RectD & featureRect) +{ + if (!m_selectedFeatureID.IsValid()) + return false; + + featureRect.MakeEmpty(); + for (auto const & handle : m_handlesCache) + { + if (handle->IsVisible() && handle->GetFeatureID() == m_selectedFeatureID) + { + m2::RectD rect = handle->GetPixelRect(screen, screen.isPerspective()); + featureRect.Add(rect); + } + } + return true; +} + void OverlayTree::Select(m2::PointD const & glbPoint, TOverlayContainer & result) const { ScreenBase const & screen = m_traits.m_modelView; diff --git a/drape/overlay_tree.hpp b/drape/overlay_tree.hpp index 8a65e18afb..ef669d1a7b 100644 --- a/drape/overlay_tree.hpp +++ b/drape/overlay_tree.hpp @@ -66,6 +66,7 @@ public: void SetDisplacementMode(int displacementMode); void SetSelectedFeature(FeatureID const & featureID); + bool GetSelectedFeatureRect(ScreenBase const & screen, m2::RectD & featureRect); #ifdef COLLECT_DISPLACEMENT_INFO struct DisplacementData diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 42b4b554a2..402a9d732a 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -111,6 +111,13 @@ void DrapeEngine::Resize(int w, int h) ResizeImpl(w, h); } +void DrapeEngine::SetVisibleViewport(m2::RectD const & rect) const +{ + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(rect), + MessagePriority::Normal); +} + void DrapeEngine::Invalidate() { m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index 8eacbbde71..c908b64dec 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -89,6 +89,8 @@ public: void Resize(int w, int h); void Invalidate(); + void SetVisibleViewport(m2::RectD const & rect) const; + void AddTouchEvent(TouchEvent const & event); void Scale(double factor, m2::PointD const & pxPoint, bool isAnim); 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 036019ea90..e79148ff47 100644 --- a/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp +++ b/drape_frontend/drape_frontend_tests/user_event_stream_tests.cpp @@ -38,6 +38,11 @@ public: void OnScaleEnded() override {} void OnTouchMapAction() override {} void OnAnimatedScaleEnded() override {} + bool OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, + m2::PointD & gOffset) override + { + return false; + } void AddUserEvent(df::TouchEvent const & event) { diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 9abb4d2496..e3893092ce 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -387,6 +387,7 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) { ProcessSelection(make_ref(m_selectObjectMessage)); m_selectObjectMessage.reset(); + AddUserEvent(make_unique_dp(m_userEventStream.GetVisibleViewport())); } } break; @@ -452,6 +453,8 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } ProcessSelection(msg); + AddUserEvent(make_unique_dp(m_userEventStream.GetVisibleViewport())); + break; } @@ -718,6 +721,15 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::SetVisibleViewport: + { + ref_ptr msg = message; + AddUserEvent(make_unique_dp(msg->GetRect())); + m_myPositionController->SetVisibleViewport(msg->GetRect()); + m_myPositionController->UpdatePosition(); + break; + } + case Message::Invalidate: { m_myPositionController->ResetRoutingNotFollowTimer(); @@ -843,11 +855,11 @@ void FrontendRenderer::OnResize(ScreenBase const & screen) double const kEps = 1e-5; bool const viewportChanged = !m2::IsEqualSize(m_lastReadedModelView.PixelRectIn3d(), viewportRect, kEps, kEps); - m_myPositionController->UpdatePixelPosition(screen); + m_myPositionController->OnUpdateScreen(screen); if (viewportChanged) { - m_myPositionController->OnNewViewportRect(); + m_myPositionController->UpdatePosition(); m_viewport.SetViewport(0, 0, viewportRect.SizeX(), viewportRect.SizeY()); } @@ -1438,6 +1450,47 @@ void FrontendRenderer::OnTouchMapAction() m_myPositionController->ResetRoutingNotFollowTimer(); } +bool FrontendRenderer::OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) +{ + gOffset = m2::PointD(0, 0); + if (m_myPositionController->IsModeChangeViewport() || m_selectionShape == nullptr) + return false; + + ScreenBase const & screen = m_userEventStream.GetCurrentScreen(); + m2::PointD pos; + + double const vs = VisualParams::Instance().GetVisualScale(); + if (m_selectionShape->IsVisible(screen, pos)) + { + m2::RectD rect(pos, pos); + if (!(m_selectionShape->GetSelectedObject() == SelectionShape::OBJECT_POI && + m_overlayTree->GetSelectedFeatureRect(screen, rect))) + { + double const r = m_selectionShape->GetRadius(); + rect.Inflate(r, r); + } + + if (oldViewport.IsIntersect(rect) && !newViewport.IsRectInside(rect)) + { + double const kOffset = 50 * vs; + m2::PointD pOffset(0.0, 0.0); + if (rect.minX() < newViewport.minX()) + pOffset.x = newViewport.minX() - rect.minX() + kOffset; + else if (rect.maxX() > newViewport.maxX()) + pOffset.x = newViewport.maxX() - rect.maxX() - kOffset; + + if (rect.minY() < newViewport.minY()) + pOffset.y = newViewport.minY() - rect.minY() + kOffset; + else if (rect.maxY() > newViewport.maxY()) + pOffset.y = newViewport.maxY() - rect.maxY() - kOffset; + + gOffset = screen.PtoG(screen.P3dtoP(pos + pOffset)) - screen.PtoG(screen.P3dtoP(pos)); + } + return true; + } + return false; +} + TTilesCollection FrontendRenderer::ResolveTileKeys(ScreenBase const & screen) { m2::RectD const & rect = screen.ClipRect(); @@ -1726,7 +1779,7 @@ void FrontendRenderer::PrepareScene(ScreenBase const & modelView) RefreshZScale(modelView); RefreshPivotTransform(modelView); - m_myPositionController->UpdatePixelPosition(modelView); + m_myPositionController->OnUpdateScreen(modelView); m_routeRenderer->UpdateRoute(modelView, bind(&FrontendRenderer::OnCacheRouteArrows, this, _1, _2)); } diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index 47c443e668..cccc8e4578 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -203,6 +203,7 @@ private: void OnScaleEnded() override; void OnAnimatedScaleEnded() override; void OnTouchMapAction() override; + bool OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) override; class Routine : public threads::IRoutine { diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index e237b93c6c..851608e968 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -63,7 +63,8 @@ public: SetDisplacementMode, AllowAutoZoom, RequestSymbolsSize, - RecoverGLResources + RecoverGLResources, + SetVisibleViewport }; virtual ~Message() {} diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index 67ad21e1f1..03c418a634 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -794,6 +794,20 @@ public: bool IsGLContextDependent() const override { return true; } }; +class SetVisibleViewportMessage : public Message +{ +public: + SetVisibleViewportMessage(m2::RectD const & rect) + : m_rect(rect) + {} + + Type GetType() const override { return Message::SetVisibleViewport; } + m2::RectD const & GetRect() const { return m_rect; } + +private: + m2::RectD m_rect; +}; + class DeactivateRouteFollowingMessage : public Message { public: diff --git a/drape_frontend/my_position_controller.cpp b/drape_frontend/my_position_controller.cpp index 592ea95390..ea2fc4befe 100644 --- a/drape_frontend/my_position_controller.cpp +++ b/drape_frontend/my_position_controller.cpp @@ -167,15 +167,22 @@ MyPositionController::~MyPositionController() { } -void MyPositionController::OnNewViewportRect() +void MyPositionController::UpdatePosition() { UpdateViewport(kDoNotChangeZoom); } -void MyPositionController::UpdatePixelPosition(ScreenBase const & screen) +void MyPositionController::OnUpdateScreen(ScreenBase const & screen) { m_pixelRect = screen.isPerspective() ? screen.PixelRectIn3d() : screen.PixelRect(); m_positionYOffset = screen.isPerspective() ? kPositionOffsetYIn3D : kPositionOffsetY; + if (m_visiblePixelRect.IsEmptyInterior()) + m_visiblePixelRect = m_pixelRect; +} + +void MyPositionController::SetVisibleViewport(const m2::RectD &rect) +{ + m_visiblePixelRect = rect; } void MyPositionController::SetListener(ref_ptr listener) @@ -344,7 +351,7 @@ void MyPositionController::NextMode(ScreenBase const & screen) if (!m_isInRouting) { ChangeMode(location::Follow); - ChangeModelView(m_position, 0.0, m_pixelRect.Center(), preferredZoomLevel); + ChangeModelView(m_position, 0.0, m_visiblePixelRect.Center(), preferredZoomLevel); } } } @@ -399,7 +406,7 @@ void MyPositionController::OnLocationUpdate(location::GpsInfo const & info, bool ChangeModelView(m_position, kDoNotChangeZoom); else if (m_mode == location::FollowAndRotate) ChangeModelView(m_position, m_drawDirection, - m_isInRouting ? GetRoutingRotationPixelCenter() : m_pixelRect.Center(), kDoNotChangeZoom); + m_isInRouting ? GetRoutingRotationPixelCenter() : m_visiblePixelRect.Center(), kDoNotChangeZoom); } } else if (m_mode == location::PendingPosition || m_mode == location::NotFollowNoPosition) @@ -635,7 +642,7 @@ void MyPositionController::OnCompassTapped() if (m_mode == location::FollowAndRotate) { ChangeMode(location::Follow); - ChangeModelView(m_position, 0.0, m_pixelRect.Center(), kDoNotChangeZoom); + ChangeModelView(m_position, 0.0, m_visiblePixelRect.Center(), kDoNotChangeZoom); } else { @@ -688,24 +695,24 @@ void MyPositionController::UpdateViewport(int zoomLevel) ChangeModelView(m_position, zoomLevel); else if (m_mode == location::FollowAndRotate) ChangeModelView(m_position, m_drawDirection, - m_isInRouting ? GetRoutingRotationPixelCenter() : m_pixelRect.Center(), zoomLevel); + m_isInRouting ? GetRoutingRotationPixelCenter() : m_visiblePixelRect.Center(), zoomLevel); } m2::PointD MyPositionController::GetRotationPixelCenter() const { if (m_mode == location::Follow) - return m_pixelRect.Center(); + return m_visiblePixelRect.Center(); if (m_mode == location::FollowAndRotate) - return m_isInRouting ? GetRoutingRotationPixelCenter() : m_pixelRect.Center(); + return m_isInRouting ? GetRoutingRotationPixelCenter() : m_visiblePixelRect.Center(); return m2::PointD::Zero(); } m2::PointD MyPositionController::GetRoutingRotationPixelCenter() const { - return m2::PointD(m_pixelRect.Center().x, - m_pixelRect.maxY() - m_positionYOffset * VisualParams::Instance().GetVisualScale()); + return m2::PointD(m_visiblePixelRect.Center().x, + m_visiblePixelRect.maxY() - m_positionYOffset * VisualParams::Instance().GetVisualScale()); } m2::PointD MyPositionController::GetDrawablePosition() @@ -806,7 +813,7 @@ void MyPositionController::DeactivateRouting() m_isInRouting = false; ChangeMode(location::Follow); - ChangeModelView(m_position, 0.0, m_pixelRect.Center(), kDoNotChangeZoom); + ChangeModelView(m_position, 0.0, m_visiblePixelRect.Center(), kDoNotChangeZoom); } } diff --git a/drape_frontend/my_position_controller.hpp b/drape_frontend/my_position_controller.hpp index 51d9ff75ef..1f11c1e7b7 100644 --- a/drape_frontend/my_position_controller.hpp +++ b/drape_frontend/my_position_controller.hpp @@ -44,8 +44,10 @@ public: bool isFirstLaunch, bool isRoutingActive, bool isAutozoomEnabled); ~MyPositionController(); - void OnNewViewportRect(); - void UpdatePixelPosition(ScreenBase const & screen); + void UpdatePosition(); + void OnUpdateScreen(ScreenBase const & screen); + void SetVisibleViewport(m2::RectD const & rect); + void SetListener(ref_ptr listener); m2::PointD const & Position() const; @@ -97,12 +99,12 @@ public: bool IsInRouting() const { return m_isInRouting; } bool IsRouteFollowingActive() const; bool IsWaitingForTimers() const; + bool IsModeChangeViewport() const; bool IsWaitingForLocation() const; m2::PointD GetDrawablePosition(); private: - bool IsModeChangeViewport() const; void ChangeMode(location::EMyPositionMode newMode); void SetDirection(double bearing); @@ -161,6 +163,7 @@ private: double m_lastLocationTimestamp; m2::RectD m_pixelRect; + m2::RectD m_visiblePixelRect; double m_positionYOffset; bool m_isVisible; diff --git a/drape_frontend/selection_shape.cpp b/drape_frontend/selection_shape.cpp index caafa84566..715cb73460 100644 --- a/drape_frontend/selection_shape.cpp +++ b/drape_frontend/selection_shape.cpp @@ -104,10 +104,10 @@ SelectionShape::SelectionShape(ref_ptr mng) batcher.InsertTriangleList(state, make_ref(&provider), nullptr); } - double r = 15.0f * VisualParams::Instance().GetVisualScale(); - m_mapping.AddRangePoint(0.6, 1.3 * r); - m_mapping.AddRangePoint(0.85, 0.8 * r); - m_mapping.AddRangePoint(1.0, r); + m_radius = 15.0f * VisualParams::Instance().GetVisualScale(); + m_mapping.AddRangePoint(0.6, 1.3 * m_radius); + m_mapping.AddRangePoint(0.85, 0.8 * m_radius); + m_mapping.AddRangePoint(1.0, m_radius); } void SelectionShape::Show(ESelectedObject obj, m2::PointD const & position, double positionZ, bool isAnimate) @@ -128,6 +128,20 @@ void SelectionShape::Hide() m_selectedObject = OBJECT_EMPTY; } +bool SelectionShape::IsVisible(ScreenBase const & screen, m2::PointD & pxPos) const +{ + m2::PointD const pt = screen.GtoP(m_position); + ShowHideAnimation::EState state = m_animation.GetState(); + + if ((state == ShowHideAnimation::STATE_VISIBLE || state == ShowHideAnimation::STATE_SHOW_DIRECTION) && + !screen.IsReverseProjection3d(pt)) + { + pxPos = screen.PtoP3d(pt, -m_positionZ); + return true; + } + return false; +} + void SelectionShape::Render(ScreenBase const & screen, int zoomLevel, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms) { diff --git a/drape_frontend/selection_shape.hpp b/drape_frontend/selection_shape.hpp index 3f47a10c3a..5655033ae1 100644 --- a/drape_frontend/selection_shape.hpp +++ b/drape_frontend/selection_shape.hpp @@ -38,6 +38,9 @@ public: void Render(ScreenBase const & screen, int zoomLevel, ref_ptr mng, dp::UniformValuesStorage const & commonUniforms); + bool IsVisible(ScreenBase const & screen, m2::PointD & pxPos) const; + double GetRadius() const { return m_radius; } + ESelectedObject GetSelectedObject() const; private: @@ -46,6 +49,7 @@ private: private: m2::PointD m_position; double m_positionZ; + double m_radius; ShowHideAnimation m_animation; ESelectedObject m_selectedObject; diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index 4108da46e1..1f10bebd42 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -180,6 +180,8 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool { ref_ptr resizeEvent = make_ref(e); m_navigator.OnSize(resizeEvent->GetWidth(), resizeEvent->GetHeight()); + if (!m_visibleViewport.IsValid()) + m_visibleViewport = m2::RectD(0, 0, resizeEvent->GetWidth(), resizeEvent->GetHeight()); viewportChanged = true; breakAnim = true; TouchCancel(m_touches); @@ -236,6 +238,21 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChanged, bool SetAutoPerspective(perspectiveEvent->IsAutoPerspective()); } break; + case UserEvent::EventType::VisibleViewport: + { + ref_ptr viewportEvent = make_ref(e); + m2::RectD const prevVisibleViewport = m_visibleViewport; + m_visibleViewport = viewportEvent->GetRect(); + m2::PointD gOffset; + if (m_listener->OnNewVisibleViewport(prevVisibleViewport, m_visibleViewport, gOffset)) + { + ScreenBase screen = GetCurrentScreen(); + screen.MoveG(gOffset); + SetScreen(screen, true /* isAnim */); + } + } + break; + default: ASSERT(false, ()); break; @@ -284,6 +301,11 @@ ScreenBase const & UserEventStream::GetCurrentScreen() const return m_navigator.Screen(); } +m2::RectD const & UserEventStream::GetVisibleViewport() const +{ + return m_visibleViewport; +} + bool UserEventStream::OnSetScale(ref_ptr scaleEvent) { double factor = scaleEvent->GetFactor(); @@ -359,12 +381,12 @@ bool UserEventStream::OnSetCenter(ref_ptr centerEvent) if (zoom == kDoNotChangeZoom) { GetTargetScreen(screen); - screen.MatchGandP3d(center, screen.PixelRectIn3d().Center()); + screen.MatchGandP3d(center, m_visibleViewport.Center()); } else { screen.SetFromParams(center, screen.GetAngle(), GetScale(zoom)); - screen.MatchGandP3d(center, screen.PixelRectIn3d().Center()); + screen.MatchGandP3d(center, m_visibleViewport.Center()); } ShrinkAndScaleInto(screen, df::GetWorldRect()); @@ -381,16 +403,19 @@ bool UserEventStream::SetAngle(double azimuth, TAnimationCreator const & paralle { ScreenBase screen; GetTargetScreen(screen); + m2::PointD pt = m_visibleViewport.Center(); + m2::PointD gPt = screen.PtoG(screen.P3dtoP(pt)); + if (screen.isPerspective()) { - m2::PointD pt = screen.PixelRectIn3d().Center(); - return SetFollowAndRotate(screen.PtoG(screen.P3dtoP(pt)), pt, + return SetFollowAndRotate(gPt, pt, azimuth, kDoNotChangeZoom, kDoNotAutoZoom, true /* isAnim */, false /* isAutoScale */, parallelAnimCreator); } screen.SetAngle(azimuth); + screen.MatchGandP3d(gPt, pt); return SetScreen(screen, true /* isAnim */, parallelAnimCreator); } diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index cdf2e04382..98d2fc482c 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -38,7 +38,8 @@ public: Resize, Rotate, FollowAndRotate, - AutoPerspective + AutoPerspective, + VisibleViewport }; virtual ~UserEvent() {} @@ -306,6 +307,21 @@ private: uint32_t m_height; }; +class SetVisibleViewportEvent : public UserEvent +{ +public: + SetVisibleViewportEvent(m2::RectD const & rect) + : m_rect(rect) + {} + + EventType GetType() const override { return UserEvent::EventType::VisibleViewport; } + + m2::RectD const & GetRect() const { return m_rect; } + +private: + m2::RectD m_rect; +}; + class UserEventStream { public: @@ -331,12 +347,15 @@ public: virtual void OnAnimatedScaleEnded() = 0; virtual void OnTouchMapAction() = 0; + + virtual bool OnNewVisibleViewport(m2::RectD const & oldViewport, m2::RectD const & newViewport, m2::PointD & gOffset) = 0; }; UserEventStream(); void AddEvent(drape_ptr && event); ScreenBase const & ProcessEvents(bool & modelViewChanged, bool & viewportChanged); ScreenBase const & GetCurrentScreen() const; + m2::RectD const & GetVisibleViewport() const; void GetTargetScreen(ScreenBase & screen); m2::AnyRectD GetTargetRect(); @@ -444,6 +463,8 @@ private: TEventsList m_events; mutable mutex m_lock; + m2::RectD m_visibleViewport; + Navigator m_navigator; my::Timer m_touchTimer; enum ERecognitionState diff --git a/iphone/Maps/Classes/EAGLView.mm b/iphone/Maps/Classes/EAGLView.mm index 0b9335d684..b00decdafd 100644 --- a/iphone/Maps/Classes/EAGLView.mm +++ b/iphone/Maps/Classes/EAGLView.mm @@ -121,6 +121,8 @@ double getExactDPI(double contentScaleFactor) dispatch_async(dispatch_get_main_queue(), ^ { GetFramework().OnSize(width, height); + // TODO: Temporary realization of visible viewport, this code must be removed later. + GetFramework().SetVisibleViewport(m2::RectD(0.0, 0.0, width, height)); [self.widgetsManager resize:CGSizeMake(width, height)]; self->_drapeEngineCreated = YES; }); diff --git a/map/framework.cpp b/map/framework.cpp index 665f39ac8f..e4686e70af 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -948,6 +948,11 @@ m2::PointD Framework::GetPixelCenter() const : m_currentModelView.PixelRect().Center(); } +m2::PointD Framework::GetVisiblePixelCenter() const +{ + return m_visibleViewport.Center(); +} + m2::PointD const & Framework::GetViewportCenter() const { return m_currentModelView.GetOrg(); @@ -968,6 +973,14 @@ m2::RectD Framework::GetCurrentViewport() const return m_currentModelView.ClipRect(); } +void Framework::SetVisibleViewport(m2::RectD const & rect) +{ + if (m_drapeEngine == nullptr) + return; + m_visibleViewport = rect; + m_drapeEngine->SetVisibleViewport(rect); +} + void Framework::ShowRect(m2::RectD const & rect, int maxScale) { CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewRect, _1, rect, true, maxScale, true)); @@ -1016,7 +1029,7 @@ void Framework::Scale(Framework::EScaleMode mode, m2::PointD const & pxPoint, bo void Framework::Scale(double factor, bool isAnim) { - Scale(factor, GetPixelCenter(), isAnim); + Scale(factor, GetVisiblePixelCenter(), isAnim); } void Framework::Scale(double factor, m2::PointD const & pxPoint, bool isAnim) diff --git a/map/framework.hpp b/map/framework.hpp index 7d0e78fc19..7c5e46a9c6 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -134,6 +134,7 @@ protected: search::QuerySaver m_searchQuerySaver; ScreenBase m_currentModelView; + m2::RectD m_visibleViewport; using TViewportChanged = df::DrapeEngine::TModelViewListenerFn; TViewportChanged m_viewportChanged; @@ -531,12 +532,14 @@ public: void ShowAll(); m2::PointD GetPixelCenter() const; + m2::PointD GetVisiblePixelCenter() const; m2::PointD const & GetViewportCenter() const; void SetViewportCenter(m2::PointD const & pt); void SetViewportCenter(m2::PointD const & pt, int zoomLevel); m2::RectD GetCurrentViewport() const; + void SetVisibleViewport(m2::RectD const & rect); /// - Check minimal visible scale according to downloaded countries. void ShowRect(m2::RectD const & rect, int maxScale = -1);