diff --git a/map/framework.cpp b/map/framework.cpp index fd0cbff684..644ad87390 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -104,16 +104,6 @@ void Framework::RemoveMap(string const & file) m_model.RemoveMap(file); } -void Framework::StartLocation() -{ - m_informationDisplay.locationState()->OnStartLocation(); -} - -void Framework::StopLocation() -{ - m_informationDisplay.locationState()->OnStopLocation(); -} - void Framework::OnLocationError(location::TLocationError error) {} @@ -146,7 +136,7 @@ void Framework::OnLocationUpdate(location::GpsInfo const & info) state->OnLocationUpdate(rInfo); m_balloonManager.LocationChanged(rInfo); - if (state->GetLocationProcessMode() != location::ELocationDoNothing) + if (state->IsModeChangeViewport()) UpdateUserViewportChanged(); } @@ -164,11 +154,7 @@ void Framework::OnCompassUpdate(location::CompassInfo const & info) void Framework::StopLocationFollow() { - shared_ptr ls = m_informationDisplay.locationState(); - - ls->StopCompassFollowing(); - ls->SetLocationProcessMode(location::ELocationDoNothing); - ls->SetIsCentered(false); + m_informationDisplay.locationState()->StopLocationFollow(); } InformationDisplay & Framework::GetInformationDisplay() @@ -908,13 +894,14 @@ void Framework::StartDrag(DragEvent const & e) #endif m_navigator.StartDrag(pt, ElapsedSeconds()); + m_informationDisplay.locationState()->DragStarted(); if (m_renderPolicy) m_renderPolicy->StartDrag(); - shared_ptr locationState = m_informationDisplay.locationState(); - m_dragCompassProcessMode = locationState->GetCompassProcessMode(); - m_dragLocationProcessMode = locationState->GetLocationProcessMode(); +// shared_ptr locationState = m_informationDisplay.locationState(); +// m_dragCompassProcessMode = locationState->GetCompassProcessMode(); +// m_dragLocationProcessMode = locationState->GetLocationProcessMode(); } void Framework::DoDrag(DragEvent const & e) @@ -926,12 +913,7 @@ void Framework::DoDrag(DragEvent const & e) #endif m_navigator.DoDrag(pt, ElapsedSeconds()); - - shared_ptr locationState = m_informationDisplay.locationState(); - - locationState->SetIsCentered(false); - locationState->StopCompassFollowing(); - locationState->SetLocationProcessMode(location::ELocationDoNothing); + m_informationDisplay.locationState()->Draged(); if (m_renderPolicy) m_renderPolicy->DoDrag(); @@ -946,24 +928,7 @@ void Framework::StopDrag(DragEvent const & e) #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pt); #endif - - shared_ptr locationState = m_informationDisplay.locationState(); - - if (m_dragLocationProcessMode != location::ELocationDoNothing) - { - // reset GPS centering mode if we have dragged far from current location - ScreenBase const & s = m_navigator.Screen(); - if (GetPixelCenter().Length(s.GtoP(locationState->Position())) >= s.GetMinPixelRectSize() / 5.0) - locationState->SetLocationProcessMode(location::ELocationDoNothing); - else - { - locationState->SetLocationProcessMode(m_dragLocationProcessMode); - if (m_dragCompassProcessMode == location::ECompassFollow) - locationState->AnimateToPositionAndEnqueueFollowing(); - else - locationState->AnimateToPosition(); - } - } + m_informationDisplay.locationState()->DragEnded(); if (m_renderPolicy) { @@ -995,6 +960,7 @@ void Framework::StopRotate(RotateEvent const & e) if (m_renderPolicy && m_renderPolicy->DoSupportRotation()) { m_navigator.StopRotate(e.Angle(), ElapsedSeconds()); + m_informationDisplay.locationState()->Rotated(); m_renderPolicy->StopRotate(e.Angle(), ElapsedSeconds()); UpdateUserViewportChanged(); @@ -1013,9 +979,8 @@ void Framework::Move(double azDir, double factor) //@{ void Framework::ScaleToPoint(ScaleToPointEvent const & e) { - shared_ptr locationState = m_informationDisplay.locationState(); - m2::PointD const pt = (locationState->GetLocationProcessMode() == location::ELocationDoNothing) ? - m_navigator.ShiftPoint(e.Pt()) : GetPixelCenter(); + m2::PointD pt = m_navigator.ShiftPoint(e.Pt()); + m_informationDisplay.locationState()->ScaleCorrection(pt); m_animController->AddTask(m_navigator.ScaleToPointAnim(pt, e.ScaleFactor(), 0.25)); @@ -1041,16 +1006,7 @@ void Framework::CalcScalePoints(ScaleEvent const & e, m2::PointD & pt1, m2::Poin pt1 = m_navigator.ShiftPoint(e.Pt1()); pt2 = m_navigator.ShiftPoint(e.Pt2()); - shared_ptr locationState = m_informationDisplay.locationState(); - - if (locationState->HasPosition() - && (locationState->GetLocationProcessMode() == location::ELocationCenterOnly)) - { - m2::PointD const ptC = (pt1 + pt2) / 2; - m2::PointD const ptDiff = GetPixelCenter() - ptC; - pt1 += ptDiff; - pt2 += ptDiff; - } + m_informationDisplay.locationState()->ScaleCorrection(pt1, pt2); #ifdef DRAW_TOUCH_POINTS m_informationDisplay.setDebugPoint(0, pt1); @@ -1077,11 +1033,8 @@ void Framework::DoScale(ScaleEvent const & e) if (m_renderPolicy) m_renderPolicy->DoScale(); - shared_ptr locationState = m_informationDisplay.locationState(); - - if (m_navigator.IsRotatingDuringScale() - && (locationState->GetCompassProcessMode() == location::ECompassFollow)) - locationState->StopCompassFollowing(); + if (m_navigator.IsRotatingDuringScale()) + m_informationDisplay.locationState()->Rotated(); } void Framework::StopScale(ScaleEvent const & e) @@ -1349,7 +1302,7 @@ bool Framework::GetCurrentPosition(double & lat, double & lon) const { shared_ptr locationState = m_informationDisplay.locationState(); - if (locationState->HasPosition()) + if (locationState->IsModeHasPosition()) { m2::PointD const pos = locationState->Position(); lat = MercatorBounds::YToLat(pos.y); @@ -1891,7 +1844,7 @@ UserMark const * Framework::GetUserMark(m2::PointD const & pxPoint, bool isLongP m_navigator.GetTouchRect(pxPoint, TOUCH_PIXEL_RADIUS * GetVisualScale(), rect); shared_ptr const & locationState = GetLocationState(); - if (locationState->HasPosition()) + if (locationState->IsModeHasPosition()) { m2::PointD const & glPivot = locationState->Position(); if (rect.IsPointInside(glPivot)) diff --git a/map/framework.hpp b/map/framework.hpp index c4a1e653f8..db5dd7bb8d 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -110,9 +110,6 @@ protected: int m_width; int m_height; - location::ECompassProcessMode m_dragCompassProcessMode; - location::ELocationProcessMode m_dragLocationProcessMode; - void StopLocationFollow(); storage::Storage m_storage; @@ -215,10 +212,6 @@ public: /// @name GPS location updates routine. //@{ - - void StartLocation(); - void StopLocation(); - void OnLocationError(location::TLocationError error); void OnLocationUpdate(location::GpsInfo const & info); void OnCompassUpdate(location::CompassInfo const & info); @@ -391,9 +384,9 @@ public: /// @name Drag implementation. //@{ -private: - m2::PointD GetPixelCenter() const; public: + m2::PointD GetPixelCenter() const; + void StartDrag(DragEvent const & e); void DoDrag(DragEvent const & e); void StopDrag(DragEvent const & e); diff --git a/map/location_state.cpp b/map/location_state.cpp index 7c308540a9..b9c879c863 100644 --- a/map/location_state.cpp +++ b/map/location_state.cpp @@ -22,428 +22,459 @@ namespace location { -// namespace -// { -// const float MaxPositionFault = 25.0; -// const float MaxHeadingFaultDeg = 3.0; -// } - double const State::s_cacheRadius = 500; +namespace +{ - State::Params::Params() - : m_locationAreaColor(0, 0, 0, 0), - m_framework(0) - {} +uint16_t IncludeModeBit(uint16_t mode, uint16_t bit) +{ + return mode | bit; +} - State::State(Params const & p) - : BaseT(p), - m_errorRadius(0), - m_position(0, 0), - m_drawHeading(0.0), - m_hasPosition(false), - m_hasCompass(false), - m_isCentered(false), - m_isFirstPosition(false), - m_currentSlotID(0), - m_locationProcessMode(ELocationDoNothing), - m_compassProcessMode(ECompassDoNothing) +uint16_t ExcludeModeBit(uint16_t mode, uint16_t bit) +{ + return mode & (~bit); +} + +State::Mode ExcludeAllBits(uint16_t mode) +{ + return (State::Mode)(mode & 0xF); +} + +uint16_t ChangeMode(uint16_t mode, State::Mode newMode) +{ + return (mode & 0xF0) | newMode; +} + +bool TestModeBit(uint16_t mode, uint16_t bit) +{ + return (mode & bit) != 0; +} + +} + +State::Params::Params() + : m_locationAreaColor(0, 0, 0, 0), + m_framework(0) +{} + +State::State(Params const & p) + : TBase(p), + m_modeInfo(UnknowPosition), + m_errorRadius(0), + m_position(0, 0), + m_drawDirection(0.0), + m_currentSlotID(0) +{ + m_locationAreaColor = p.m_locationAreaColor; + m_framework = p.m_framework; + + setIsVisible(false); +} + +m2::PointD const & State::Position() const +{ + return m_position; +} + +State::Mode State::GetMode() const +{ + return ExcludeAllBits(m_modeInfo); +} + +bool State::IsModeChangeViewport() const +{ + return !(GetMode() < Follow); +} + +bool State::IsModeHasPosition() const +{ + return !(GetMode() < NotFollow); +} + +void State::SwitchToNextMode() +{ + Mode currentMode = GetMode(); + Mode newMode = currentMode; + switch (currentMode) { - m_locationAreaColor = p.m_locationAreaColor; - m_framework = p.m_framework; - - setState(EActive); - setIsVisible(false); - } - - bool State::HasPosition() const - { - return m_hasPosition; - } - - m2::PointD const & State::Position() const - { - return m_position; - } - - bool State::HasCompass() const - { - return m_hasCompass; - } - - bool State::IsFirstPosition() const - { - return m_isFirstPosition; - } - - void State::TurnOff() - { - m_hasPosition = false; - m_hasCompass = false; - m_isFirstPosition = false; - - setIsVisible(false); - invalidate(); - } - - ELocationProcessMode State::GetLocationProcessMode() const - { - return m_locationProcessMode; - } - - void State::SetLocationProcessMode(ELocationProcessMode mode) - { - m_locationProcessMode = mode; - } - - ECompassProcessMode State::GetCompassProcessMode() const - { - return m_compassProcessMode; - } - - void State::SetCompassProcessMode(ECompassProcessMode mode) - { - bool stateChanged = (m_compassProcessMode != mode); - - m_compassProcessMode = mode; - - if (stateChanged) - CallCompassStatusListeners(mode); - } - - void State::OnLocationUpdate(location::GpsInfo const & info) - { - m_isFirstPosition = false; - m2::RectD rect = MercatorBounds::MetresToXY(info.m_longitude, - info.m_latitude, - info.m_horizontalAccuracy); - m2::PointD const center = rect.Center(); - - m_hasPosition = true; - setIsVisible(true); - m_position = center; - m_errorRadius = rect.SizeX() / 2; - - switch (m_locationProcessMode) - { - case ELocationCenterAndScale: - m_framework->ShowRectExVisibleScale(rect, scales::GetUpperComfortScale()); - - SetIsCentered(true); - CheckCompassFollowing(); - - m_locationProcessMode = ELocationCenterOnly; - break; - - case ELocationCenterOnly: - m_framework->SetViewportCenter(center); - - SetIsCentered(true); - CheckCompassFollowing(); - break; - - case ELocationDoNothing: - break; - } - - CallPositionChangedListeners(m_position); - invalidate(); - } - - void State::OnCompassUpdate(location::CompassInfo const & info) - { - m_hasCompass = true; - if (info.m_trueHeading >= 0.0) - m_drawHeading = info.m_trueHeading; + case UnknowPosition: + newMode = PendingPosition; + break; + case PendingPosition: + newMode = UnknowPosition; + break; + case NotFollow: + newMode = Follow; + break; + case Follow: + if (TestModeBit(m_modeInfo, KnownDirectionBit)) + newMode = RotateAndFollow; else - m_drawHeading = info.m_magneticHeading; - - CheckCompassFollowing(); - - invalidate(); + newMode = UnknowPosition; + break; + case RotateAndFollow: + newMode = UnknowPosition; + break; } - m2::RectD State::GetBoundRect() const + SetModeInfo(ChangeMode(m_modeInfo, newMode)); +} + +void State::RestoreMode() +{ + SetModeInfo(IncludeModeBit(m_modeInfo, ModeNotProcessed)); +} + +void State::TurnOff() +{ + SetModeInfo(UnknowPosition); + setIsVisible(false); + invalidate(); +} + +void State::OnLocationUpdate(location::GpsInfo const & info) +{ + + m2::RectD rect = MercatorBounds::MetresToXY(info.m_longitude, + info.m_latitude, + info.m_horizontalAccuracy); + m2::PointD const center = rect.Center(); + + m_position = center; + m_errorRadius = rect.SizeX() / 2; + + setIsVisible(true); + + if (GetMode() == PendingPosition) + SetModeInfo(IncludeModeBit(ChangeMode(m_modeInfo, Follow), ModeNotProcessed)); + + AnimateCurrentState(); + + CallPositionChangedListeners(m_position); + invalidate(); +} + +void State::OnCompassUpdate(location::CompassInfo const & info) +{ + SetModeInfo(IncludeModeBit(m_modeInfo, KnownDirectionBit)); + + if (info.m_trueHeading >= 0.0) + m_drawDirection = info.m_trueHeading; + else + m_drawDirection = info.m_magneticHeading; + + FollowCompass(); + invalidate(); +} + +void State::CallStateModeListeners() +{ + Mode currentMode = GetMode(); + for (auto it : m_modeListeners) + it.second(currentMode); +} + +int State::AddStateModeListener(TStateModeListener const & l) +{ + int slotID = m_currentSlotID++; + m_modeListeners[slotID] = l; + return slotID; +} + +void State::RemoveStateModeListener(int slotID) +{ + m_modeListeners.erase(slotID); +} + +void State::CallPositionChangedListeners(m2::PointD const & pt) +{ + for (auto it : m_positionListeners) + it.second(pt); +} + +int State::AddPositionChangedListener(State::TPositionListener const & func) +{ + int result = m_currentSlotID++; + m_positionListeners[result] = func; + return result; +} + +void State::RemovePositionChangedListener(int slotID) +{ + m_positionListeners.erase(slotID); +} + +void State::cache() +{ + CachePositionArrow(); + CacheLocationMark(); + + m_controller->GetCacheScreen()->completeCommands(); +} + +void State::purge() +{ + m_positionArrow.reset(); + m_locationMarkDL.reset(); + m_positionMarkDL.reset(); +} + +void State::update() +{ + if (isVisible() && IsModeHasPosition()) { - return m2::RectD(); + m2::PointD const pxPosition = m_framework->GetNavigator().GtoP(Position()); + setPivot(pxPosition); } +} - void State::CallCompassStatusListeners(ECompassProcessMode mode) +void State::draw(graphics::OverlayRenderer * r, + math::Matrix const & m) const +{ + Mode currentMode = GetMode(); + if (currentMode < NotFollow || !isVisible()) + return; + + checkDirtyLayout(); + + m2::PointD const pxPosition = m_framework->GetNavigator().GtoP(Position()); + double const pxErrorRadius = pxPosition.Length( + m_framework->GetNavigator().GtoP(Position() + m2::PointD(m_errorRadius, 0.0))); + + double const drawScale = pxErrorRadius / s_cacheRadius; + + math::Matrix locationDrawM = math::Shift( + math::Scale( + math::Identity(), + drawScale, + drawScale), + pivot()); + + math::Matrix const drawM = locationDrawM * m; + // draw error sector + r->drawDisplayList(m_locationMarkDL.get(), drawM); + + // if we know look direction than we draw arrow + if (TestModeBit(m_modeInfo, KnownDirectionBit)) { - for (TCompassStatusListeners::const_iterator it = m_compassStatusListeners.begin(); - it != m_compassStatusListeners.end(); - ++it) - it->second(mode); + double rotateAngle = m_drawDirection + m_framework->GetNavigator().Screen().GetAngle(); + + math::Matrix compassDrawM =math::Shift( + math::Rotate( + math::Identity(), + rotateAngle), + pivot()); + + r->drawDisplayList(m_positionArrow.get(), compassDrawM * m); } + else + r->drawDisplayList(m_positionMarkDL.get(), drawM); +} - int State::AddCompassStatusListener(TCompassStatusListener const & l) +void State::CachePositionArrow() +{ + graphics::Screen * cacheScreen = m_controller->GetCacheScreen(); + graphics::Icon::Info info("current-position-compas"); + + graphics::Resource const * res = cacheScreen->fromID(cacheScreen->findInfo(info)); + m2::RectU rect = res->m_texRect; + m2::PointD halfArrowSize(rect.SizeX() / 2.0, rect.SizeY() / 2.0); + + m_positionArrow.reset(); + m_positionArrow.reset(cacheScreen->createDisplayList()); + + cacheScreen->beginFrame(); + cacheScreen->setDisplayList(m_positionArrow.get()); + + m2::PointD coords[4] = { - int slotID = m_currentSlotID++; - m_compassStatusListeners[slotID] = l; - return slotID; - } + m2::PointD(-halfArrowSize.x, -halfArrowSize.y), + m2::PointD(-halfArrowSize.x, halfArrowSize.y), + m2::PointD( halfArrowSize.x, -halfArrowSize.y), + m2::PointD( halfArrowSize.x, halfArrowSize.y) + }; - void State::RemoveCompassStatusListener(int slotID) + m2::PointF normal(0.0, 0.0); + shared_ptr texture = cacheScreen->pipeline(res->m_pipelineID).texture(); + + m2::PointF texCoords[4] = { - m_compassStatusListeners.erase(slotID); - } + texture->mapPixel(m2::PointF(rect.minX(), rect.minY())), + texture->mapPixel(m2::PointF(rect.minX(), rect.maxY())), + texture->mapPixel(m2::PointF(rect.maxX(), rect.minY())), + texture->mapPixel(m2::PointF(rect.maxX(), rect.maxY())) + }; - void State::CallPositionChangedListeners(m2::PointD const & pt) + cacheScreen->addTexturedStripStrided(coords, sizeof(m2::PointD), + &normal, 0, + texCoords, sizeof(m2::PointF), + 4, depth(), res->m_pipelineID); + cacheScreen->setDisplayList(0); + cacheScreen->endFrame(); +} + +void State::CacheLocationMark() +{ + graphics::Screen * cacheScreen = m_controller->GetCacheScreen(); + + m_locationMarkDL.reset(); + m_locationMarkDL.reset(cacheScreen->createDisplayList()); + + m_positionMarkDL.reset(); + m_positionMarkDL.reset(cacheScreen->createDisplayList()); + + cacheScreen->beginFrame(); + cacheScreen->setDisplayList(m_locationMarkDL.get()); + + cacheScreen->fillSector(m2::PointD(0, 0), + 0, 2.0 * math::pi, + s_cacheRadius, + m_locationAreaColor, + depth() - 3); + + cacheScreen->setDisplayList(m_positionMarkDL.get()); + cacheScreen->drawSymbol(m2::PointD(0, 0), + "current-position", + graphics::EPosCenter, + depth() - 1); + + cacheScreen->setDisplayList(0); + + cacheScreen->endFrame(); +} + +void State::FollowCompass() +{ + if (!m_framework->GetNavigator().DoSupportRotation()) + return; + + if (TestModeBit(m_modeInfo, KnownDirectionBit) && GetMode() == RotateAndFollow) { - typedef TPositionChangedListeners::const_iterator iter_t; - for (iter_t it = m_callbacks.begin(); it != m_callbacks.end(); ++it) - it->second(pt); - } - - int State::AddPositionChangedListener(State::TPositionChangedCallback const & func) - { - int result = m_currentSlotID++; - m_callbacks[result] = func; - return result; - } - - void State::RemovePositionChangedListener(int slotID) - { - m_callbacks.erase(slotID); - } - - void State::cachePositionArrow() - { - graphics::Screen * cacheScreen = m_controller->GetCacheScreen(); - graphics::Icon::Info info("current-position-compas"); - - graphics::Resource const * res = cacheScreen->fromID(cacheScreen->findInfo(info)); - m2::RectU rect = res->m_texRect; - m2::PointD halfArrowSize(rect.SizeX() / 2.0, rect.SizeY() / 2.0); - - m_positionArrow.reset(); - m_positionArrow.reset(cacheScreen->createDisplayList()); - - cacheScreen->beginFrame(); - cacheScreen->setDisplayList(m_positionArrow.get()); - - m2::PointD coords[4] = - { - m2::PointD(-halfArrowSize.x, -halfArrowSize.y), - m2::PointD(-halfArrowSize.x, halfArrowSize.y), - m2::PointD( halfArrowSize.x, -halfArrowSize.y), - m2::PointD( halfArrowSize.x, halfArrowSize.y) - }; - - m2::PointF normal(0.0, 0.0); - shared_ptr texture = cacheScreen->pipeline(res->m_pipelineID).texture(); - - m2::PointF texCoords[4] = - { - texture->mapPixel(m2::PointF(rect.minX(), rect.minY())), - texture->mapPixel(m2::PointF(rect.minX(), rect.maxY())), - texture->mapPixel(m2::PointF(rect.maxX(), rect.minY())), - texture->mapPixel(m2::PointF(rect.maxX(), rect.maxY())) - }; - - cacheScreen->addTexturedStripStrided(coords, sizeof(m2::PointD), - &normal, 0, - texCoords, sizeof(m2::PointF), - 4, depth(), res->m_pipelineID); - cacheScreen->setDisplayList(0); - cacheScreen->endFrame(); - } - - void State::cacheLocationMark() - { - graphics::Screen * cacheScreen = m_controller->GetCacheScreen(); - - m_locationMarkDL.reset(); - m_locationMarkDL.reset(cacheScreen->createDisplayList()); - - m_positionMarkDL.reset(); - m_positionMarkDL.reset(cacheScreen->createDisplayList()); - - cacheScreen->beginFrame(); - cacheScreen->setDisplayList(m_locationMarkDL.get()); - - cacheScreen->fillSector(m2::PointD(0, 0), - 0, 2.0 * math::pi, - s_cacheRadius, - m_locationAreaColor, - depth() - 3); - - cacheScreen->setDisplayList(m_positionMarkDL.get()); - cacheScreen->drawSymbol(m2::PointD(0, 0), - "current-position", - graphics::EPosCenter, - depth() - 1); - - cacheScreen->setDisplayList(0); - - cacheScreen->endFrame(); - } - - void State::cache() - { - cachePositionArrow(); - cacheLocationMark(); - - m_controller->GetCacheScreen()->completeCommands(); - } - - void State::purge() - { - m_positionArrow.reset(); - m_locationMarkDL.reset(); - m_positionMarkDL.reset(); - } - - void State::update() - { - if (isVisible() && m_hasPosition) - { - m2::PointD const pxPosition = m_framework->GetNavigator().GtoP(Position()); - setPivot(pxPosition); - } - } - - void State::draw(graphics::OverlayRenderer * r, - math::Matrix const & m) const - { - if (isVisible()) - { - checkDirtyLayout(); - - if (m_hasPosition) - { - math::Matrix locationDrawM; - - /// then position - m2::PointD const pxPosition = m_framework->GetNavigator().GtoP(Position()); - double const pxErrorRadius = pxPosition.Length( - m_framework->GetNavigator().GtoP(Position() + m2::PointD(m_errorRadius, 0.0))); - - double const drawScale = pxErrorRadius / s_cacheRadius; - - locationDrawM = - math::Shift( - math::Scale( - math::Identity(), - drawScale, - drawScale), - pivot()); - - math::Matrix const drawM = locationDrawM * m; - r->drawDisplayList(m_locationMarkDL.get(), drawM); - - if (HasCompass()) - { - double screenAngle = m_framework->GetNavigator().Screen().GetAngle(); - - math::Matrix compassDrawM; - - double const headingRad = m_drawHeading; - - compassDrawM = - math::Shift( - math::Rotate( - math::Identity(), - screenAngle + headingRad), - pivot()); - - r->drawDisplayList(m_positionArrow.get(), compassDrawM * m); - } - else - r->drawDisplayList(m_positionMarkDL.get(), drawM); - } - } - } - - bool State::hitTest(m2::PointD const & /*pt*/) const - { - return false; - } - - void State::CheckCompassFollowing() - { - if (HasCompass() - && (GetCompassProcessMode() == ECompassFollow) - && IsCentered()) - FollowCompass(); - } - - void State::FollowCompass() - { - if (!m_framework->GetNavigator().DoSupportRotation()) - return; - anim::Controller::Guard guard(m_framework->GetAnimController()); m_framework->GetAnimator().RotateScreen( m_framework->GetNavigator().Screen().GetAngle(), - -m_drawHeading); - } - - void State::AnimateToPosition() - { - m_framework->SetViewportCenterAnimated(Position()); - } - - void State::AnimateToPositionAndEnqueueFollowing() - { - shared_ptr const & t = m_framework->SetViewportCenterAnimated(Position()); - - t->Lock(); - t->AddCallback(anim::Task::EEnded, bind(&State::SetIsCentered, this, true)); - t->AddCallback(anim::Task::EEnded, bind(&State::StartCompassFollowing, this)); - t->Unlock(); - } - - void State::AnimateToPositionAndEnqueueLocationProcessMode(location::ELocationProcessMode mode) - { - shared_ptr const & t = m_framework->SetViewportCenterAnimated(Position()); - - t->Lock(); - t->AddCallback(anim::Task::EEnded, bind(&State::SetIsCentered, this, true)); - t->AddCallback(anim::Task::EEnded, bind(&State::SetLocationProcessMode, this, mode)); - t->Unlock(); - } - - void State::StartCompassFollowing() - { - SetCompassProcessMode(ECompassFollow); - SetLocationProcessMode(ELocationCenterOnly); - - CheckCompassFollowing(); - setState(EPressed); - } - - void State::StopCompassFollowing() - { - SetCompassProcessMode(ECompassDoNothing); - m_framework->GetAnimator().StopRotation(); - m_framework->GetAnimator().StopChangeViewport(); - m_framework->GetAnimator().StopMoveScreen(); - setState(EActive); - } - - bool State::IsCentered() const - { - return m_isCentered; - } - - void State::SetIsCentered(bool flag) - { - m_isCentered = flag; - } - - void State::OnStartLocation() - { - SetCompassProcessMode(location::ECompassDoNothing); - SetLocationProcessMode(location::ELocationCenterAndScale); - m_isFirstPosition = true; - } - - void State::OnStopLocation() - { - SetLocationProcessMode(location::ELocationDoNothing); - SetCompassProcessMode(location::ECompassDoNothing); - m_isFirstPosition = false; - TurnOff(); + -m_drawDirection); } } + +void State::SetModeInfo(uint16_t modeInfo) +{ + bool callModeChanged = GetMode() != ExcludeAllBits(modeInfo); + m_modeInfo = modeInfo; + if (callModeChanged) + { + CallStateModeListeners(); + AnimateCurrentState(); + invalidate(); + } +} + +void State::StopCompassFollowing() +{ + if (GetMode() != RotateAndFollow) + return; + + SetModeInfo(ChangeMode(m_modeInfo, Follow)); + + m_framework->GetAnimator().StopRotation(); + m_framework->GetAnimator().StopChangeViewport(); + m_framework->GetAnimator().StopMoveScreen(); +} + +void State::StopLocationFollow() +{ + if (GetMode() > NotFollow) + SetModeInfo(NotFollow); +} + +void State::DragStarted() +{ + m_dragModeInfo = m_modeInfo; +} + +void State::Draged() +{ + if (GetMode() < Follow) + return; + + StopCompassFollowing(); + SetModeInfo(ChangeMode(m_modeInfo, NotFollow)); +} + +void State::DragEnded() +{ + if (ExcludeAllBits(m_dragModeInfo) < Follow) + return; + + // reset GPS centering mode if we have dragged far from current location + ScreenBase const & s = m_framework->GetNavigator().Screen(); + m2::PointD const pixelCenter = m_framework->GetPixelCenter(); + if (pixelCenter.Length(s.GtoP(Position())) < s.GetMinPixelRectSize() / 5.0) + SetModeInfo(IncludeModeBit(m_dragModeInfo, ModeNotProcessed)); +} + +void State::ScaleCorrection(m2::PointD & pt) +{ + if (GetMode() > NotFollow) + pt = m_framework->GetPixelCenter(); +} + +void State::ScaleCorrection(m2::PointD & pt1, m2::PointD & pt2) +{ + if (GetMode() > NotFollow) + { + m2::PointD const ptC = (pt1 + pt2) / 2; + m2::PointD const ptDiff = m_framework->GetPixelCenter() - ptC; + pt1 += ptDiff; + pt2 += ptDiff; + } +} + +void State::Rotated() +{ + StopCompassFollowing(); +} + +void State::AnimateCurrentState() +{ + if (TestModeBit(m_modeInfo, ModeNotProcessed)) + { + m2::PointD size(m_errorRadius, m_errorRadius); + m2::RectD rect(m_position - size, m_position + size); + m_framework->ShowRectExVisibleScale(rect, scales::GetUpperComfortScale()); + SetModeInfo(ExcludeModeBit(m_modeInfo, ModeNotProcessed)); + } + else if (GetMode() > NotFollow) + { + m_framework->SetViewportCenter(m_position); + FollowCompass(); + } +} + +//void State::AnimateToPosition() +//{ +// m_framework->SetViewportCenterAnimated(Position()); +//} + +//void State::AnimateToPositionAndEnqueueFollowing() +//{ +// shared_ptr const & t = m_framework->SetViewportCenterAnimated(Position()); + +// t->Lock(); +// t->AddCallback(anim::Task::EEnded, bind(&State::StartCompassFollowing, this)); +// t->Unlock(); +//} + +//void State::AnimateToPositionAndEnqueueLocationProcessMode(location::ELocationProcessMode mode) +//{ +// shared_ptr const & t = m_framework->SetViewportCenterAnimated(Position()); + +// t->Lock(); +// t->AddCallback(anim::Task::EEnded, bind(&State::SetIsCentered, this, true)); +// t->AddCallback(anim::Task::EEnded, bind(&State::SetLocationProcessMode, this, mode)); +// t->Unlock(); +//} + +} diff --git a/map/location_state.hpp b/map/location_state.hpp index 2920ebbbfa..e953349345 100644 --- a/map/location_state.hpp +++ b/map/location_state.hpp @@ -13,127 +13,73 @@ class Framework; namespace graphics { class DisplayList; } -namespace anim { class Task; } namespace location { class GpsInfo; class CompassInfo; - enum ELocationProcessMode - { - ELocationDoNothing = 0, - ELocationCenterAndScale, - ELocationCenterOnly - }; - - enum ECompassProcessMode - { - ECompassDoNothing = 0, - ECompassFollow - }; - // Class, that handles position and compass updates, // centers, scales and rotates map according to this updates // and draws location and compass marks. class State : public gui::Element { - public: - typedef function TCompassStatusListener; - typedef function TPositionChangedCallback; - - private: - - static const double s_cacheRadius; - - double m_errorRadius; //< error radius in mercator - m2::PointD m_position; //< position in mercator - - double m_drawHeading; - - bool m_hasPosition; - bool m_hasCompass; - bool m_isCentered; - bool m_isFirstPosition; - - typedef map TCompassStatusListeners; - TCompassStatusListeners m_compassStatusListeners; - - typedef map TPositionChangedListeners; - TPositionChangedListeners m_callbacks; - int m_currentSlotID; - - void CallPositionChangedListeners(m2::PointD const & pt); - void CallCompassStatusListeners(ECompassProcessMode mode); - - ELocationProcessMode m_locationProcessMode; - ECompassProcessMode m_compassProcessMode; - - typedef gui::Element BaseT; - - graphics::Color m_locationAreaColor; - - Framework * m_framework; - - /// @nameCompass Rendering Parameters - //@{ - unique_ptr m_positionArrow; - unique_ptr m_locationMarkDL; - unique_ptr m_positionMarkDL; - //@} - - void cachePositionArrow(); - void cacheLocationMark(); - - void CheckCompassFollowing(); - void FollowCompass(); + typedef gui::Element TBase; public: - struct Params : BaseT::Params + struct Params : TBase::Params { graphics::Color m_locationAreaColor; Framework * m_framework; Params(); }; + public: + // Do not change the order + enum Mode + { + UnknowPosition = 0x0, + PendingPosition = 0x1, + NotFollow = 0x2, + Follow = 0x4, + RotateAndFollow = 0x8, + }; + + typedef function TStateModeListener; + typedef function TPositionListener; + State(Params const & p); /// @return GPS center point in mercator m2::PointD const & Position() const; - // Заменяем на GetMode() - //{ - bool HasPosition() const; - bool HasCompass() const; - bool IsFirstPosition() const; + Mode GetMode() const; + bool IsModeChangeViewport() const; + bool IsModeHasPosition() const; + void SwitchToNextMode(); + void RestoreMode(); - ELocationProcessMode GetLocationProcessMode() const; - void SetLocationProcessMode(ELocationProcessMode mode); + int AddStateModeListener(TStateModeListener const & l); + void RemoveStateModeListener(int slotID); - ECompassProcessMode GetCompassProcessMode() const; - void SetCompassProcessMode(ECompassProcessMode mode); - //} - - int AddCompassStatusListener(TCompassStatusListener const & l); - void RemoveCompassStatusListener(int slotID); - - int AddPositionChangedListener(TPositionChangedCallback const & func); + int AddPositionChangedListener(TPositionListener const & func); void RemovePositionChangedListener(int slotID); void TurnOff(); - - void StartCompassFollowing(); void StopCompassFollowing(); + void StopLocationFollow(); - void OnStartLocation(); - void OnStopLocation(); + /// @name User input notification block + //@{ + void DragStarted(); + void Draged(); + void DragEnded(); - void SetIsCentered(bool flag); - bool IsCentered() const; + void ScaleCorrection(m2::PointD & pt); + void ScaleCorrection(m2::PointD & pt1, m2::PointD & pt2); - void AnimateToPosition(); - void AnimateToPositionAndEnqueueFollowing(); - void AnimateToPositionAndEnqueueLocationProcessMode(location::ELocationProcessMode mode); + void Rotated(); + //@} /// @name GPS location updates routine. //@{ @@ -143,14 +89,57 @@ namespace location /// @name Override from graphics::OverlayElement and gui::Element. //@{ - virtual m2::RectD GetBoundRect() const; + virtual m2::RectD GetBoundRect() const { return m2::RectD(); } void draw(graphics::OverlayRenderer * r, math::Matrix const & m) const; - bool hitTest(m2::PointD const & pt) const; + bool hitTest(m2::PointD const & /*pt*/) const { return false; } void cache(); void purge(); void update(); //@} + + private: + void AnimateCurrentState(); + + void CallPositionChangedListeners(m2::PointD const & pt); + void CallStateModeListeners(); + + void CachePositionArrow(); + void CacheLocationMark(); + + void FollowCompass(); + void SetModeInfo(uint16_t modeInfo); + + private: + // Mode bits + // { + constexpr static uint16_t const ModeNotProcessed = 0x40; + constexpr static uint16_t const KnownDirectionBit = 0x80; + // } + constexpr static float const s_cacheRadius = 500.0f; + + uint16_t m_modeInfo; // combination of Mode enum and "Mode bits" + uint16_t m_dragModeInfo; + Framework * m_framework; + + double m_errorRadius; //< error radius in mercator + m2::PointD m_position; //< position in mercator + double m_drawDirection; + + typedef map TModeListeners; + typedef map TPositionListeners; + + TModeListeners m_modeListeners; + TPositionListeners m_positionListeners; + int m_currentSlotID; + + /// @nameCompass Rendering Parameters + //@{ + unique_ptr m_positionArrow; + unique_ptr m_locationMarkDL; + unique_ptr m_positionMarkDL; + graphics::Color m_locationAreaColor; + //@} }; }