From 9201356184df3585de78c4abb998e4c7248b9ca2 Mon Sep 17 00:00:00 2001 From: rachytski Date: Sat, 2 Jun 2012 21:29:57 +0400 Subject: [PATCH] added CountryStatusDisplay GUI element and using it into InformationDisplay. --- gui/gui.pro | 8 +- map/country_status_display.cpp | 238 +++++++++++++++++++++++++++++++++ map/country_status_display.hpp | 78 +++++++++++ map/framework.cpp | 12 +- map/framework.hpp | 3 +- map/information_display.cpp | 62 +++------ map/information_display.hpp | 17 ++- map/map.pro | 2 + storage/storage.hpp | 6 + 9 files changed, 366 insertions(+), 60 deletions(-) create mode 100644 map/country_status_display.cpp create mode 100644 map/country_status_display.hpp diff --git a/gui/gui.pro b/gui/gui.pro index c70b2d7b79..ad122da3e1 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -13,14 +13,10 @@ HEADERS += \ controller.hpp\ element.hpp \ button.hpp \ + text_view.hpp \ SOURCES += \ controller.cpp \ element.cpp \ button.cpp \ - - - - - - + text_view.cpp \ diff --git a/map/country_status_display.cpp b/map/country_status_display.cpp new file mode 100644 index 0000000000..daa7e3bef9 --- /dev/null +++ b/map/country_status_display.cpp @@ -0,0 +1,238 @@ +#include "country_status_display.hpp" + +#include "../gui/controller.hpp" + +#include "../std/bind.hpp" +#include "../std/sstream.hpp" + +#include "../storage/storage.hpp" + +#include "../yg/overlay_renderer.hpp" + +void CountryStatusDisplay::cache() +{ + m_downloadButton->setIsVisible(false); + + m_statusMsg->setIsVisible(false); + + if (m_countryIdx != storage::TIndex()) + { + switch (m_countryStatus) + { + case storage::EInQueue: + { + m_statusMsg->setIsVisible(true); + + ostringstream out; + out << m_countryName << " is added to the\ndownloading queue"; + + m_statusMsg->setText(out.str()); + } + + break; + case storage::EDownloading: + { + m_statusMsg->setIsVisible(true); + + ostringstream out; + out << "Downloading " << m_countryName << "(" << m_countryProgress.first * 100 / m_countryProgress.second << "%)"; + + m_statusMsg->setText(out.str()); + } + break; + case storage::ENotDownloaded: + { + m_downloadButton->setIsVisible(true); + m_downloadButton->setText("Download " + m_countryName); + } + break; + case storage::EDownloadFailed: + { + m_downloadButton->setIsVisible(true); + m_downloadButton->setText("Try again"); + + ostringstream out; + out << "Downloading " << m_countryName << "\nhas failed."; + + m_statusMsg->setIsVisible(true); + m_statusMsg->setText(out.str()); + + setPivot(pivot()); + } + break; + default: + return; + } + } + + /// element bound rect is possibly changed + setIsDirtyRect(true); +} + +void CountryStatusDisplay::CountryStatusChanged(storage::TIndex const & idx) +{ + if (idx == m_countryIdx) + { + m_countryStatus = m_storage->CountryStatus(m_countryIdx); + setIsDirtyDrawing(true); + invalidate(); + } +} + +void CountryStatusDisplay::CountryProgress(storage::TIndex const & idx, pair const & progress) +{ + if ((m_countryIdx == idx) && m_storage->CountryStatus(idx) == storage::EDownloading) + { + m_countryProgress = progress; + setIsDirtyDrawing(true); + invalidate(); + } +} + +CountryStatusDisplay::CountryStatusDisplay(Params const & p) + : gui::Element(p), m_storage(p.m_storage) +{ + m_slotID = m_storage->Subscribe(bind(&CountryStatusDisplay::CountryStatusChanged, this, _1), + bind(&CountryStatusDisplay::CountryProgress, this, _1, _2)); + + gui::Button::Params bp; + + bp.m_depth = yg::maxDepth; + bp.m_width = 200; + bp.m_height = 40; + bp.m_pivot = m2::PointD(0, 0); + bp.m_position = yg::EPosCenter; + bp.m_text = "Download"; + + m_downloadButton.reset(new gui::Button(bp)); + m_downloadButton->setOnClickListener(bind(&CountryStatusDisplay::DownloadCountry, this)); + m_downloadButton->setIsVisible(false); + m_downloadButton->setPosition(yg::EPosCenter); + m_downloadButton->setFont(gui::Element::EActive, yg::FontDesc(16)); + m_downloadButton->setFont(gui::Element::EPressed, yg::FontDesc(16)); + + gui::TextView::Params tp; + tp.m_depth = yg::maxDepth; + tp.m_pivot = m2::PointD(0, 0); + tp.m_text = "Downloading"; + + m_statusMsg.reset(new gui::TextView(tp)); + + m_statusMsg->setIsVisible(false); + m_statusMsg->setPosition(yg::EPosCenter); + + m_statusMsg->setFont(gui::Element::EActive, yg::FontDesc(18)); + + m_countryIdx = storage::TIndex(); + m_countryStatus = storage::EUnknown; +} + +CountryStatusDisplay::~CountryStatusDisplay() +{ + m_storage->Unsubscribe(m_slotID); +} + +void CountryStatusDisplay::DownloadCountry() +{ + m_storage->DownloadCountry(m_countryIdx); +} + +void CountryStatusDisplay::setCountryName(string const & name) +{ + if (m_countryName != name) + { + m_countryIdx = m_storage->FindIndexByName(name); + m_countryStatus = m_storage->CountryStatus(m_countryIdx); + m_countryProgress = m_storage->CountrySizeInBytes(m_countryIdx); + m_countryName = name; + setIsDirtyDrawing(true); + invalidate(); + } +} + +void CountryStatusDisplay::draw(yg::gl::OverlayRenderer *r, + math::Matrix const & m) const +{ + if (!isVisible()) + return; + + checkDirtyDrawing(); + +// r->drawRectangle(roughBoundRect(), yg::Color(0, 0, 255, 64), yg::maxDepth); + + if (m_downloadButton->isVisible()) + m_downloadButton->draw(r, m); + if (m_statusMsg->isVisible()) + m_statusMsg->draw(r, m); +} + +vector const & CountryStatusDisplay::boundRects() const +{ + checkDirtyDrawing(); + + if (isDirtyRect()) + { + m_boundRects.clear(); + m2::RectD r = m_downloadButton->roughBoundRect(); + r.Add(m_statusMsg->roughBoundRect()); + m_boundRects.push_back(m2::AnyRectD(r)); + setIsDirtyRect(false); + } + + return m_boundRects; +} + +void CountryStatusDisplay::setController(gui::Controller *controller) +{ + Element::setController(controller); + m_statusMsg->setController(controller); + m_downloadButton->setController(controller); +} +void CountryStatusDisplay::setPivot(m2::PointD const & pv) +{ + if (m_countryStatus == storage::EDownloadFailed) + { + size_t buttonHeight = m_downloadButton->roughBoundRect().SizeY(); + size_t statusHeight = m_statusMsg->roughBoundRect().SizeY(); + + size_t commonHeight = buttonHeight + statusHeight + 10 * visualScale(); + + m_downloadButton->setPivot(m2::PointD(pv.x, pv.y + commonHeight / 2 - buttonHeight / 2)); + m_statusMsg->setPivot(m2::PointD(pv.x, pv.y - commonHeight / 2 + statusHeight / 2)); + } + else + { + m_downloadButton->setPivot(pv); + m_statusMsg->setPivot(pv); + } + + gui::Element::setPivot(pv); +} + +bool CountryStatusDisplay::onTapStarted(m2::PointD const & pt) +{ + if (m_downloadButton->isVisible()) + return m_downloadButton->onTapStarted(pt); + return false; +} + +bool CountryStatusDisplay::onTapMoved(m2::PointD const & pt) +{ + if (m_downloadButton->isVisible()) + return m_downloadButton->onTapMoved(pt); + return false; +} + +bool CountryStatusDisplay::onTapEnded(m2::PointD const & pt) +{ + if (m_downloadButton->isVisible()) + return m_downloadButton->onTapEnded(pt); + return false; +} + +bool CountryStatusDisplay::onTapCancelled(m2::PointD const & pt) +{ + if (m_downloadButton->isVisible()) + return m_downloadButton->onTapCancelled(pt); + return false; +} diff --git a/map/country_status_display.hpp b/map/country_status_display.hpp new file mode 100644 index 0000000000..05db5db664 --- /dev/null +++ b/map/country_status_display.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "../storage/storage.hpp" + +#include "../std/shared_ptr.hpp" + +#include "../gui/element.hpp" +#include "../gui/button.hpp" +#include "../gui/text_view.hpp" + +/// This class is a composite GUI element to display +/// an on-screen GUI for the country, which is not downloaded yet. +class CountryStatusDisplay : public gui::Element +{ +private: + + /// Storage-related members and methods + /// @{ + /// connection to the Storage for notifications + unsigned m_slotID; + storage::Storage * m_storage; + /// notification callback upon country status change + void CountryStatusChanged(storage::TIndex const &); + /// notification callback upon country downloading progress + void CountryProgress(storage::TIndex const &, pair const & progress); + /// @} + + /// download button + shared_ptr m_downloadButton; + /// country status message + shared_ptr m_statusMsg; + /// current country name + string m_countryName; + /// current country status + storage::TStatus m_countryStatus; + /// index of the country in Storage + storage::TIndex m_countryIdx; + /// downloading progress of the country + pair m_countryProgress; + + /// bounding rects + mutable vector m_boundRects; + + /// caching resources for fast rendering. + void cache(); + + /// callback for button click to download country + void DownloadCountry(); + +public: + + struct Params : public gui::Element::Params + { + storage::Storage * m_storage; + }; + + CountryStatusDisplay(Params const & p); + ~CountryStatusDisplay(); + + /// set current country name + void setCountryName(string const & name); + /// reposition element + void setPivot(m2::PointD const & pv); + /// attach element to controller. + void setController(gui::Controller *controller); + /// render element + void draw(yg::gl::OverlayRenderer * r, math::Matrix const & m) const; + /// get bounding rects + vector const & boundRects() const; + + /// react on touch events + /// @{ + bool onTapStarted(m2::PointD const & pt); + bool onTapMoved(m2::PointD const & pt); + bool onTapEnded(m2::PointD const & pt); + bool onTapCancelled(m2::PointD const & pt); + /// @} +}; diff --git a/map/framework.cpp b/map/framework.cpp index 0d12bd6a5d..b664ef175f 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -111,6 +111,7 @@ Framework::Framework() m_width(0), m_height(0), m_centeringMode(EDoNothing), + m_informationDisplay(&m_storage), m_lowestMapVersion(-1) { m_guiController.reset(new gui::Controller()); @@ -126,8 +127,6 @@ Framework::Framework() "Just click the downloader button \n"\ "at the bottom of the screen."; - m_informationDisplay.setEmptyModelMessage(s); - m_informationDisplay.enableCenter(true); m_informationDisplay.enableRuler(true); m_informationDisplay.setRulerParams(m_minRulerWidth, m_metresMinWidth, m_metresMaxWidth); @@ -469,11 +468,14 @@ void Framework::DrawAdditionalInfo(shared_ptr const & e) m2::PointD const center = m_navigator.Screen().GlobalRect().GlobalCenter(); - m_informationDisplay.setScreen(m_navigator.Screen()); - bool isEmptyModel = m_renderPolicy->IsEmptyModel(); - m_informationDisplay.enableEmptyModelMessage(isEmptyModel); + if (isEmptyModel) + m_informationDisplay.setEmptyCountryName(m_renderPolicy->GetCountryName().c_str()); + + m_informationDisplay.enableCountryStatusDisplay(isEmptyModel); + + m_informationDisplay.setScreen(m_navigator.Screen()); m_informationDisplay.setDebugInfo(0/*m_renderQueue.renderState().m_duration*/, GetDrawScale()); diff --git a/map/framework.hpp b/map/framework.hpp index 9b5645c936..2f4da1989a 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -72,8 +72,6 @@ protected: m2::AnyRectD m_invalidRect; m2::PointD m_placemark; - InformationDisplay m_informationDisplay; - double const m_metresMinWidth; double const m_metresMaxWidth; int const m_minRulerWidth; @@ -95,6 +93,7 @@ protected: storage::Storage m_storage; scoped_ptr m_guiController; + InformationDisplay m_informationDisplay; //my::Timer m_timer; inline double ElapsedSeconds() const diff --git a/map/information_display.cpp b/map/information_display.cpp index c4cdbc5062..d2c4cae058 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -1,5 +1,6 @@ #include "information_display.hpp" #include "drawer_yg.hpp" +#include "country_status_display.hpp" #include "../indexer/mercator.hpp" @@ -24,21 +25,18 @@ #include "../std/iomanip.hpp" #include "../std/target_os.hpp" -InformationDisplay::InformationDisplay() +InformationDisplay::InformationDisplay(storage::Storage * storage) : m_ruler(Ruler::Params()), m_bottomShift(0) { - gui::Button::Params p; + CountryStatusDisplay::Params p; p.m_pivot = m2::PointD(0, 0); p.m_position = yg::EPosCenter; p.m_depth = yg::maxDepth; - p.m_text = "Download"; - p.m_width = 200; - p.m_height = 40; + p.m_storage = storage; - m_downloadButton.reset(new gui::Button(p)); - m_downloadButton->setIsVisible(false); + m_countryStatusDisplay.reset(new CountryStatusDisplay(p)); enableDebugPoints(false); enableRuler(false); @@ -46,7 +44,7 @@ InformationDisplay::InformationDisplay() enableDebugInfo(false); enableMemoryWarning(false); enableBenchmarkInfo(false); - enableEmptyModelMessage(false); + enableCountryStatusDisplay(false); for (int i = 0; i < sizeof(m_DebugPts) / sizeof(m2::PointD); ++i) m_DebugPts[i] = m2::PointD(0, 0); @@ -58,13 +56,20 @@ InformationDisplay::InformationDisplay() void InformationDisplay::setController(gui::Controller *controller) { m_controller = controller; - m_controller->AddElement(m_downloadButton); + m_controller->AddElement(m_countryStatusDisplay); } void InformationDisplay::setScreen(ScreenBase const & screen) { m_screen = screen; m_ruler.setScreen(screen); + + if (m_countryStatusDisplay->isVisible()) + { + m2::RectD pxRect = m_screen.PixelRect(); + m2::PointD pt = m2::PointD(pxRect.SizeX() / 2, pxRect.SizeY() / 2) - m2::PointD(0, m_bottomShift * m_visualScale); + m_countryStatusDisplay->setPivot(pt); + } } void InformationDisplay::setBottomShift(double bottomShift) @@ -280,6 +285,7 @@ WindowHandle * InformationDisplay::s_windowHandle = 0; size_t s_msgNum = 0; void InformationDisplay::logMessage(my::LogLevel level, my::SrcPoint const &, string const & msg) +void InformationDisplay::setEmptyCountryName(const char * country) { { threads::MutexGuard guard(s_logMutex); @@ -298,6 +304,7 @@ void InformationDisplay::logMessage(my::LogLevel level, my::SrcPoint const &, st /// call redisplay s_windowHandle->invalidate(); + m_countryStatusDisplay->setCountryName(country); } void InformationDisplay::enableLog(bool doEnable, WindowHandle * windowHandle) @@ -350,15 +357,14 @@ void InformationDisplay::drawLog(DrawerYG * drawer) } */ -void InformationDisplay::enableEmptyModelMessage(bool doEnable) +void InformationDisplay::enableCountryStatusDisplay(bool doEnable) { - m_isEmptyModelMessageEnabled = doEnable; -// m_downloadButton->setIsVisible(doEnable); + m_countryStatusDisplay->setIsVisible(doEnable); } -void InformationDisplay::setEmptyModelMessage(char const * msg) +void InformationDisplay::setEmptyCountryName(const char *country) { - m_emptyModelMessage = msg; + m_countryStatusDisplay->setCountryName(country); } void InformationDisplay::setDownloadListener(gui::Button::TOnClickListener l) @@ -366,32 +372,6 @@ void InformationDisplay::setDownloadListener(gui::Button::TOnClickListener l) m_downloadButton->setOnClickListener(l); } -void InformationDisplay::drawEmptyModelMessage(DrawerYG * pDrawer) -{ - m2::RectD pxRect = m_screen.PixelRect(); - m2::PointD pt = m2::PointD(pxRect.SizeX() / 2, pxRect.SizeY() / 2) - m2::PointD(0, m_bottomShift * m_visualScale); - - yg::StraightTextElement::Params params; - params.m_depth = yg::maxDepth; - params.m_fontDesc = m_emptyMessageFont; - params.m_log2vis = false; - params.m_pivot = pt; - params.m_position = yg::EPosCenter; - params.m_glyphCache = pDrawer->screen()->glyphCache(); - params.m_logText = strings::MakeUniString(m_emptyModelMessage); - params.m_doSplit = true; - params.m_delimiters = "\n"; - params.m_useAllParts = true; - - yg::StraightTextElement ste(params); - - ste.draw(pDrawer->screen().get(), math::Identity()); - - m2::PointD pv(pt.x, ste.roughBoundRect().maxY() + m_downloadButton->roughBoundRect().SizeY() / 2 + 10 * m_visualScale); - - m_downloadButton->setPivot(pv); -} - void InformationDisplay::enableBenchmarkInfo(bool doEnable) { m_isBenchmarkInfoEnabled = doEnable; @@ -477,6 +457,4 @@ void InformationDisplay::doDraw(DrawerYG *drawer) drawBenchmarkInfo(drawer); //if (s_isLogEnabled) // drawLog(drawer); - if (m_isEmptyModelMessageEnabled) - drawEmptyModelMessage(drawer); } diff --git a/map/information_display.hpp b/map/information_display.hpp index 580c323ae9..c468d33cf7 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -22,6 +22,13 @@ namespace gui class Controller; } +namespace storage +{ + class Storage; +} + +class CountryStatusDisplay; + /// Class, which displays additional information on the primary layer. /// like rules, coordinates, GPS position and heading class InformationDisplay @@ -50,7 +57,7 @@ private: bool m_isDebugInfoEnabled; double m_frameDuration; - bool m_isEmptyModelMessageEnabled; + string m_emptyCountryName; string m_emptyModelMessage; shared_ptr m_downloadButton; @@ -80,10 +87,11 @@ private: static size_t s_logSize; static WindowHandle * s_windowHandle; */ + shared_ptr m_countryStatusDisplay; public: - InformationDisplay(); + InformationDisplay(storage::Storage * storage); void setController(gui::Controller * controller); @@ -125,10 +133,9 @@ public: void setLogSize(size_t logSize); void drawLog(DrawerYG * pDrawer); - void enableEmptyModelMessage(bool doEnable); - void setEmptyModelMessage(char const * msg); + void enableCountryStatusDisplay(bool doEnable); void setDownloadListener(gui::Button::TOnClickListener l); - void drawEmptyModelMessage(DrawerYG * pDrawer); + void setEmptyCountryName(char const * country); static void logMessage(my::LogLevel, my::SrcPoint const &, string const &); }; diff --git a/map/map.pro b/map/map.pro index 2117110227..35bb865f98 100644 --- a/map/map.pro +++ b/map/map.pro @@ -50,6 +50,7 @@ HEADERS += \ bookmark.hpp \ tile_set.hpp \ geourl_process.hpp \ + country_status_display.hpp \ SOURCES += \ feature_vec_model.cpp \ @@ -91,6 +92,7 @@ SOURCES += \ tile_set.cpp \ geourl_process.cpp \ bookmark.cpp \ + country_status_display.cpp \ !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp diff --git a/storage/storage.hpp b/storage/storage.hpp index afae87ce11..83f405018c 100644 --- a/storage/storage.hpp +++ b/storage/storage.hpp @@ -43,6 +43,12 @@ namespace storage m_country == other.m_country && m_region == other.m_region); } + + bool operator!=(TIndex const & other) const + { + return !(*this == other); + } + bool operator<(TIndex const & other) const { if (m_group != other.m_group)