From b04784b71678a4c96a51e23f875c3ef5ef69bf2b Mon Sep 17 00:00:00 2001 From: ExMix Date: Thu, 13 Mar 2014 09:47:12 +0300 Subject: [PATCH] prev frame animation for ruler --- map/alfa_animation_task.cpp | 10 +- map/alfa_animation_task.hpp | 4 +- map/compass_arrow.cpp | 6 +- map/framework.cpp | 15 - map/framework.hpp | 4 - map/information_display.cpp | 8 - map/information_display.hpp | 1 - map/ruler.cpp | 771 +++++++++++++++++++++--------------- map/ruler.hpp | 101 +++-- 9 files changed, 528 insertions(+), 392 deletions(-) diff --git a/map/alfa_animation_task.cpp b/map/alfa_animation_task.cpp index 0370758b0c..70e0b45489 100644 --- a/map/alfa_animation_task.cpp +++ b/map/alfa_animation_task.cpp @@ -2,7 +2,7 @@ #include "framework.hpp" -AlfaCompassAnim::AlfaCompassAnim(double start, double end, double timeInterval, double timeOffset, Framework * f) +AlfaAnimationTask::AlfaAnimationTask(double start, double end, double timeInterval, double timeOffset, Framework * f) : m_start(start) , m_end(end) , m_current(start) @@ -12,24 +12,24 @@ AlfaCompassAnim::AlfaCompassAnim(double start, double end, double timeInterval, { } -bool AlfaCompassAnim::IsHiding() const +bool AlfaAnimationTask::IsHiding() const { return m_start > m_end; } -float AlfaCompassAnim::GetCurrentAlfa() const +float AlfaAnimationTask::GetCurrentAlfa() const { return m_current; } -void AlfaCompassAnim::OnStart(double ts) +void AlfaAnimationTask::OnStart(double ts) { m_timeStart = ts; base_t::OnStart(ts); m_f->Invalidate(); } -void AlfaCompassAnim::OnStep(double ts) +void AlfaAnimationTask::OnStep(double ts) { base_t::OnStep(ts); double elapsed = ts - (m_timeStart + m_timeOffset); diff --git a/map/alfa_animation_task.hpp b/map/alfa_animation_task.hpp index 151b1f9c3a..cc446fc4b0 100644 --- a/map/alfa_animation_task.hpp +++ b/map/alfa_animation_task.hpp @@ -4,11 +4,11 @@ class Framework; -class AlfaCompassAnim : public anim::Task +class AlfaAnimationTask : public anim::Task { typedef anim::Task base_t; public: - AlfaCompassAnim(double start, double end, double timeInterval, double timeOffset, Framework * f); + AlfaAnimationTask(double start, double end, double timeInterval, double timeOffset, Framework * f); bool IsHiding() const; diff --git a/map/compass_arrow.cpp b/map/compass_arrow.cpp index 45d6f60e7d..0c9261b229 100644 --- a/map/compass_arrow.cpp +++ b/map/compass_arrow.cpp @@ -107,7 +107,7 @@ void CompassArrow::AlfaAnimEnded(bool isVisible) bool CompassArrow::IsHidingAnim() const { ASSERT(m_animTask != NULL, ()); - AlfaCompassAnim * a = static_cast(m_animTask.get()); + AlfaAnimationTask * a = static_cast(m_animTask.get()); return a->IsHiding(); } @@ -115,7 +115,7 @@ float CompassArrow::GetCurrentAlfa() const { if (m_animTask) { - AlfaCompassAnim * a = static_cast(m_animTask.get()); + AlfaAnimationTask * a = static_cast(m_animTask.get()); return a->GetCurrentAlfa(); } @@ -129,7 +129,7 @@ void CompassArrow::CreateAnim(double startAlfa, double endAlfa, double timeInter if (m_animTask) m_animTask->Cancel(); - m_animTask.reset(new AlfaCompassAnim(startAlfa, endAlfa, timeInterval, timeOffset, m_framework)); + m_animTask.reset(new AlfaAnimationTask(startAlfa, endAlfa, timeInterval, timeOffset, m_framework)); m_animTask->AddCallback(anim::Task::EEnded, bind(&CompassArrow::AlfaAnimEnded, this, isVisibleAtEnd)); m_framework->GetAnimController()->AddTask(m_animTask); } diff --git a/map/framework.cpp b/map/framework.cpp index ed36c3b237..5d06a6e527 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -179,18 +179,6 @@ Framework::Framework() : m_navigator(m_scales), m_animator(this), m_queryMaxScaleMode(false), - - /// @todo It's not a class state, so no need to store it in memory. - /// Move this constants to Ruler (and don't store them at all). - m_metresMinWidth(10), - m_metresMaxWidth(1000000), - -#if defined(OMIM_OS_DESKTOP) - m_minRulerWidth(97), -#else - m_minRulerWidth(60), -#endif - m_width(0), m_height(0), m_informationDisplay(this), @@ -229,9 +217,6 @@ Framework::Framework() #ifdef DRAW_TOUCH_POINTS m_informationDisplay.enableDebugPoints(true); #endif - - m_informationDisplay.setRulerParams(m_minRulerWidth, m_metresMinWidth, m_metresMaxWidth); - m_model.InitClassificator(); // Get all available maps. diff --git a/map/framework.hpp b/map/framework.hpp index 53e3d84a60..d70ea4c50a 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -102,10 +102,6 @@ protected: bool m_queryMaxScaleMode; - double const m_metresMinWidth; - double const m_metresMaxWidth; - int const m_minRulerWidth; - int m_width; int m_height; diff --git a/map/information_display.cpp b/map/information_display.cpp index b3ffd59ed2..1ba9fa323d 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -49,7 +49,6 @@ InformationDisplay::InformationDisplay(Framework * fw) InitDebugLabel(); enableDebugPoints(false); - enableRuler(false); enableDebugInfo(false); enableMemoryWarning(false); enableBenchmarkInfo(false); @@ -203,13 +202,6 @@ bool InformationDisplay::isRulerEnabled() const return m_ruler->isVisible(); } -void InformationDisplay::setRulerParams(unsigned pxMinWidth, double metresMinWidth, double metresMaxWidth) -{ - m_ruler->setMinPxWidth(pxMinWidth); - m_ruler->setMinMetersWidth(metresMinWidth); - m_ruler->setMaxMetersWidth(metresMaxWidth); -} - void InformationDisplay::setVisualScale(double visualScale) { m_visualScale = visualScale; diff --git a/map/information_display.hpp b/map/information_display.hpp index 1c153c4570..54143ca557 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -114,7 +114,6 @@ public: void enableRuler(bool doEnable); bool isRulerEnabled() const; - void setRulerParams(unsigned pxMinWidth, double metresMinWidth, double metresMaxWidth); void enableDebugInfo(bool doEnable); void setDebugInfo(double frameDuration, int currentScale); diff --git a/map/ruler.cpp b/map/ruler.cpp index d46c4a59bc..048659c440 100644 --- a/map/ruler.cpp +++ b/map/ruler.cpp @@ -26,6 +26,15 @@ namespace { + static const int32_t MinPixelWidth = 60; + static const int32_t MinMetersWidth = 10; + static const int32_t MaxMetersWidth = 1000000; + static const int32_t CacheLength = 500; + + static const int32_t MinUnitValue = -1; + static const int32_t MaxUnitValue = numeric_limits::max() - 1; + static const int32_t InvalidUnitValue = MaxUnitValue + 1; + struct UnitValue { char const * m_s; @@ -33,6 +42,9 @@ namespace }; UnitValue g_arrFeets[] = { + { "10 ft", 10 }, + { "20 ft", 20 }, + { "50 ft", 50 }, { "100 ft", 100 }, { "200 ft", 200 }, { "0.1 mi", 528 }, @@ -67,6 +79,10 @@ namespace }; UnitValue g_arrMetres[] = { + { "1 m", 1 }, + { "2 m", 2 }, + { "5 m", 5 }, + { "10 m", 10 }, { "20 m", 20 }, { "50 m", 50 }, { "100 m", 100 }, @@ -90,90 +106,425 @@ namespace } } -void Ruler::AlfaAnimEnded(bool isVisible) +// ========================================================= // +Ruler::RulerFrame::RulerFrame(Framework & f, const Ruler::RulerFrame::frame_end_fn & fn, double depth) + : m_f(f) + , m_scale(0.0) + , m_depth(depth) + , m_callback(fn) { - setIsVisible(isVisible); - m_rulerAnim.reset(); } -bool Ruler::IsHidingAnim() const + +Ruler::RulerFrame::RulerFrame(const Ruler::RulerFrame & other, const Ruler::RulerFrame::frame_end_fn & fn) + : m_f(other.m_f) { - ASSERT(m_rulerAnim != NULL, ()); - AlfaCompassAnim * a = static_cast(m_rulerAnim.get()); + m_dl = other.m_dl; + m_textDL = other.m_textDL; + m_scale = other.m_scale; + m_depth = other.m_depth; + m_orgPt = other.m_orgPt; + m_callback = fn; + HideAnimate(false); +} + +Ruler::RulerFrame::~RulerFrame() +{ + if (m_frameAnim) + { + m_frameAnim->Cancel(); + m_frameAnim.reset(); + } + + Purge(); +} + +bool Ruler::RulerFrame::IsValid() const +{ + return m_dl != NULL && m_textDL != NULL; +} + +void Ruler::RulerFrame::Cache(const string & text, graphics::FontDesc const & f) +{ + gui::Controller * controller = m_f.GetGuiController(); + graphics::Screen * cs = controller->GetCacheScreen(); + double k = m_f.GetVisualScale(); + { + m_dl.reset(); + m_dl.reset(cs->createDisplayList()); + + cs->beginFrame(); + + cs->setDisplayList(m_dl.get()); + + cs->applyVarAlfaStates(); + + double halfLength = CacheLength / 2.0; + + graphics::GlyphKey key(strings::LastUniChar("0"), f.m_size, f.m_isMasked, f.m_color); + graphics::Glyph::Info glyphInfo(key, controller->GetGlyphCache()); + uint32_t zeroMarkGlyph = cs->mapInfo(glyphInfo); + graphics::Resource const * glyphRes = cs->fromID(zeroMarkGlyph); + + m2::RectI glyphRect(glyphRes->m_texRect); + double glyphHalfW = glyphRect.SizeX() / 2.0; + double glyphHalfH = glyphRect.SizeY() / 2.0; + double zeroMarkOffset = (glyphHalfH + 2) + 5 * k; + + graphics::Brush::Info brushInfo(graphics::Color(3, 3, 3, 255)); + uint32_t brushId = cs->mapInfo(brushInfo); + graphics::Resource const * brushRes = cs->fromID(brushId); + m2::RectU brushRect = brushRes->m_texRect; + + shared_ptr glyphTexture = cs->pipeline(glyphRes->m_pipelineID).texture(); + m2::PointF brushCenter = cs->pipeline(brushRes->m_pipelineID).texture()->mapPixel(brushRect.Center()); + + // 0 1 10 11 18 17 + // -- -- -- + // || || || + // || 3, 6 9||8, 12 16||14 + // 2|--------- -------------| + // | | + // | | + // 4-------------------------- + // 5 7, 13 15 + + m2::PointD coords[] = + { + // Zero mark geometry + /*-4*/ m2::PointD(0.0, -zeroMarkOffset), + /*-3*/ m2::PointD(0.0, -zeroMarkOffset), + /*-2*/ m2::PointD(0.0, -zeroMarkOffset), + /*-1*/ m2::PointD(0.0, -zeroMarkOffset), + // Ruler geometry + /* 0*/ m2::PointD(0.0, -5.0 * k), + /* 1*/ m2::PointD(0.0, -5.0 * k), + /* 2*/ m2::PointD(0.0, -3.0 * k), + /* 3*/ m2::PointD(0.0, -3.0 * k), + /* 4*/ m2::PointD(0.0, 0.0), + /* 5*/ m2::PointD(0.0, 0.0), + /* 6*/ m2::PointD(0.0, -3.0 * k), + /* 7*/ m2::PointD(halfLength - 0.5, 0.0), + /* 8*/ m2::PointD(halfLength - 0.5, -3.0 * k), + /* 9*/ m2::PointD(halfLength - 0.5, -3.0 * k), + /*10*/ m2::PointD(halfLength - 0.5, -7.0 * k), + /*11*/ m2::PointD(halfLength - 0.5, -7.0 * k), + /*12*/ m2::PointD(halfLength - 0.5, -3.0 * k), + /*13*/ m2::PointD(halfLength - 0.5, 0.0 * k), + /*14*/ m2::PointD(CacheLength, -3.0 * k), + /*15*/ m2::PointD(CacheLength, 0.0 * k), + /*16*/ m2::PointD(CacheLength, -3.0 * k), + /*17*/ m2::PointD(CacheLength, -5.0 * k), + /*18*/ m2::PointD(CacheLength, -5.0 * k) + }; + + m2::PointF normals[] = + { + // Zero mark normals + /*-4*/ m2::PointF(-glyphHalfW + 1, -glyphHalfH), + /*-3*/ m2::PointF(-glyphHalfW + 1, glyphHalfH), + /*-2*/ m2::PointF( glyphHalfW + 1, -glyphHalfH), + /*-1*/ m2::PointF( glyphHalfW + 1, glyphHalfH), + // Ruler normals + /* 0*/ m2::PointF( 0.0 , 0.0), + /* 1*/ m2::PointF( 1.0 * k , 0.0), + /* 2*/ m2::PointF( 0.0 , 0.0), + /* 3*/ m2::PointF( 1.0 * k , 0.0), + /* 4*/ m2::PointF( 0.0 , 0.0), + /* 5*/ m2::PointF( 1.0 * k , 0.0), + /* 6*/ m2::PointF( 1.0 * k , 0.0), + /* 7*/ m2::PointF( 1.0 * k , 0.0), + /* 8*/ m2::PointF( 1.0 * k , 0.0), + /* 9*/ m2::PointF( 0.0 , 0.0), + /*10*/ m2::PointF( 0.0 , 0.0), + /*11*/ m2::PointF( 1.0 * k , 0.0), + /*12*/ m2::PointF( 1.0 * k , 0.0), + /*13*/ m2::PointF( 1.0 * k , 0.0), + /*14*/ m2::PointF( 0.0 , 0.0), + /*15*/ m2::PointF( 0.0 , 0.0), + /*16*/ m2::PointF(-1.0 * k , 0.0), + /*17*/ m2::PointF( 0.0 , 0.0), + /*18*/ m2::PointF(-1.0 * k , 0.0) + }; + + vector texCoords(ARRAY_SIZE(normals), brushCenter); + texCoords[0] = glyphTexture->mapPixel(m2::PointF(glyphRect.minX(), glyphRect.minY())); + texCoords[1] = glyphTexture->mapPixel(m2::PointF(glyphRect.minX(), glyphRect.maxY())); + texCoords[2] = glyphTexture->mapPixel(m2::PointF(glyphRect.maxX(), glyphRect.minY())); + texCoords[3] = glyphTexture->mapPixel(m2::PointF(glyphRect.maxX(), glyphRect.maxY())); + + ASSERT(ARRAY_SIZE(coords) == ARRAY_SIZE(normals), ()); + + cs->addTexturedStripStrided(coords, sizeof(m2::PointD), + normals, sizeof(m2::PointF), + &texCoords[0], sizeof(m2::PointF), 4, + m_depth, glyphRes->m_pipelineID); + + cs->addTexturedStripStrided(coords + 4, sizeof(m2::PointD), + normals + 4, sizeof(m2::PointF), + &texCoords[4], sizeof(m2::PointF), ARRAY_SIZE(coords) - 4, + m_depth, brushRes->m_pipelineID); + + cs->setDisplayList(0); + + cs->applyStates(); + + cs->endFrame(); + } + + // ============================================================ // + + ASSERT(!text.empty(), ()); + + { + m_textDL.reset(); + m_textDL.reset(cs->createDisplayList()); + + cs->beginFrame(); + cs->setDisplayList(m_textDL.get()); + cs->applyVarAlfaStates(); + + strings::UniString uniString = strings::MakeUniString(text); + size_t length = uniString.size(); + buffer_vector infos(length, graphics::Glyph::Info()); + buffer_vector resInfos(length, NULL); + buffer_vector ids(length, 0); + buffer_vector glyphRes(length, NULL); + + for (size_t i = 0; i < uniString.size(); ++i) + { + infos[i] = graphics::Glyph::Info(graphics::GlyphKey(uniString[i], f.m_size, false, f.m_color), + controller->GetGlyphCache()); + + resInfos[i] = &infos[i]; + } + + if (cs->mapInfo(resInfos.data(), ids.data(), infos.size())) + { + uint32_t width = 0; + for (size_t i = 0; i < ids.size(); ++i) + { + graphics::Resource const * res = cs->fromID(ids[i]); + width += res->m_texRect.SizeX(); + glyphRes[i] = res; + } + + int32_t pipelineID = glyphRes[0]->m_pipelineID; + shared_ptr texture = cs->pipeline(pipelineID).texture(); + double halfWidth = width / 2.0; + double lengthFromStart = 0.0; + + buffer_vector coords; + buffer_vector normals; + buffer_vector texCoords; + + for (size_t i = 0; i < uniString.size(); ++i) + { + double baseX = lengthFromStart - halfWidth; + coords.push_back(m2::PointD(baseX, 0.0)); + coords.push_back(m2::PointD(baseX, 0.0)); + coords.push_back(m2::PointD(baseX, 0.0)); + + coords.push_back(m2::PointD(baseX, 0.0)); + coords.push_back(m2::PointD(baseX, 0.0)); + coords.push_back(m2::PointD(baseX, 0.0)); + + m2::RectI resourceRect(glyphRes[i]->m_texRect); + double w = resourceRect.SizeX(); + double h = resourceRect.SizeY(); + lengthFromStart += w; + + normals.push_back(m2::PointF(0.0, 0.0)); + normals.push_back(m2::PointF(0.0, -h)); + normals.push_back(m2::PointF(w , 0.0)); + + normals.push_back(m2::PointF(w , 0.0)); + normals.push_back(m2::PointF(0.0, -h)); + normals.push_back(m2::PointF(w , -h)); + + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.maxY()))); + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.minY()))); + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.maxY()))); + + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.maxY()))); + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.minY()))); + texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.minY()))); + } + + cs->addTexturedListStrided(coords.data(), sizeof(m2::PointF), + normals.data(), sizeof(m2::PointF), + texCoords.data(), sizeof(m2::PointF), + coords.size(), m_depth, pipelineID); + } + + cs->setDisplayList(0); + cs->endFrame(); + } +} + +void Ruler::RulerFrame::Purge() +{ + m_dl.reset(); + m_textDL.reset(); +} + +bool Ruler::RulerFrame::IsHidingAnim() const +{ + ASSERT(m_frameAnim != NULL, ()); + AlfaAnimationTask * a = static_cast(m_frameAnim.get()); return a->IsHiding(); } -float Ruler::GetCurrentAlfa() const +bool Ruler::RulerFrame::IsAnimActive() const { - if (m_rulerAnim) + return m_frameAnim != NULL; +} + +void Ruler::RulerFrame::SetScale(double scale) +{ + m_scale = scale; +} + +double Ruler::RulerFrame::GetScale() const +{ + return m_scale; +} + +void Ruler::RulerFrame::SetOrgPoint(const m2::PointD & org) +{ + m_orgPt = org; +} + +const m2::PointD &Ruler::RulerFrame::GetOrgPoint() const +{ + return m_orgPt; +} + +void Ruler::RulerFrame::ShowAnimate(bool needPause) +{ + double offset = (needPause == true) ? 0.07 : 0.0; + CreateAnim(IsAnimActive() ? GetCurrentAlfa() : 0.1, 1.0, 0.2, offset, true); +} + +void Ruler::RulerFrame::HideAnimate(bool needPause) +{ + double offset = (needPause == true) ? 1.0 : 0.0; + double timeInterval = (needPause == true) ? 0.3 : 0.15; + CreateAnim(1.0, 0.0, timeInterval, offset, false); +} + +void Ruler::RulerFrame::Draw(graphics::OverlayRenderer * r, const math::Matrix & m) +{ + LOG(LINFO, ("Main dl = ", m_dl.get())); + ASSERT(m_dl != NULL, ()); + ASSERT(m_textDL != NULL, ()); + graphics::UniformsHolder holder; + float a = GetCurrentAlfa(); + holder.insertValue(graphics::ETransparency, a); + + r->drawDisplayList(m_dl.get(), math::Shift( + math::Scale(m, m2::PointD(m_scale, 1.0)), + m_orgPt), &holder); + + double yOffset = -(2 + 5 * m_f.GetVisualScale()); + r->drawDisplayList(m_textDL.get(), + math::Shift(m, m_orgPt + m2::PointF(CacheLength * m_scale, yOffset)), + &holder); +} + +void Ruler::RulerFrame::CreateAnim(double startAlfa, double endAlfa, double timeInterval, double timeOffset, bool isVisibleAtEnd) +{ + anim::Controller * animController = m_f.GetAnimController(); + if (animController == NULL) + return; + + if (m_frameAnim) + m_frameAnim->Cancel(); + + m_frameAnim.reset(new AlfaAnimationTask(startAlfa, endAlfa, timeInterval, timeOffset, &m_f)); + m_frameAnim->AddCallback(anim::Task::EEnded, bind(&RulerFrame::AnimEnded, this, isVisibleAtEnd)); + animController->AddTask(m_frameAnim); +} + +float Ruler::RulerFrame::GetCurrentAlfa() +{ + if (m_frameAnim) { - AlfaCompassAnim * a = static_cast(m_rulerAnim.get()); + AlfaAnimationTask * a = static_cast(m_frameAnim.get()); return a->GetCurrentAlfa(); } - return isVisible() ? 1.0 : 0.0; + return 1.0; } -void Ruler::CreateAnim(double startAlfa, double endAlfa, double timeInterval, double timeOffset, bool isVisibleAtEnd) +void Ruler::RulerFrame::AnimEnded(bool isVisible) { - if (m_framework->GetAnimController() == NULL) - return; - - if (m_rulerAnim) - m_rulerAnim->Cancel(); - m_rulerAnim.reset(new AlfaCompassAnim(startAlfa, endAlfa, timeInterval, timeOffset, m_framework)); - m_rulerAnim->AddCallback(anim::Task::EEnded, bind(&Ruler::AlfaAnimEnded, this, isVisibleAtEnd)); - m_framework->GetAnimController()->AddTask(m_rulerAnim); + if (m_frameAnim != NULL) + { + m_frameAnim.reset(); + m_callback(isVisible, this); + } } +// ========================================================= // -void Ruler::CalcMetresDiff(double v) +double Ruler::CalcMetresDiff(double value) { - UnitValue * arrU; - int count; + UnitValue * arrU = g_arrMetres; + int count = ARRAY_SIZE(g_arrMetres); + + typedef double (*ConversionFn)(double); + ConversionFn conversionFn = &identity; switch (m_currSystem) { default: ASSERT_EQUAL ( m_currSystem, 0, () ); - arrU = g_arrMetres; - count = ARRAY_SIZE(g_arrMetres); break; case 1: arrU = g_arrFeets; count = ARRAY_SIZE(g_arrFeets); + conversionFn = &MeasurementUtils::MetersToFeet; break; case 2: arrU = g_arrYards; count = ARRAY_SIZE(g_arrYards); + conversionFn = &MeasurementUtils::MetersToYards; break; } + int prevUnitRange = m_currentRangeIndex; string s; - + double result = 0.0; + double v = conversionFn(value); if (arrU[0].m_i > v) { + m_currentRangeIndex = MinUnitValue; s = string("< ") + arrU[0].m_s; - m_metresDiff = m_minMetersWidth - 1.0; + result = MinMetersWidth - 1.0; } else if (arrU[count-1].m_i <= v) { + m_currentRangeIndex = MaxUnitValue; s = string("> ") + arrU[count-1].m_s; - m_metresDiff = m_maxMetersWidth + 1.0; + result = MaxMetersWidth + 1.0; } else for (int i = 0; i < count; ++i) { if (arrU[i].m_i > v) { - m_metresDiff = arrU[i].m_i / m_conversionFn(1.0); + m_currentRangeIndex = i; + result = arrU[i].m_i / conversionFn(1.0); s = arrU[i].m_s; break; } } - UpdateText(s); + if (m_currentRangeIndex != prevUnitRange) + UpdateText(s); + return result; } Ruler::Params::Params() @@ -182,35 +533,33 @@ Ruler::Params::Params() Ruler::Ruler(Params const & p) : base_t(p), - m_cacheLength(500), m_boundRects(1), + m_currentRangeIndex(InvalidUnitValue), m_currSystem(0), + m_mainFrame(NULL), + m_animFrames(NULL), m_framework(p.m_framework) { - gui::CachedTextView::Params pp; - - pp.m_depth = depth(); - - m_dl = NULL; - memset(m_textDL, 0, ARRAY_SIZE(m_textDL) * sizeof(void *)); + setIsVisible(false); } void Ruler::AnimateShow() { - if (!isVisible() && (m_rulerAnim == NULL || IsHidingAnim())) + RulerFrame * frame = GetMainFrame(); + if (!isVisible() && (!frame->IsAnimActive() || frame->IsHidingAnim())) { setIsVisible(true); - CreateAnim(0.1, 1.0, 0.2, 0.0, true); + frame->ShowAnimate(false); } - - if (isVisible() && (m_rulerAnim == NULL || IsHidingAnim())) - CreateAnim(GetCurrentAlfa(), 1.0, 0.2, 0.0, true); + else if (isVisible() && (frame->IsAnimActive() && frame->IsHidingAnim())) + frame->ShowAnimate(false); } void Ruler::AnimateHide() { - if (isVisible() && (m_rulerAnim == NULL || !IsHidingAnim())) - CreateAnim(1.0, 0.0, 0.3, 1.0, false); + RulerFrame * frame = GetMainFrame(); + if (isVisible() && (!frame->IsAnimActive() || !frame->IsHidingAnim())) + frame->HideAnimate(true); } void Ruler::layout() @@ -218,282 +567,81 @@ void Ruler::layout() Settings::Units units = Settings::Metric; Settings::Get("Units", units); + int prevCurrSystem = m_currSystem; switch (units) { default: ASSERT_EQUAL ( units, Settings::Metric, () ); m_currSystem = 0; - m_conversionFn = &identity; break; - case Settings::Foot: m_currSystem = 1; - m_conversionFn = &MeasurementUtils::MetersToFeet; break; - case Settings::Yard: m_currSystem = 2; - m_conversionFn = &MeasurementUtils::MetersToYards; break; } + if (prevCurrSystem != m_currSystem) + m_currentRangeIndex = InvalidUnitValue; + update(); } -void Ruler::setMinPxWidth(unsigned minPxWidth) -{ - m_minPxWidth = minPxWidth; - setIsDirtyLayout(true); -} - -void Ruler::setMinMetersWidth(double v) -{ - m_minMetersWidth = v; - setIsDirtyLayout(true); -} - -void Ruler::setMaxMetersWidth(double v) -{ - m_maxMetersWidth = v; - setIsDirtyLayout(true); -} - -void Ruler::PurgeMainDL() -{ - delete m_dl; - m_dl = NULL; -} - -void Ruler::CacheMainDL() -{ - graphics::Screen * cs = m_controller->GetCacheScreen(); - - PurgeMainDL(); - m_dl = cs->createDisplayList(); - - cs->beginFrame(); - - cs->setDisplayList(m_dl); - - cs->applyVarAlfaStates(); - - double k = visualScale(); - double halfLength = m_cacheLength / 2.0; - - graphics::FontDesc const & f = font(EActive); - graphics::GlyphKey key(strings::LastUniChar("0"), f.m_size, f.m_isMasked, f.m_color); - graphics::Glyph::Info glyphInfo(key, m_controller->GetGlyphCache()); - uint32_t zeroMarkGlyph = cs->mapInfo(glyphInfo); - graphics::Resource const * glyphRes = cs->fromID(zeroMarkGlyph); - - m2::RectI glyphRect(glyphRes->m_texRect); - double glyphHalfW = glyphRect.SizeX() / 2.0; - double glyphHalfH = glyphRect.SizeY() / 2.0; - double zeroMarkOffset = (glyphHalfH + 2) + 5 * k; - - graphics::Brush::Info brushInfo(graphics::Color(3, 3, 3, 255)); - uint32_t brushId = cs->mapInfo(brushInfo); - graphics::Resource const * brushRes = cs->fromID(brushId); - m2::RectU brushRect = brushRes->m_texRect; - - shared_ptr glyphTexture = cs->pipeline(glyphRes->m_pipelineID).texture(); - m2::PointF brushCenter = cs->pipeline(brushRes->m_pipelineID).texture()->mapPixel(brushRect.Center()); - - // 0 1 10 11 18 17 - // -- -- -- - // || || || - // || 3, 6 9||8, 12 16||14 - // 2|--------- -------------| - // | | - // | | - // 4-------------------------- - // 5 7, 13 15 - - m2::PointD coords[] = - { - // Zero mark geometry - /*-4*/ m2::PointD(0.0, -zeroMarkOffset), - /*-3*/ m2::PointD(0.0, -zeroMarkOffset), - /*-2*/ m2::PointD(0.0, -zeroMarkOffset), - /*-1*/ m2::PointD(0.0, -zeroMarkOffset), - // Ruler geometry - /* 0*/ m2::PointD(0.0, -5.0 * k), - /* 1*/ m2::PointD(0.0, -5.0 * k), - /* 2*/ m2::PointD(0.0, -3.0 * k), - /* 3*/ m2::PointD(0.0, -3.0 * k), - /* 4*/ m2::PointD(0.0, 0.0), - /* 5*/ m2::PointD(0.0, 0.0), - /* 6*/ m2::PointD(0.0, -3.0 * k), - /* 7*/ m2::PointD(halfLength - 0.5, 0.0), - /* 8*/ m2::PointD(halfLength - 0.5, -3.0 * k), - /* 9*/ m2::PointD(halfLength - 0.5, -3.0 * k), - /*10*/ m2::PointD(halfLength - 0.5, -7.0 * k), - /*11*/ m2::PointD(halfLength - 0.5, -7.0 * k), - /*12*/ m2::PointD(halfLength - 0.5, -3.0 * k), - /*13*/ m2::PointD(halfLength - 0.5, 0.0 * k), - /*14*/ m2::PointD(m_cacheLength, -3.0 * k), - /*15*/ m2::PointD(m_cacheLength, 0.0 * k), - /*16*/ m2::PointD(m_cacheLength, -3.0 * k), - /*17*/ m2::PointD(m_cacheLength, -5.0 * k), - /*18*/ m2::PointD(m_cacheLength, -5.0 * k) - }; - - m2::PointF normals[] = - { - // Zero mark normals - /*-4*/ m2::PointF(-glyphHalfW + 1, -glyphHalfH), - /*-3*/ m2::PointF(-glyphHalfW + 1, glyphHalfH), - /*-2*/ m2::PointF( glyphHalfW + 1, -glyphHalfH), - /*-1*/ m2::PointF( glyphHalfW + 1, glyphHalfH), - // Ruler normals - /* 0*/ m2::PointF( 0.0 , 0.0), - /* 1*/ m2::PointF( 1.0 * k , 0.0), - /* 2*/ m2::PointF( 0.0 , 0.0), - /* 3*/ m2::PointF( 1.0 * k , 0.0), - /* 4*/ m2::PointF( 0.0 , 0.0), - /* 5*/ m2::PointF( 1.0 * k , 0.0), - /* 6*/ m2::PointF( 1.0 * k , 0.0), - /* 7*/ m2::PointF( 1.0 * k , 0.0), - /* 8*/ m2::PointF( 1.0 * k , 0.0), - /* 9*/ m2::PointF( 0.0 , 0.0), - /*10*/ m2::PointF( 0.0 , 0.0), - /*11*/ m2::PointF( 1.0 * k , 0.0), - /*12*/ m2::PointF( 1.0 * k , 0.0), - /*13*/ m2::PointF( 1.0 * k , 0.0), - /*14*/ m2::PointF( 0.0 , 0.0), - /*15*/ m2::PointF( 0.0 , 0.0), - /*16*/ m2::PointF(-1.0 * k , 0.0), - /*17*/ m2::PointF( 0.0 , 0.0), - /*18*/ m2::PointF(-1.0 * k , 0.0) - }; - - vector texCoords(ARRAY_SIZE(normals), brushCenter); - texCoords[0] = glyphTexture->mapPixel(m2::PointF(glyphRect.minX(), glyphRect.minY())); - texCoords[1] = glyphTexture->mapPixel(m2::PointF(glyphRect.minX(), glyphRect.maxY())); - texCoords[2] = glyphTexture->mapPixel(m2::PointF(glyphRect.maxX(), glyphRect.minY())); - texCoords[3] = glyphTexture->mapPixel(m2::PointF(glyphRect.maxX(), glyphRect.maxY())); - - ASSERT(ARRAY_SIZE(coords) == ARRAY_SIZE(normals), ()); - - cs->addTexturedStripStrided(coords, sizeof(m2::PointD), - normals, sizeof(m2::PointF), - &texCoords[0], sizeof(m2::PointF), 4, - depth(), glyphRes->m_pipelineID); - - cs->addTexturedStripStrided(coords + 4, sizeof(m2::PointD), - normals + 4, sizeof(m2::PointF), - &texCoords[4], sizeof(m2::PointF), ARRAY_SIZE(coords) - 4, - depth(), brushRes->m_pipelineID); - - cs->setDisplayList(0); - - cs->applyStates(); - - cs->endFrame(); -} - -void Ruler::PurgeTextDL(int index) -{ - delete m_textDL[index]; - m_textDL[index] = NULL; -} - void Ruler::UpdateText(const string & text) { - ASSERT(!text.empty(), ()); - ASSERT(m_textDL[1] == NULL, ()); - swap(m_textDL[0], m_textDL[1]); - PurgeTextDL(1); - - graphics::Screen * cs = m_controller->GetCacheScreen(); - m_textDL[0] = cs->createDisplayList(); - - cs->beginFrame(); - cs->setDisplayList(m_textDL[0]); - cs->applyVarAlfaStates(); - - strings::UniString uniString = strings::MakeUniString(text); - size_t length = uniString.size(); - buffer_vector infos(length, graphics::Glyph::Info()); - buffer_vector resInfos(length, NULL); - buffer_vector ids(length, 0); - buffer_vector glyphRes(length, NULL); - - graphics::FontDesc const & f = font(EActive); - - for (size_t i = 0; i < uniString.size(); ++i) + RulerFrame * frame = GetMainFrame(); + if (frame->IsValid()) { - infos[i] = graphics::Glyph::Info(graphics::GlyphKey(uniString[i], f.m_size, false, f.m_color), - m_controller->GetGlyphCache()); - - resInfos[i] = &infos[i]; + //RulerFrame * addFrame = new RulerFrame(*frame, bind(&Ruler::AnimFrameAnimEnded, this, _1, _2)); + //m_animFrames.push_back(addFrame); + delete m_animFrames; + m_animFrames = new RulerFrame(*frame, bind(&Ruler::AnimFrameAnimEnded, this, _1, _2)); } - if (cs->mapInfo(resInfos.data(), ids.data(), infos.size())) - { - uint32_t width = 0; - for (size_t i = 0; i < ids.size(); ++i) - { - graphics::Resource const * res = cs->fromID(ids[i]); - width += res->m_texRect.SizeX(); - glyphRes[i] = res; - } + frame->Cache(text, font(EActive)); + if (isVisible()) + frame->ShowAnimate(true); +} - int32_t pipelineID = glyphRes[0]->m_pipelineID; - shared_ptr texture = cs->pipeline(pipelineID).texture(); - double halfWidth = width / 2.0; - double lengthFromStart = 0.0; +void Ruler::MainFrameAnimEnded(bool isVisible, RulerFrame * frame) +{ + setIsVisible(isVisible); + ASSERT(GetMainFrame() == frame, ()); +} - buffer_vector coords; - buffer_vector normals; - buffer_vector texCoords; +void Ruler::AnimFrameAnimEnded(bool /*isVisible*/, RulerFrame * frame) +{ + //m_animFrames.remove(frame); + //delete frame; + delete frame; + m_animFrames = NULL; +} - for (size_t i = 0; i < uniString.size(); ++i) - { - double baseX = lengthFromStart - halfWidth; - coords.push_back(m2::PointD(baseX, 0.0)); - coords.push_back(m2::PointD(baseX, 0.0)); - coords.push_back(m2::PointD(baseX, 0.0)); +Ruler::RulerFrame * Ruler::GetMainFrame() +{ + if (m_mainFrame == NULL) + m_mainFrame = new RulerFrame(*m_framework, bind(&Ruler::MainFrameAnimEnded, this, _1, _2), depth()); - coords.push_back(m2::PointD(baseX, 0.0)); - coords.push_back(m2::PointD(baseX, 0.0)); - coords.push_back(m2::PointD(baseX, 0.0)); + return m_mainFrame; +} - m2::RectI resourceRect(glyphRes[i]->m_texRect); - double w = resourceRect.SizeX(); - double h = resourceRect.SizeY(); - lengthFromStart += w; - - normals.push_back(m2::PointF(0.0, 0.0)); - normals.push_back(m2::PointF(0.0, -h)); - normals.push_back(m2::PointF(w , 0.0)); - - normals.push_back(m2::PointF(w , 0.0)); - normals.push_back(m2::PointF(0.0, -h)); - normals.push_back(m2::PointF(w , -h)); - - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.maxY()))); - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.minY()))); - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.maxY()))); - - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.maxY()))); - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.minX(), resourceRect.minY()))); - texCoords.push_back(texture->mapPixel(m2::PointF(resourceRect.maxX(), resourceRect.minY()))); - } - - cs->addTexturedListStrided(coords.data(), sizeof(m2::PointF), - normals.data(), sizeof(m2::PointF), - texCoords.data(), sizeof(m2::PointF), - coords.size(), depth(), pipelineID); - } - - cs->setDisplayList(0); - cs->endFrame(); +Ruler::RulerFrame * Ruler::GetMainFrame() const +{ + ASSERT(m_mainFrame != NULL, ()); + return m_mainFrame; } void Ruler::purge() { - PurgeMainDL(); + m_currentRangeIndex = InvalidUnitValue; + delete m_mainFrame; + m_mainFrame = NULL; + + //GetRangeDeletor(m_animFrames, DeleteFunctor())(); + delete m_animFrames; + m_animFrames = NULL; + setIsVisible(false); } void Ruler::update() @@ -503,7 +651,7 @@ void Ruler::update() ScreenBase const & screen = m_framework->GetNavigator().Screen(); int const rulerHeight = my::rounds(5 * k); - int const minPxWidth = my::rounds(m_minPxWidth * k); + int const minPxWidth = my::rounds(MinPixelWidth * k); // pivot() here is the down right point of the ruler. // Get global points of ruler and distance according to minPxWidth. @@ -516,10 +664,10 @@ void Ruler::update() MercatorBounds::YToLat(pt1.y), MercatorBounds::XToLon(pt1.x)); // convert metres to units for calculating m_metresDiff - CalcMetresDiff(m_conversionFn(distanceInMetres)); + double metersDiff = CalcMetresDiff(distanceInMetres); - bool const higherThanMax = m_metresDiff > m_maxMetersWidth; - bool const lessThanMin = m_metresDiff < m_minMetersWidth; + bool const higherThanMax = metersDiff > MaxMetersWidth; + bool const lessThanMin = metersDiff < MinMetersWidth; // Calculate width of the ruler in pixels. double scalerWidthInPx = minPxWidth; @@ -532,35 +680,37 @@ void Ruler::update() // (in global coordinates) of the ruler. double const a = ang::AngleTo(pt1, pt0); - pt0 = MercatorBounds::GetSmPoint(pt1, cos(a) * m_metresDiff, sin(a) * m_metresDiff); + pt0 = MercatorBounds::GetSmPoint(pt1, cos(a) * metersDiff, sin(a) * metersDiff); scalerWidthInPx = my::rounds(pivot().Length(screen.GtoP(pt0))); } - m_scalerOrg = pivot() + m2::PointD(-scalerWidthInPx / 2, rulerHeight / 2); + m2::PointD orgPt = pivot() + m2::PointD(-scalerWidthInPx / 2, rulerHeight / 2); if (position() & graphics::EPosLeft) - m_scalerOrg.x -= scalerWidthInPx / 2; + orgPt.x -= scalerWidthInPx / 2; if (position() & graphics::EPosRight) - m_scalerOrg.x += scalerWidthInPx / 2; + orgPt.x += scalerWidthInPx / 2; if (position() & graphics::EPosAbove) - m_scalerOrg.y -= rulerHeight / 2; + orgPt.y -= rulerHeight / 2; if (position() & graphics::EPosUnder) - m_scalerOrg.y += rulerHeight / 2; + orgPt.y += rulerHeight / 2; - m_scaleKoeff = scalerWidthInPx / m_cacheLength; + RulerFrame * frame = GetMainFrame(); + frame->SetScale(scalerWidthInPx / CacheLength); + frame->SetOrgPoint(orgPt); } vector const & Ruler::boundRects() const { if (isDirtyRect()) { - // TODO graphics::FontDesc const & f = font(EActive); - m2::RectD rect(m_scalerOrg, m2::PointD(m_cacheLength * m_scaleKoeff, f.m_size * 2)); + RulerFrame * frame = GetMainFrame(); + m2::RectD rect(frame->GetOrgPoint(), m2::PointD(CacheLength * frame->GetScale(), f.m_size * 2)); m_boundRects[0] = m2::AnyRectD(rect); setIsDirtyRect(false); } @@ -570,7 +720,8 @@ vector const & Ruler::boundRects() const void Ruler::cache() { - CacheMainDL(); + (void)GetMainFrame(); + update(); } void Ruler::draw(graphics::OverlayRenderer * s, math::Matrix const & m) const @@ -579,16 +730,10 @@ void Ruler::draw(graphics::OverlayRenderer * s, math::Matrix const { checkDirtyLayout(); - graphics::UniformsHolder holder; - holder.insertValue(graphics::ETransparency, GetCurrentAlfa()); - - s->drawDisplayList(m_dl, math::Shift( - math::Scale(m, m2::PointD(m_scaleKoeff, 1.0)), - m_scalerOrg), &holder); - - double yOffset = -(2 + 5 * m_controller->GetVisualScale()); - if (m_textDL[0]) - s->drawDisplayList(m_textDL[0], - math::Shift(m, m_scalerOrg + m2::PointF(m_cacheLength * m_scaleKoeff, yOffset))); + RulerFrame * frame = GetMainFrame(); + frame->Draw(s, m); + //for_each(m_animFrames.begin(), m_animFrames.end(), bind(&Ruler::RulerFrame::Draw, _1, s, m)); + if (m_animFrames) + m_animFrames->Draw(s, m); } } diff --git a/map/ruler.hpp b/map/ruler.hpp index 81a35e9991..e786d43f71 100644 --- a/map/ruler.hpp +++ b/map/ruler.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../std/shared_ptr.hpp" #include "../gui/element.hpp" @@ -10,6 +9,9 @@ #include "../graphics/display_list.hpp" +#include "../std/shared_ptr.hpp" +#include "../std/list.hpp" + namespace anim { class Task; @@ -32,50 +34,71 @@ class Framework; class Ruler : public gui::Element { -private: - - shared_ptr m_rulerAnim; - void AlfaAnimEnded(bool isVisible); - bool IsHidingAnim() const; - float GetCurrentAlfa() const; - void CreateAnim(double startAlfa, double endAlfa, double timeInterval, double timeOffset, bool isVisibleAtEnd); - - /// @todo Remove this variables. All this stuff are constants - /// (get values from Framework constructor) - unsigned m_minPxWidth; - - double m_minMetersWidth; - double m_maxMetersWidth; - //@} - - /// Current diff in units between two endpoints of the ruler. - /// @todo No need to store it here. It's calculated once for calculating ruler's m_path. - double m_metresDiff; - - double m_cacheLength; - double m_scaleKoeff; - m2::PointD m_scalerOrg; - - m2::RectD m_boundRect; - typedef gui::Element base_t; mutable vector m_boundRects; - typedef double (*ConversionFn)(double); - ConversionFn m_conversionFn; + class RulerFrame + { + public: + typedef function frame_end_fn; + RulerFrame(Framework & f, + frame_end_fn const & fn, + double depth); + + RulerFrame(RulerFrame const & other, const frame_end_fn & fn); + ~RulerFrame(); + + bool IsValid() const; + + void Cache(const string & text, const graphics::FontDesc & f); + void Purge(); + bool IsHidingAnim() const; + bool IsAnimActive() const; + void SetScale(double scale); + double GetScale() const; + void SetOrgPoint(m2::PointD const & org); + m2::PointD const & GetOrgPoint() const; + + void ShowAnimate(bool needPause); + void HideAnimate(bool needPause); + void Draw(graphics::OverlayRenderer * r, math::Matrix const & m); + + private: + void CreateAnim(double startAlfa, double endAlfa, + double timeInterval, double timeOffset, + bool isVisibleAtEnd); + float GetCurrentAlfa(); + void AnimEnded(bool isVisible); + + private: + Framework & m_f; + shared_ptr m_dl; + shared_ptr m_textDL; + double m_scale; + double m_depth; + m2::PointD m_orgPt; + frame_end_fn m_callback; + + shared_ptr m_frameAnim; + }; + +private: + int m_currentRangeIndex; int m_currSystem; - void CalcMetresDiff(double v); - - graphics::DisplayList * m_dl; - void PurgeMainDL(); - void CacheMainDL(); - - graphics::DisplayList * m_textDL[2]; - void PurgeTextDL(int index); + double CalcMetresDiff(double value); void UpdateText(const string & text); + void MainFrameAnimEnded(bool isVisible, RulerFrame * frame); + void AnimFrameAnimEnded(bool isVisible, RulerFrame * frame); + + RulerFrame * GetMainFrame(); + RulerFrame * GetMainFrame() const; + RulerFrame * m_mainFrame; + //list m_animFrames; + RulerFrame * m_animFrames; + Framework * m_framework; public: @@ -91,10 +114,6 @@ public: void AnimateShow(); void AnimateHide(); - void setMinPxWidth(unsigned minPxWidth); - void setMinMetersWidth(double v); - void setMaxMetersWidth(double v); - vector const & boundRects() const; void draw(graphics::OverlayRenderer * r, math::Matrix const & m) const;