[core] location state refactoring

This commit is contained in:
ExMix 2014-09-10 12:07:33 +03:00 committed by Alex Zolotarev
parent feaedef14c
commit 333a4967eb
4 changed files with 529 additions and 563 deletions

View file

@ -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<location::State> 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<location::State> locationState = m_informationDisplay.locationState();
m_dragCompassProcessMode = locationState->GetCompassProcessMode();
m_dragLocationProcessMode = locationState->GetLocationProcessMode();
// shared_ptr<location::State> 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<location::State> 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<location::State> 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<location::State> 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<location::State> 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<location::State> 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<location::State> 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<location::State> const & locationState = GetLocationState();
if (locationState->HasPosition())
if (locationState->IsModeHasPosition())
{
m2::PointD const & glPivot = locationState->Position();
if (rect.IsPointInside(glPivot))

View file

@ -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);

View file

@ -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<double, 3, 3> 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<double, 3, 3> locationDrawM = math::Shift(
math::Scale(
math::Identity<double, 3>(),
drawScale,
drawScale),
pivot());
math::Matrix<double, 3, 3> 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<double, 3, 3> compassDrawM =math::Shift(
math::Rotate(
math::Identity<double, 3>(),
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<graphics::gl::BaseTexture> 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<graphics::gl::BaseTexture> 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<double, 3, 3> const & m) const
{
if (isVisible())
{
checkDirtyLayout();
if (m_hasPosition)
{
math::Matrix<double, 3, 3> 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<double, 3>(),
drawScale,
drawScale),
pivot());
math::Matrix<double, 3, 3> const drawM = locationDrawM * m;
r->drawDisplayList(m_locationMarkDL.get(), drawM);
if (HasCompass())
{
double screenAngle = m_framework->GetNavigator().Screen().GetAngle();
math::Matrix<double, 3, 3> compassDrawM;
double const headingRad = m_drawHeading;
compassDrawM =
math::Shift(
math::Rotate(
math::Identity<double, 3>(),
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<MoveScreenTask> 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<MoveScreenTask> 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<MoveScreenTask> 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<MoveScreenTask> 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();
//}
}

View file

@ -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<void(int)> TCompassStatusListener;
typedef function<void (m2::PointD const &)> 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<int, TCompassStatusListener> TCompassStatusListeners;
TCompassStatusListeners m_compassStatusListeners;
typedef map<int, TPositionChangedCallback> 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<graphics::DisplayList> m_positionArrow;
unique_ptr<graphics::DisplayList> m_locationMarkDL;
unique_ptr<graphics::DisplayList> 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<void(Mode)> TStateModeListener;
typedef function<void (m2::PointD const &)> 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<double, 3, 3> 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<int, TStateModeListener> TModeListeners;
typedef map<int, TPositionListener> TPositionListeners;
TModeListeners m_modeListeners;
TPositionListeners m_positionListeners;
int m_currentSlotID;
/// @nameCompass Rendering Parameters
//@{
unique_ptr<graphics::DisplayList> m_positionArrow;
unique_ptr<graphics::DisplayList> m_locationMarkDL;
unique_ptr<graphics::DisplayList> m_positionMarkDL;
graphics::Color m_locationAreaColor;
//@}
};
}