diff --git a/omim.pro b/omim.pro index d04db27586..eccec26629 100644 --- a/omim.pro +++ b/omim.pro @@ -83,9 +83,13 @@ SUBDIRS = 3party base coding geometry editor indexer routing routing_common sear benchmark_tool.subdir = map/benchmark_tool benchmark_tool.depends = 3party base coding geometry platform indexer search map mapshot.depends = $$SUBDIRS - qt.depends = $$SUBDIRS - SUBDIRS *= benchmark_tool mapshot qt + qt_common.subdir = qt/qt_common + qt_common.depends = $$SUBDIRS + + qt.depends = $$SUBDIRS qt_common + + SUBDIRS *= benchmark_tool mapshot qt qt_common } CONFIG(desktop) { diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index f35a96173c..31c27fd0bb 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -38,16 +38,8 @@ set( place_page_dialog.hpp preferences_dialog.cpp preferences_dialog.hpp - proxystyle.cpp - proxystyle.hpp - qtoglcontext.cpp - qtoglcontext.hpp - qtoglcontextfactory.cpp - qtoglcontextfactory.hpp search_panel.cpp search_panel.hpp - slider_ctrl.cpp - slider_ctrl.hpp traffic_mode.cpp traffic_mode.hpp traffic_panel.cpp @@ -62,6 +54,7 @@ add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${RES_SOURCES} ${SRC}) omim_link_libraries( ${PROJECT_NAME} + qt_common map drape_frontend routing @@ -167,3 +160,5 @@ copy_resources( 06_code2000.ttf 07_roboto_medium.ttf ) + +add_subdirectory(qt_common) diff --git a/qt/draw_widget.cpp b/qt/draw_widget.cpp index b86817e789..1b0fc4cd6c 100644 --- a/qt/draw_widget.cpp +++ b/qt/draw_widget.cpp @@ -2,8 +2,10 @@ #include "qt/draw_widget.hpp" #include "qt/editor_dialog.hpp" #include "qt/place_page_dialog.hpp" -#include "qt/slider_ctrl.hpp" -#include "qt/qtoglcontext.hpp" +#include "qt/qt_common/helpers.hpp" +#include "qt/qt_common/scale_slider.hpp" + +#include "map/framework.hpp" #include "drape_frontend/visual_params.hpp" @@ -19,10 +21,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -34,66 +32,27 @@ #include #include +using namespace qt::common; + namespace qt { - -namespace -{ - -bool IsLeftButton(Qt::MouseButtons buttons) -{ - return buttons & Qt::LeftButton; -} -bool IsLeftButton(QMouseEvent const * const e) -{ - return IsLeftButton(e->button()) || IsLeftButton(e->buttons()); -} - -bool IsRightButton(Qt::MouseButtons buttons) -{ - return buttons & Qt::RightButton; -} -bool IsRightButton(QMouseEvent const * const e) -{ - return IsRightButton(e->button()) || IsRightButton(e->buttons()); -} - -bool IsCommandModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::ControlModifier; } -bool IsShiftModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::ShiftModifier; } -bool IsAltModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::AltModifier; } -} // namespace - -DrawWidget::DrawWidget(QWidget * parent) - : TBase(parent) - , m_contextFactory(nullptr) - , m_framework(new Framework()) - , m_ratio(1.0) - , m_pScale(nullptr) +DrawWidget::DrawWidget(Framework & framework, QWidget * parent) + : TBase(framework, parent) , m_rubberBand(nullptr) - , m_enableScaleUpdate(true) , m_emulatingLocation(false) { - m_framework->SetMapSelectionListeners([this](place_page::Info const & info) - { - ShowPlacePage(info); - }, [](bool /*switchFullScreenMode*/){}); // Empty deactivation listener. + m_framework.SetMapSelectionListeners( + [this](place_page::Info const & info) { ShowPlacePage(info); }, + [](bool /*switchFullScreenMode*/) {}); // Empty deactivation listener. - m_framework->SetRouteBuildingListener([](routing::IRouter::ResultCode, - storage::TCountriesVec const &) - { - }); + m_framework.SetRouteBuildingListener( + [](routing::IRouter::ResultCode, storage::TCountriesVec const &) {}); - m_framework->SetCurrentCountryChangedListener([this](storage::TCountryId const & countryId) - { + m_framework.SetCurrentCountryChangedListener([this](storage::TCountryId const & countryId) { m_countryId = countryId; UpdateCountryStatus(countryId); }); - QTimer * timer = new QTimer(this); - VERIFY(connect(timer, SIGNAL(timeout()), this, SLOT(update())), ()); - timer->setSingleShot(false); - timer->start(30); - QTimer * countryStatusTimer = new QTimer(this); VERIFY(connect(countryStatusTimer, SIGNAL(timeout()), this, SLOT(OnUpdateCountryStatusByTimer())), ()); countryStatusTimer->setSingleShot(false); @@ -103,9 +62,6 @@ DrawWidget::DrawWidget(QWidget * parent) DrawWidget::~DrawWidget() { delete m_rubberBand; - - m_framework->EnterBackground(); - m_framework.reset(); } void DrawWidget::UpdateCountryStatus(storage::TCountryId const & countryId) @@ -113,14 +69,14 @@ void DrawWidget::UpdateCountryStatus(storage::TCountryId const & countryId) if (m_currentCountryChanged != nullptr) { string countryName = countryId; - auto status = m_framework->GetStorage().CountryStatusEx(countryId); + auto status = m_framework.GetStorage().CountryStatusEx(countryId); uint8_t progressInPercentage = 0; storage::MapFilesDownloader::TProgress progressInByte = make_pair(0, 0); if (!countryId.empty()) { storage::NodeAttrs nodeAttrs; - m_framework->GetStorage().GetNodeAttrs(countryId, nodeAttrs); + m_framework.GetStorage().GetNodeAttrs(countryId, nodeAttrs); progressInByte = nodeAttrs.m_downloadingProgress; if (progressInByte.second != 0) progressInPercentage = static_cast(100 * progressInByte.first / progressInByte.second); @@ -144,7 +100,7 @@ void DrawWidget::SetCurrentCountryChangedListener(DrawWidget::TCurrentCountryCha void DrawWidget::DownloadCountry(storage::TCountryId const & countryId) { - m_framework->GetStorage().DownloadNode(countryId); + m_framework.GetStorage().DownloadNode(countryId); if (!m_countryId.empty()) UpdateCountryStatus(m_countryId); } @@ -154,223 +110,41 @@ void DrawWidget::RetryToDownloadCountry(storage::TCountryId const & countryId) // TODO @bykoianko } -void DrawWidget::SetScaleControl(QScaleSlider * pScale) -{ - m_pScale = pScale; - - connect(m_pScale, SIGNAL(actionTriggered(int)), this, SLOT(ScaleChanged(int))); - connect(m_pScale, SIGNAL(sliderPressed()), this, SLOT(SliderPressed())); - connect(m_pScale, SIGNAL(sliderReleased()), this, SLOT(SliderReleased())); -} - void DrawWidget::PrepareShutdown() { } void DrawWidget::UpdateAfterSettingsChanged() { - m_framework->EnterForeground(); -} - -void DrawWidget::ScalePlus() -{ - m_framework->Scale(Framework::SCALE_MAG, true); -} - -void DrawWidget::ScaleMinus() -{ - m_framework->Scale(Framework::SCALE_MIN, true); -} - -void DrawWidget::ScalePlusLight() -{ - m_framework->Scale(Framework::SCALE_MAG_LIGHT, true); -} - -void DrawWidget::ScaleMinusLight() -{ - m_framework->Scale(Framework::SCALE_MIN_LIGHT, true); + m_framework.EnterForeground(); } void DrawWidget::ShowAll() { - m_framework->ShowAll(); -} - -void DrawWidget::ScaleChanged(int action) -{ - if (action != QAbstractSlider::SliderNoAction) - { - double const factor = m_pScale->GetScaleFactor(); - if (factor != 1.0) - m_framework->Scale(factor, false); - } -} - -void DrawWidget::SliderPressed() -{ - m_enableScaleUpdate = false; -} - -void DrawWidget::SliderReleased() -{ - m_enableScaleUpdate = true; + m_framework.ShowAll(); } void DrawWidget::ChoosePositionModeEnable() { - m_framework->BlockTapEvents(true); - m_framework->EnableChoosePositionMode(true, false, false, m2::PointD()); + m_framework.BlockTapEvents(true); + m_framework.EnableChoosePositionMode(true, false, false, m2::PointD()); } void DrawWidget::ChoosePositionModeDisable() { - m_framework->EnableChoosePositionMode(false, false, false, m2::PointD()); - m_framework->BlockTapEvents(false); -} - -void DrawWidget::CreateEngine() -{ - Framework::DrapeCreationParams p; - p.m_surfaceWidth = m_ratio * width(); - p.m_surfaceHeight = m_ratio * height(); - p.m_visualScale = m_ratio; - - m_skin.reset(new gui::Skin(gui::ResolveGuiSkinFile("default"), m_ratio)); - m_skin->Resize(p.m_surfaceWidth, p.m_surfaceHeight); - m_skin->ForEach([&p](gui::EWidget widget, gui::Position const & pos) - { - p.m_widgetsInitInfo[widget] = pos; - }); - - p.m_widgetsInitInfo[gui::WIDGET_SCALE_LABEL] = gui::Position(dp::LeftBottom); - - m_framework->CreateDrapeEngine(make_ref(m_contextFactory), std::move(p)); - m_framework->SetViewportListener(bind(&DrawWidget::OnViewportChanged, this, _1)); + m_framework.EnableChoosePositionMode(false, false, false, m2::PointD()); + m_framework.BlockTapEvents(false); } void DrawWidget::initializeGL() { - ASSERT(m_contextFactory == nullptr, ()); - m_ratio = devicePixelRatio(); - m_contextFactory.reset(new QtOGLContextFactory(context())); - - emit BeforeEngineCreation(); - CreateEngine(); - - m_framework->LoadBookmarks(); - m_framework->EnterForeground(); -} - -void DrawWidget::paintGL() -{ - static QOpenGLShaderProgram * program = nullptr; - if (program == nullptr) - { - const char * vertexSrc = "\ - attribute vec2 a_position; \ - attribute vec2 a_texCoord; \ - uniform mat4 u_projection; \ - varying vec2 v_texCoord; \ - \ - void main(void) \ - { \ - gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\ - v_texCoord = a_texCoord; \ - }"; - - const char * fragmentSrc = "\ - uniform sampler2D u_sampler; \ - varying vec2 v_texCoord; \ - \ - void main(void) \ - { \ - gl_FragColor = vec4(texture2D(u_sampler, v_texCoord).rgb, 1.0); \ - }"; - - program = new QOpenGLShaderProgram(this); - program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSrc); - program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSrc); - program->link(); - } - - if (m_contextFactory->LockFrame()) - { - QOpenGLFunctions * funcs = context()->functions(); - funcs->glActiveTexture(GL_TEXTURE0); - GLuint image = m_contextFactory->GetTextureHandle(); - funcs->glBindTexture(GL_TEXTURE_2D, image); - - int projectionLocation = program->uniformLocation("u_projection"); - int samplerLocation = program->uniformLocation("u_sampler"); - - QMatrix4x4 projection; - QRect r = rect(); - r.setWidth(m_ratio * r.width()); - r.setHeight(m_ratio * r.height()); - projection.ortho(r); - - program->bind(); - program->setUniformValue(projectionLocation, projection); - program->setUniformValue(samplerLocation, 0); - - float const w = m_ratio * width(); - float h = m_ratio * height(); - - QVector2D positions[4] = - { - QVector2D(0.0, 0.0), - QVector2D(w, 0.0), - QVector2D(0.0, h), - QVector2D(w, h) - }; - - QRectF const & texRect = m_contextFactory->GetTexRect(); - QVector2D texCoords[4] = - { - QVector2D(texRect.bottomLeft()), - QVector2D(texRect.bottomRight()), - QVector2D(texRect.topLeft()), - QVector2D(texRect.topRight()) - }; - - program->enableAttributeArray("a_position"); - program->enableAttributeArray("a_texCoord"); - program->setAttributeArray("a_position", positions, 0); - program->setAttributeArray("a_texCoord", texCoords, 0); - - funcs->glClearColor(0.0, 0.0, 0.0, 1.0); - funcs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - funcs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - m_contextFactory->UnlockFrame(); - } - -} - -void DrawWidget::resizeGL(int width, int height) -{ - float w = m_ratio * width; - float h = m_ratio * height; - m_framework->OnSize(w, h); - m_framework->SetVisibleViewport(m2::RectD(0, 0, w, h)); - if (m_skin) - { - m_skin->Resize(w, h); - - gui::TWidgetsLayoutInfo layout; - m_skin->ForEach([&layout](gui::EWidget w, gui::Position const & pos) - { - layout[w] = pos.m_pixelPivot; - }); - - m_framework->SetWidgetLayout(std::move(layout)); - } + MapWidget::initializeGL(); + m_framework.LoadBookmarks(); } void DrawWidget::mousePressEvent(QMouseEvent * e) { - TBase::mousePressEvent(e); + QOpenGLWidget::mousePressEvent(e); m2::PointD const pt = GetDevicePoint(e); @@ -381,7 +155,7 @@ void DrawWidget::mousePressEvent(QMouseEvent * e) else if (IsAltModifier(e)) SubmitFakeLocationPoint(pt); else - m_framework->TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_DOWN)); + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_DOWN)); } else if (IsRightButton(e)) { @@ -400,18 +174,11 @@ void DrawWidget::mousePressEvent(QMouseEvent * e) } } -void DrawWidget::mouseDoubleClickEvent(QMouseEvent * e) -{ - TBase::mouseDoubleClickEvent(e); - if (IsLeftButton(e)) - m_framework->Scale(Framework::SCALE_MAG_LIGHT, GetDevicePoint(e), true); -} - void DrawWidget::mouseMoveEvent(QMouseEvent * e) { - TBase::mouseMoveEvent(e); + QOpenGLWidget::mouseMoveEvent(e); if (IsLeftButton(e) && !IsAltModifier(e)) - m_framework->TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_MOVE)); + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_MOVE)); if (m_selectionMode && m_rubberBand != nullptr && m_rubberBand->isVisible()) { @@ -421,10 +188,10 @@ void DrawWidget::mouseMoveEvent(QMouseEvent * e) void DrawWidget::mouseReleaseEvent(QMouseEvent * e) { - TBase::mouseReleaseEvent(e); + QOpenGLWidget::mouseReleaseEvent(e); if (IsLeftButton(e) && !IsAltModifier(e)) { - m_framework->TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_UP)); + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_UP)); } else if (m_selectionMode && IsRightButton(e) && m_rubberBand != nullptr && m_rubberBand->isVisible()) @@ -432,9 +199,9 @@ void DrawWidget::mouseReleaseEvent(QMouseEvent * e) QPoint const lt = m_rubberBand->geometry().topLeft(); QPoint const rb = m_rubberBand->geometry().bottomRight(); m2::RectD rect; - rect.Add(m_framework->PtoG(m2::PointD(L2D(lt.x()), L2D(lt.y())))); - rect.Add(m_framework->PtoG(m2::PointD(L2D(rb.x()), L2D(rb.y())))); - m_framework->VisualizeRoadsInRect(rect); + rect.Add(m_framework.PtoG(m2::PointD(L2D(lt.x()), L2D(lt.y())))); + rect.Add(m_framework.PtoG(m2::PointD(L2D(rb.x()), L2D(rb.y())))); + m_framework.VisualizeRoadsInRect(rect); m_rubberBand->hide(); } } @@ -453,7 +220,7 @@ void DrawWidget::keyPressEvent(QKeyEvent * e) event.SetFirstTouch(touch); event.SetSecondTouch(GetSymmetrical(touch)); - m_framework->TouchEvent(event); + m_framework.TouchEvent(event); } } @@ -472,52 +239,47 @@ void DrawWidget::keyReleaseEvent(QKeyEvent * e) event.SetFirstTouch(touch); event.SetSecondTouch(GetSymmetrical(touch)); - m_framework->TouchEvent(event); + m_framework.TouchEvent(event); } else if (e->key() == Qt::Key_Alt) m_emulatingLocation = false; } -void DrawWidget::wheelEvent(QWheelEvent * e) -{ - m_framework->Scale(exp(e->delta() / 360.0), m2::PointD(L2D(e->x()), L2D(e->y())), false); -} - bool DrawWidget::Search(search::EverywhereSearchParams const & params) { - return m_framework->SearchEverywhere(params); + return m_framework.SearchEverywhere(params); } string DrawWidget::GetDistance(search::Result const & res) const { string dist; double lat, lon; - if (m_framework->GetCurrentPosition(lat, lon)) + if (m_framework.GetCurrentPosition(lat, lon)) { double dummy; - (void) m_framework->GetDistanceAndAzimut(res.GetFeatureCenter(), lat, lon, -1.0, dist, dummy); + (void) m_framework.GetDistanceAndAzimut(res.GetFeatureCenter(), lat, lon, -1.0, dist, dummy); } return dist; } void DrawWidget::ShowSearchResult(search::Result const & res) { - m_framework->ShowSearchResult(res); + m_framework.ShowSearchResult(res); } void DrawWidget::CreateFeature() { - auto cats = m_framework->GetEditorCategories(); + auto cats = m_framework.GetEditorCategories(); CreateFeatureDialog dlg(this, cats); if (dlg.exec() == QDialog::Accepted) { osm::EditableMapObject emo; - if (m_framework->CreateMapObject(m_framework->GetViewportCenter(), dlg.GetSelectedType(), emo)) + if (m_framework.CreateMapObject(m_framework.GetViewportCenter(), dlg.GetSelectedType(), emo)) { EditorDialog dlg(this, emo); int const result = dlg.exec(); if (result == QDialog::Accepted) - m_framework->SaveEditedMapObject(emo); + m_framework.SaveEditedMapObject(emo); } else { @@ -529,18 +291,18 @@ void DrawWidget::CreateFeature() void DrawWidget::OnLocationUpdate(location::GpsInfo const & info) { if (!m_emulatingLocation) - m_framework->OnLocationUpdate(info); + m_framework.OnLocationUpdate(info); } void DrawWidget::SetMapStyle(MapStyle mapStyle) { - m_framework->SetMapStyle(mapStyle); + m_framework.SetMapStyle(mapStyle); } void DrawWidget::SubmitFakeLocationPoint(m2::PointD const & pt) { m_emulatingLocation = true; - m2::PointD const point = m_framework->PtoG(pt); + m2::PointD const point = m_framework.PtoG(pt); location::GpsInfo info; info.m_latitude = MercatorBounds::YToLat(point.y); @@ -548,12 +310,12 @@ void DrawWidget::SubmitFakeLocationPoint(m2::PointD const & pt) info.m_horizontalAccuracy = 10; info.m_timestamp = QDateTime::currentMSecsSinceEpoch() / 1000.0; - m_framework->OnLocationUpdate(info); + m_framework.OnLocationUpdate(info); - if (m_framework->IsRoutingActive()) + if (m_framework.IsRoutingActive()) { location::FollowingInfo loc; - m_framework->GetRouteFollowingInfo(loc); + m_framework.GetRouteFollowingInfo(loc); LOG(LDEBUG, ("Distance:", loc.m_distToTarget, loc.m_targetUnitsSuffix, "Time:", loc.m_time, "Turn:", routing::turns::GetTurnString(loc.m_turn), "(", loc.m_distToTurn, loc.m_turnUnitsSuffix, ") Roundabout exit number:", loc.m_exitNum)); @@ -562,36 +324,36 @@ void DrawWidget::SubmitFakeLocationPoint(m2::PointD const & pt) void DrawWidget::SubmitRoutingPoint(m2::PointD const & pt) { - if (m_framework->IsRoutingActive()) - m_framework->CloseRouting(); + if (m_framework.IsRoutingActive()) + m_framework.CloseRouting(); else - m_framework->BuildRoute(m_framework->PtoG(pt), 0 /* timeoutSec */); + m_framework.BuildRoute(m_framework.PtoG(pt), 0 /* timeoutSec */); } void DrawWidget::ShowPlacePage(place_page::Info const & info) { search::AddressInfo address; if (info.IsFeature()) - address = m_framework->GetFeatureAddressInfo(info.GetID()); + address = m_framework.GetFeatureAddressInfo(info.GetID()); else - address = m_framework->GetAddressInfoAtPoint(info.GetMercator()); + address = m_framework.GetAddressInfoAtPoint(info.GetMercator()); PlacePageDialog dlg(this, info, address); if (dlg.exec() == QDialog::Accepted) { osm::EditableMapObject emo; - if (m_framework->GetEditableMapObject(info.GetID(), emo)) + if (m_framework.GetEditableMapObject(info.GetID(), emo)) { EditorDialog dlg(this, emo); int const result = dlg.exec(); if (result == QDialog::Accepted) { - m_framework->SaveEditedMapObject(emo); - m_framework->UpdatePlacePageInfoForCurrentSelection(); + m_framework.SaveEditedMapObject(emo); + m_framework.UpdatePlacePageInfoForCurrentSelection(); } else if (result == QDialogButtonBox::DestructiveRole) { - m_framework->DeleteFeature(info.GetID()); + m_framework.DeleteFeature(info.GetID()); } } else @@ -599,7 +361,7 @@ void DrawWidget::ShowPlacePage(place_page::Info const & info) LOG(LERROR, ("Error while trying to edit feature.")); } } - m_framework->DeactivateMapSelection(false); + m_framework.DeactivateMapSelection(false); } void DrawWidget::ShowInfoPopup(QMouseEvent * e, m2::PointD const & pt) @@ -611,9 +373,9 @@ void DrawWidget::ShowInfoPopup(QMouseEvent * e, m2::PointD const & pt) menu.addAction(QString::fromUtf8(s.c_str())); }; - m_framework->ForEachFeatureAtPoint([&](FeatureType & ft) + m_framework.ForEachFeatureAtPoint([&](FeatureType & ft) { - search::AddressInfo const info = m_framework->GetFeatureAddressInfo(ft); + search::AddressInfo const info = m_framework.GetFeatureAddressInfo(ft); string concat; for (auto const & type : info.m_types) @@ -628,64 +390,14 @@ void DrawWidget::ShowInfoPopup(QMouseEvent * e, m2::PointD const & pt) addStringFn(addr); menu.addSeparator(); - }, m_framework->PtoG(pt)); + }, m_framework.PtoG(pt)); menu.exec(e->pos()); } -void DrawWidget::OnViewportChanged(ScreenBase const & screen) -{ - UpdateScaleControl(); -} - -void DrawWidget::UpdateScaleControl() -{ - if (m_pScale && m_enableScaleUpdate) - { - // don't send ScaleChanged - m_pScale->SetPosWithBlockedSignals(m_framework->GetDrawScale()); - } -} - -df::Touch DrawWidget::GetTouch(QMouseEvent * e) -{ - df::Touch touch; - touch.m_id = 0; - touch.m_location = GetDevicePoint(e); - return touch; -} - -df::Touch DrawWidget::GetSymmetrical(df::Touch const & touch) -{ - m2::PointD pixelCenter = m_framework->GetPixelCenter(); - m2::PointD symmetricalLocation = pixelCenter + (pixelCenter - touch.m_location); - - df::Touch result; - result.m_id = touch.m_id + 1; - result.m_location = symmetricalLocation; - - return result; -} - -df::TouchEvent DrawWidget::GetTouchEvent(QMouseEvent * e, df::TouchEvent::ETouchType type) -{ - df::TouchEvent event; - event.SetTouchType(type); - event.SetFirstTouch(GetTouch(e)); - if (IsCommandModifier(e)) - event.SetSecondTouch(GetSymmetrical(event.GetFirstTouch())); - - return event; -} - -m2::PointD DrawWidget::GetDevicePoint(QMouseEvent * e) const -{ - return m2::PointD(L2D(e->x()), L2D(e->y())); -} - void DrawWidget::SetRouter(routing::RouterType routerType) { - m_framework->SetRouter(routerType); + m_framework.SetRouter(routerType); } void DrawWidget::SetSelectionMode(bool mode) { m_selectionMode = mode; } } diff --git a/qt/draw_widget.hpp b/qt/draw_widget.hpp index 2e60e40d93..7386d54145 100644 --- a/qt/draw_widget.hpp +++ b/qt/draw_widget.hpp @@ -1,10 +1,13 @@ #pragma once -#include "qt/qtoglcontextfactory.hpp" +#include "qt/qt_common/map_widget.hpp" -#include "map/framework.hpp" +#include "map/place_page_info.hpp" #include "search/everywhere_search_params.hpp" +#include "search/result.hpp" + +#include "routing/router.hpp" #include "drape_frontend/gui/skin.hpp" @@ -14,123 +17,91 @@ #include "std/mutex.hpp" #include "std/unique_ptr.hpp" -#include #include +class Framework; class QQuickWindow; namespace qt { - class QScaleSlider; - - class DrawWidget : public QOpenGLWidget - { - using TBase = QOpenGLWidget; - - drape_ptr m_contextFactory; - unique_ptr m_framework; - - qreal m_ratio; - - Q_OBJECT - - public Q_SLOTS: - void ScalePlus(); - void ScaleMinus(); - void ScalePlusLight(); - void ScaleMinusLight(); - - void ShowAll(); - void ScaleChanged(int action); - void SliderPressed(); - void SliderReleased(); - - void ChoosePositionModeEnable(); - void ChoosePositionModeDisable(); - void OnUpdateCountryStatusByTimer(); - - public: - DrawWidget(QWidget * parent); - ~DrawWidget(); - - void SetScaleControl(QScaleSlider * pScale); - - bool Search(search::EverywhereSearchParams const & params); - string GetDistance(search::Result const & res) const; - void ShowSearchResult(search::Result const & res); - - void CreateFeature(); - - void OnLocationUpdate(location::GpsInfo const & info); - - void UpdateAfterSettingsChanged(); - - void PrepareShutdown(); - - Framework & GetFramework() { return *m_framework.get(); } - - void SetMapStyle(MapStyle mapStyle); - - void SetRouter(routing::RouterType routerType); - Q_SIGNAL void BeforeEngineCreation(); - - void CreateEngine(); - - using TCurrentCountryChanged = function; - void SetCurrentCountryChangedListener(TCurrentCountryChanged const & listener); - - void DownloadCountry(storage::TCountryId const & countryId); - void RetryToDownloadCountry(storage::TCountryId const & countryId); - - void SetSelectionMode(bool mode); - - protected: - void initializeGL() override; - void paintGL() override; - void resizeGL(int width, int height) override; - /// @name Overriden from QOpenGLWindow. - //@{ - void mousePressEvent(QMouseEvent * e) override; - void mouseDoubleClickEvent(QMouseEvent * e) override; - void mouseMoveEvent(QMouseEvent * e) override; - void mouseReleaseEvent(QMouseEvent * e) override; - void wheelEvent(QWheelEvent * e) override; - void keyPressEvent(QKeyEvent * e) override; - void keyReleaseEvent(QKeyEvent * e) override; - //@} - - private: - void SubmitFakeLocationPoint(m2::PointD const & pt); - void SubmitRoutingPoint(m2::PointD const & pt); - void ShowInfoPopup(QMouseEvent * e, m2::PointD const & pt); - void ShowPlacePage(place_page::Info const & info); - - void OnViewportChanged(ScreenBase const & screen); - void UpdateScaleControl(); - df::Touch GetTouch(QMouseEvent * e); - df::Touch GetSymmetrical(const df::Touch & touch); - df::TouchEvent GetTouchEvent(QMouseEvent * e, df::TouchEvent::ETouchType type); - - inline int L2D(int px) const { return px * m_ratio; } - m2::PointD GetDevicePoint(QMouseEvent * e) const; - - void UpdateCountryStatus(storage::TCountryId const & countryId); - - QScaleSlider * m_pScale; - QRubberBand * m_rubberBand; - QPoint m_rubberBandOrigin; - bool m_enableScaleUpdate; - - bool m_emulatingLocation; - - void InitRenderPolicy(); - - unique_ptr m_skin; - - TCurrentCountryChanged m_currentCountryChanged; - storage::TCountryId m_countryId; - - bool m_selectionMode = false; - }; +namespace common +{ +class ScaleSlider; } + +class DrawWidget : public qt::common::MapWidget +{ + using TBase = MapWidget; + + Q_OBJECT + +public Q_SLOTS: + void ShowAll(); + + void ChoosePositionModeEnable(); + void ChoosePositionModeDisable(); + void OnUpdateCountryStatusByTimer(); + +public: + DrawWidget(Framework & framework, QWidget * parent); + ~DrawWidget(); + + bool Search(search::EverywhereSearchParams const & params); + string GetDistance(search::Result const & res) const; + void ShowSearchResult(search::Result const & res); + + void CreateFeature(); + + void OnLocationUpdate(location::GpsInfo const & info); + + void UpdateAfterSettingsChanged(); + + void PrepareShutdown(); + + Framework & GetFramework() { return m_framework; } + void SetMapStyle(MapStyle mapStyle); + + void SetRouter(routing::RouterType routerType); + + using TCurrentCountryChanged = function; + void SetCurrentCountryChangedListener(TCurrentCountryChanged const & listener); + + void DownloadCountry(storage::TCountryId const & countryId); + void RetryToDownloadCountry(storage::TCountryId const & countryId); + + void SetSelectionMode(bool mode); + +protected: + /// @name Overriden from MapWidget. + //@{ + void initializeGL() override; + + void mousePressEvent(QMouseEvent * e) override; + void mouseMoveEvent(QMouseEvent * e) override; + void mouseReleaseEvent(QMouseEvent * e) override; + void keyPressEvent(QKeyEvent * e) override; + void keyReleaseEvent(QKeyEvent * e) override; + //@} + +private: + void SubmitFakeLocationPoint(m2::PointD const & pt); + void SubmitRoutingPoint(m2::PointD const & pt); + void ShowInfoPopup(QMouseEvent * e, m2::PointD const & pt); + void ShowPlacePage(place_page::Info const & info); + + void UpdateCountryStatus(storage::TCountryId const & countryId); + + QRubberBand * m_rubberBand; + QPoint m_rubberBandOrigin; + + bool m_emulatingLocation; + + void InitRenderPolicy(); + + TCurrentCountryChanged m_currentCountryChanged; + storage::TCountryId m_countryId; + + bool m_selectionMode = false; +}; +} // namespace qt diff --git a/qt/main.cpp b/qt/main.cpp index 96c82e12e4..b34bc046bd 100644 --- a/qt/main.cpp +++ b/qt/main.cpp @@ -1,7 +1,8 @@ - #include "qt/info_dialog.hpp" #include "qt/mainwindow.hpp" +#include "map/framework.hpp" + #include "platform/platform.hpp" #include "platform/settings.hpp" @@ -62,6 +63,8 @@ namespace int main(int argc, char * argv[]) { + Q_INIT_RESOURCE(resources_common); + // Our double parsing code (base/string_utils.hpp) needs dots as a floating point delimiters, not commas. // TODO: Refactor our doubles parsing code to use locale-independent delimiters. // For example, https://github.com/google/double-conversion can be used. @@ -100,7 +103,8 @@ int main(int argc, char * argv[]) int returnCode = -1; if (eulaAccepted) // User has accepted EULA { - qt::MainWindow w; + Framework framework; + qt::MainWindow w(framework); w.show(); returnCode = a.exec(); } diff --git a/qt/mainwindow.cpp b/qt/mainwindow.cpp index 2d8225ee56..6ab5c3fc4d 100644 --- a/qt/mainwindow.cpp +++ b/qt/mainwindow.cpp @@ -3,8 +3,9 @@ #include "qt/mainwindow.hpp" #include "qt/osm_auth_dialog.hpp" #include "qt/preferences_dialog.hpp" +#include "qt/qt_common/helpers.hpp" +#include "qt/qt_common/scale_slider.hpp" #include "qt/search_panel.hpp" -#include "qt/slider_ctrl.hpp" #include "qt/traffic_mode.hpp" #include "qt/traffic_panel.hpp" #include "qt/trafficmodeinitdlg.h" @@ -120,7 +121,7 @@ namespace qt extern char const * kTokenKeySetting; extern char const * kTokenSecretSetting; -MainWindow::MainWindow() +MainWindow::MainWindow(Framework & framework) : m_Docks{} , m_locationService(CreateDesktopLocationService(*this)) { @@ -128,26 +129,7 @@ MainWindow::MainWindow() QDesktopWidget const * desktop(QApplication::desktop()); setGeometry(desktop->screenGeometry(desktop->primaryScreen())); - m_pDrawWidget = new DrawWidget(this); - QSurfaceFormat format = m_pDrawWidget->format(); - - format.setMajorVersion(2); - format.setMinorVersion(1); - - format.setAlphaBufferSize(8); - format.setBlueBufferSize(8); - format.setGreenBufferSize(8); - format.setRedBufferSize(8); - format.setStencilBufferSize(0); - format.setSamples(0); - format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - format.setSwapInterval(1); - format.setDepthBufferSize(16); - - format.setProfile(QSurfaceFormat::CompatibilityProfile); - //format.setOption(QSurfaceFormat::DebugContext); - m_pDrawWidget->setFormat(format); - m_pDrawWidget->setMouseTracking(true); + m_pDrawWidget = new DrawWidget(framework, this); setCentralWidget(m_pDrawWidget); QObject::connect(m_pDrawWidget, SIGNAL(BeforeEngineCreation()), this, SLOT(OnBeforeEngineCreation())); @@ -297,12 +279,6 @@ namespace } } - struct hotkey_t - { - int key; - char const * slot; - }; - void FormatMapSize(uint64_t sizeInBytes, string & units, size_t & sizeToDownload) { int const mbInBytes = 1024 * 1024; @@ -332,22 +308,20 @@ void MainWindow::CreateNavigationBar() pToolBar->setIconSize(QSize(32, 32)); { + m_pDrawWidget->BindHotkeys(*this); + // Add navigation hot keys. - hotkey_t const arr[] = { - { Qt::Key_Equal, SLOT(ScalePlus()) }, - { Qt::Key_Minus, SLOT(ScaleMinus()) }, - { Qt::ALT + Qt::Key_Equal, SLOT(ScalePlusLight()) }, - { Qt::ALT + Qt::Key_Minus, SLOT(ScaleMinusLight()) }, + qt::common::Hotkey const hotkeys[] = { { Qt::Key_A, SLOT(ShowAll()) }, // Use CMD+n (New Item hotkey) to activate Create Feature mode. { Qt::Key_Escape, SLOT(ChoosePositionModeDisable()) } }; - for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + for (auto const & hotkey : hotkeys) { QAction * pAct = new QAction(this); - pAct->setShortcut(QKeySequence(arr[i].key)); - connect(pAct, SIGNAL(triggered()), m_pDrawWidget, arr[i].slot); + pAct->setShortcut(QKeySequence(hotkey.m_key)); + connect(pAct, SIGNAL(triggered()), m_pDrawWidget, hotkey.m_slot); addAction(pAct); } } @@ -399,30 +373,9 @@ void MainWindow::CreateNavigationBar() m_pMyPositionAction->setToolTip(tr("My Position")); // #endif - // add view actions 1 - button_t arr[] = { - { QString(), 0, 0 }, - //{ tr("Show all"), ":/navig64/world.png", SLOT(ShowAll()) }, - { tr("Scale +"), ":/navig64/plus.png", SLOT(ScalePlus()) } - }; - add_buttons(pToolBar, arr, ARRAY_SIZE(arr), m_pDrawWidget); } - // add scale slider - QScaleSlider * pScale = new QScaleSlider(Qt::Vertical, this, 20); - pScale->SetRange(2, scales::GetUpperScale()); - pScale->setTickPosition(QSlider::TicksRight); - - pToolBar->addWidget(pScale); - m_pDrawWidget->SetScaleControl(pScale); - - { - // add view actions 2 - button_t arr[] = { - { tr("Scale -"), ":/navig64/minus.png", SLOT(ScaleMinus()) } - }; - add_buttons(pToolBar, arr, ARRAY_SIZE(arr), m_pDrawWidget); - } + qt::common::ScaleSlider::Embed(Qt::Vertical, *pToolBar, *m_pDrawWidget); #ifndef NO_DOWNLOADER { diff --git a/qt/mainwindow.hpp b/qt/mainwindow.hpp index 16fc563072..e523084753 100644 --- a/qt/mainwindow.hpp +++ b/qt/mainwindow.hpp @@ -15,9 +15,10 @@ #include #endif +class Framework; class QDockWidget; -class QPushButton; class QLabel; +class QPushButton; class TrafficMode; namespace search { class Result; } @@ -54,7 +55,7 @@ namespace qt Q_OBJECT public: - MainWindow(); + MainWindow(Framework & framework); virtual void OnLocationError(location::TLocationError errorCode); virtual void OnLocationUpdated(location::GpsInfo const & info); diff --git a/qt/proxystyle.cpp b/qt/proxystyle.cpp deleted file mode 100644 index 05e21dfba0..0000000000 --- a/qt/proxystyle.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "qt/proxystyle.hpp" - - -ProxyStyle::ProxyStyle(QStyle * p) - : QStyle(), style(p) -{ -} - -void ProxyStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const -{ - style->drawComplexControl(control, option, painter, widget); -} - -void ProxyStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const -{ - style->drawControl(element, option, painter, widget); -} - -void ProxyStyle::drawItemPixmap(QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const -{ - style->drawItemPixmap(painter, rect, alignment, pixmap); -} - -void ProxyStyle::drawItemText(QPainter* painter, const QRect& rect, int alignment, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole) const -{ - style->drawItemText(painter, rect, alignment, pal, enabled, text, textRole); -} - -void ProxyStyle::drawPrimitive(PrimitiveElement elem, const QStyleOption* option, QPainter* painter, const QWidget* widget) const -{ - style->drawPrimitive(elem, option, painter, widget); -} - -QPixmap ProxyStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* option) const -{ - return style->generatedIconPixmap(iconMode, pixmap, option); -} - -QStyle::SubControl ProxyStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex* option, const QPoint& pos, const QWidget* widget) const -{ - return style->hitTestComplexControl(control, option, pos, widget); -} - -QRect ProxyStyle::itemPixmapRect(const QRect& rect, int alignment, const QPixmap& pixmap) const -{ - return style->itemPixmapRect(rect, alignment, pixmap); -} - -QRect ProxyStyle::itemTextRect(const QFontMetrics& metrics, const QRect& rect, int alignment, bool enabled, const QString& text) const -{ - return style->itemTextRect(metrics, rect, alignment, enabled, text); -} - -int ProxyStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const -{ - return style->pixelMetric(metric, option, widget); -} - -void ProxyStyle::polish(QWidget* widget) -{ - style->polish(widget); -} - -void ProxyStyle::polish(QApplication* app) -{ - style->polish(app); -} - -void ProxyStyle::polish(QPalette& pal) -{ - style->polish(pal); -} - -QSize ProxyStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget) const -{ - return style->sizeFromContents(type, option, contentsSize, widget); -} - -QIcon ProxyStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption* option, const QWidget* widget) const -{ - return style->standardIcon(standardIcon, option, widget); -} - -QPalette ProxyStyle::standardPalette() const -{ - return style->standardPalette(); -} - -QPixmap ProxyStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption* option, const QWidget* widget) const -{ - return style->standardPixmap(standardPixmap, option, widget); -} - -int ProxyStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const -{ - return style->styleHint(hint, option, widget, returnData); -} - -QRect ProxyStyle::subControlRect(ComplexControl control, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget) const -{ - return style->subControlRect(control, option, subControl, widget); -} - -QRect ProxyStyle::subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const -{ - return style->subElementRect(element, option, widget); -} - -void ProxyStyle::unpolish(QWidget* widget) -{ - style->unpolish(widget); -} - -void ProxyStyle::unpolish(QApplication* app) -{ - style->unpolish(app); -} - -int ProxyStyle::layoutSpacing(QSizePolicy::ControlType control1, - QSizePolicy::ControlType control2, Qt::Orientation orientation, - const QStyleOption *option, const QWidget *widget) const -{ - return style->layoutSpacing(control1, control2, orientation, option, widget); -} diff --git a/qt/proxystyle.hpp b/qt/proxystyle.hpp deleted file mode 100644 index b6a49e36fc..0000000000 --- a/qt/proxystyle.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - #include -#else - #include -#endif - - -class ProxyStyle : public QStyle -{ -public: - explicit ProxyStyle(QStyle * p); - - void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = 0) const; - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0) const; - void drawItemPixmap(QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const; - void drawItemText(QPainter* painter, const QRect& rect, int alignment, const QPalette& pal, bool enabled, const QString& text, QPalette::ColorRole textRole = QPalette::NoRole) const; - void drawPrimitive(PrimitiveElement elem, const QStyleOption* option, QPainter* painter, const QWidget* widget = 0) const; - QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap& pixmap, const QStyleOption* option) const; - SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex* option, const QPoint& pos, const QWidget* widget = 0) const; - QRect itemPixmapRect(const QRect& rect, int alignment, const QPixmap& pixmap) const; - QRect itemTextRect(const QFontMetrics& metrics, const QRect& rect, int alignment, bool enabled, const QString& text) const; - int pixelMetric(PixelMetric metric, const QStyleOption* option = 0, const QWidget* widget = 0) const; - void polish(QWidget* widget); - void polish(QApplication* app); - void polish(QPalette& pal); - QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget = 0) const; - QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption* option = 0, const QWidget* widget = 0) const; - QPalette standardPalette() const; - QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption* option = 0, const QWidget* widget = 0) const; - int styleHint(StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const; - QRect subControlRect(ComplexControl control, const QStyleOptionComplex* option, SubControl subControl, const QWidget* widget = 0) const; - QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget = 0) const; - void unpolish(QWidget* widget); - void unpolish(QApplication* app); - int layoutSpacing(QSizePolicy::ControlType control1, - QSizePolicy::ControlType control2, Qt::Orientation orientation, - const QStyleOption *option = 0, const QWidget *widget = 0) const; - -private: - QStyle * style; -}; diff --git a/qt/qt.pro b/qt/qt.pro index 1c424a0825..8959cf5b07 100644 --- a/qt/qt.pro +++ b/qt/qt.pro @@ -1,6 +1,7 @@ # Main application in qt. ROOT_DIR = .. -DEPENDENCIES = map drape_frontend openlr routing search storage tracking traffic routing_common \ + +DEPENDENCIES = qt_common map drape_frontend openlr routing search storage tracking traffic routing_common \ indexer drape partners_api platform editor geometry \ coding base freetype expat fribidi jansson protobuf osrm stats_client \ minizip succinct pugixml oauthcpp stb_image sdf_image @@ -112,11 +113,7 @@ SOURCES += \ osm_auth_dialog.cpp \ place_page_dialog.cpp \ preferences_dialog.cpp \ - proxystyle.cpp \ - qtoglcontext.cpp \ - qtoglcontextfactory.cpp \ search_panel.cpp \ - slider_ctrl.cpp \ traffic_mode.cpp \ traffic_panel.cpp \ trafficmodeinitdlg.cpp \ @@ -132,11 +129,7 @@ HEADERS += \ osm_auth_dialog.hpp \ place_page_dialog.hpp \ preferences_dialog.hpp \ - proxystyle.hpp \ - qtoglcontext.hpp \ - qtoglcontextfactory.hpp \ search_panel.hpp \ - slider_ctrl.hpp \ traffic_mode.hpp \ traffic_panel.hpp \ trafficmodeinitdlg.h \ diff --git a/qt/qt_common/CMakeLists.txt b/qt/qt_common/CMakeLists.txt new file mode 100644 index 0000000000..04c98fc873 --- /dev/null +++ b/qt/qt_common/CMakeLists.txt @@ -0,0 +1,21 @@ +project(qt_common) + +QT5_ADD_RESOURCES(RESOURCES res/resources_common.qrc) + +set( + SRC + helpers.cpp + helpers.hpp + map_widget.cpp + map_widget.hpp + proxy_style.cpp + proxy_style.hpp + qtoglcontext.cpp + qtoglcontext.hpp + qtoglcontextfactory.cpp + qtoglcontextfactory.hpp + scale_slider.cpp + scale_slider.hpp +) + +add_library(${PROJECT_NAME} ${SRC} ${RESOURCES}) diff --git a/qt/qt_common/helpers.cpp b/qt/qt_common/helpers.cpp new file mode 100644 index 0000000000..a6081809b3 --- /dev/null +++ b/qt/qt_common/helpers.cpp @@ -0,0 +1,27 @@ +#include "qt/qt_common/helpers.hpp" + +namespace qt +{ +namespace common +{ +bool IsLeftButton(Qt::MouseButtons buttons) { return buttons & Qt::LeftButton; } + +bool IsLeftButton(QMouseEvent const * const e) +{ + return IsLeftButton(e->button()) || IsLeftButton(e->buttons()); +} + +bool IsRightButton(Qt::MouseButtons buttons) { return buttons & Qt::RightButton; } + +bool IsRightButton(QMouseEvent const * const e) +{ + return IsRightButton(e->button()) || IsRightButton(e->buttons()); +} + +bool IsCommandModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::ControlModifier; } + +bool IsShiftModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::ShiftModifier; } + +bool IsAltModifier(QMouseEvent const * const e) { return e->modifiers() & Qt::AltModifier; } +} // namespace common +} // namespace qt diff --git a/qt/qt_common/helpers.hpp b/qt/qt_common/helpers.hpp new file mode 100644 index 0000000000..71c1c37e83 --- /dev/null +++ b/qt/qt_common/helpers.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace qt +{ +namespace common +{ +bool IsLeftButton(Qt::MouseButtons buttons); +bool IsLeftButton(QMouseEvent const * const e); + +bool IsRightButton(Qt::MouseButtons buttons); +bool IsRightButton(QMouseEvent const * const e); + +bool IsCommandModifier(QMouseEvent const * const e); +bool IsShiftModifier(QMouseEvent const * const e); +bool IsAltModifier(QMouseEvent const * const e); + +struct Hotkey +{ + Hotkey() = default; + Hotkey(int key, char const * slot) : m_key(key), m_slot(slot) {} + + int m_key = 0; + char const * m_slot = nullptr; +}; +} // namespace common +} // namespace qt diff --git a/qt/qt_common/map_widget.cpp b/qt/qt_common/map_widget.cpp new file mode 100644 index 0000000000..08490e2d74 --- /dev/null +++ b/qt/qt_common/map_widget.cpp @@ -0,0 +1,313 @@ +#include "qt/qt_common/map_widget.hpp" + +#include "qt/qt_common/helpers.hpp" +#include "qt/qt_common/scale_slider.hpp" + +#include "map/framework.hpp" + +#include "geometry/point2d.hpp" + +#include "base/assert.hpp" + +#include +#include +#include +#include + +namespace qt +{ +namespace common +{ +MapWidget::MapWidget(Framework & framework, QWidget * parent) + : QOpenGLWidget(parent) + , m_framework(framework) + , m_slider(nullptr) + , m_sliderState(SliderState::Released) + , m_ratio(1.0) + , m_contextFactory(nullptr) +{ + QSurfaceFormat fmt = format(); + + fmt.setMajorVersion(2); + fmt.setMinorVersion(1); + + fmt.setAlphaBufferSize(8); + fmt.setBlueBufferSize(8); + fmt.setGreenBufferSize(8); + fmt.setRedBufferSize(8); + fmt.setStencilBufferSize(0); + fmt.setSamples(0); + fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + fmt.setSwapInterval(1); + fmt.setDepthBufferSize(16); + fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + + // fmt.setOption(QSurfaceFormat::DebugContext); + setFormat(fmt); + setMouseTracking(true); + + // Update widget contents each 30ms. + m_updateTimer = make_unique(this); + VERIFY(connect(m_updateTimer.get(), SIGNAL(timeout()), this, SLOT(update())), ()); + m_updateTimer->setSingleShot(false); + m_updateTimer->start(30); +} + +MapWidget::~MapWidget() { m_framework.EnterBackground(); } + +void MapWidget::BindHotkeys(QWidget & parent) +{ + Hotkey const hotkeys[] = { + {Qt::Key_Equal, SLOT(ScalePlus())}, + {Qt::Key_Minus, SLOT(ScaleMinus())}, + {Qt::ALT + Qt::Key_Equal, SLOT(ScalePlusLight())}, + {Qt::ALT + Qt::Key_Minus, SLOT(ScaleMinusLight())}, + }; + + for (auto const & hotkey : hotkeys) + { + auto action = make_unique(&parent); + action->setShortcut(QKeySequence(hotkey.m_key)); + connect(action.get(), SIGNAL(triggered()), this, hotkey.m_slot); + parent.addAction(action.release()); + } +} + +void MapWidget::BindSlider(ScaleSlider & slider) +{ + m_slider = &slider; + + connect(m_slider, SIGNAL(actionTriggered(int)), this, SLOT(ScaleChanged(int))); + connect(m_slider, SIGNAL(sliderPressed()), this, SLOT(SliderPressed())); + connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(SliderReleased())); +} + +void MapWidget::CreateEngine() +{ + Framework::DrapeCreationParams p; + p.m_surfaceWidth = m_ratio * width(); + p.m_surfaceHeight = m_ratio * height(); + p.m_visualScale = m_ratio; + + m_skin.reset(new gui::Skin(gui::ResolveGuiSkinFile("default"), m_ratio)); + m_skin->Resize(p.m_surfaceWidth, p.m_surfaceHeight); + m_skin->ForEach( + [&p](gui::EWidget widget, gui::Position const & pos) { p.m_widgetsInitInfo[widget] = pos; }); + + p.m_widgetsInitInfo[gui::WIDGET_SCALE_LABEL] = gui::Position(dp::LeftBottom); + + m_framework.CreateDrapeEngine(make_ref(m_contextFactory), std::move(p)); + m_framework.SetViewportListener([this](ScreenBase const & /* screen */) { + UpdateScaleControl(); + }); +} + +void MapWidget::ScalePlus() { m_framework.Scale(Framework::SCALE_MAG, true); } + +void MapWidget::ScaleMinus() { m_framework.Scale(Framework::SCALE_MIN, true); } + +void MapWidget::ScalePlusLight() { m_framework.Scale(Framework::SCALE_MAG_LIGHT, true); } + +void MapWidget::ScaleMinusLight() { m_framework.Scale(Framework::SCALE_MIN_LIGHT, true); } + +void MapWidget::ScaleChanged(int action) +{ + if (!m_slider) + return; + + if (action == QAbstractSlider::SliderNoAction) + return; + + double const factor = m_slider->GetScaleFactor(); + if (factor != 1.0) + m_framework.Scale(factor, false); +} + +void MapWidget::SliderPressed() { m_sliderState = SliderState::Pressed; } + +void MapWidget::SliderReleased() { m_sliderState = SliderState::Released; } + +m2::PointD MapWidget::GetDevicePoint(QMouseEvent * e) const +{ + return m2::PointD(L2D(e->x()), L2D(e->y())); +} + +df::Touch MapWidget::GetTouch(QMouseEvent * e) const +{ + df::Touch touch; + touch.m_id = 0; + touch.m_location = GetDevicePoint(e); + return touch; +} + +df::TouchEvent MapWidget::GetTouchEvent(QMouseEvent * e, df::TouchEvent::ETouchType type) const +{ + df::TouchEvent event; + event.SetTouchType(type); + event.SetFirstTouch(GetTouch(e)); + if (IsCommandModifier(e)) + event.SetSecondTouch(GetSymmetrical(event.GetFirstTouch())); + + return event; +} + +df::Touch MapWidget::GetSymmetrical(df::Touch const & touch) const +{ + m2::PointD pixelCenter = m_framework.GetPixelCenter(); + m2::PointD symmetricalLocation = pixelCenter + (pixelCenter - touch.m_location); + + df::Touch result; + result.m_id = touch.m_id + 1; + result.m_location = symmetricalLocation; + + return result; +} + +void MapWidget::UpdateScaleControl() +{ + if (!m_slider || m_sliderState == SliderState::Pressed) + return; + m_slider->SetPosWithBlockedSignals(m_framework.GetDrawScale()); +} + +void MapWidget::initializeGL() +{ + ASSERT(m_contextFactory == nullptr, ()); + m_ratio = devicePixelRatio(); + m_contextFactory.reset(new QtOGLContextFactory(context())); + + emit BeforeEngineCreation(); + CreateEngine(); + m_framework.EnterForeground(); +} + +void MapWidget::paintGL() +{ + static QOpenGLShaderProgram * program = nullptr; + if (program == nullptr) + { + const char * vertexSrc = + "\ + attribute vec2 a_position; \ + attribute vec2 a_texCoord; \ + uniform mat4 u_projection; \ + varying vec2 v_texCoord; \ + \ + void main(void) \ + { \ + gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\ + v_texCoord = a_texCoord; \ + }"; + + const char * fragmentSrc = + "\ + uniform sampler2D u_sampler; \ + varying vec2 v_texCoord; \ + \ + void main(void) \ + { \ + gl_FragColor = vec4(texture2D(u_sampler, v_texCoord).rgb, 1.0); \ + }"; + + program = new QOpenGLShaderProgram(this); + program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSrc); + program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSrc); + program->link(); + } + + if (m_contextFactory->LockFrame()) + { + QOpenGLFunctions * funcs = context()->functions(); + funcs->glActiveTexture(GL_TEXTURE0); + GLuint image = m_contextFactory->GetTextureHandle(); + funcs->glBindTexture(GL_TEXTURE_2D, image); + + int projectionLocation = program->uniformLocation("u_projection"); + int samplerLocation = program->uniformLocation("u_sampler"); + + QMatrix4x4 projection; + QRect r = rect(); + r.setWidth(m_ratio * r.width()); + r.setHeight(m_ratio * r.height()); + projection.ortho(r); + + program->bind(); + program->setUniformValue(projectionLocation, projection); + program->setUniformValue(samplerLocation, 0); + + float const w = m_ratio * width(); + float h = m_ratio * height(); + + QVector2D positions[4] = {QVector2D(0.0, 0.0), QVector2D(w, 0.0), QVector2D(0.0, h), + QVector2D(w, h)}; + + QRectF const & texRect = m_contextFactory->GetTexRect(); + QVector2D texCoords[4] = {QVector2D(texRect.bottomLeft()), QVector2D(texRect.bottomRight()), + QVector2D(texRect.topLeft()), QVector2D(texRect.topRight())}; + + program->enableAttributeArray("a_position"); + program->enableAttributeArray("a_texCoord"); + program->setAttributeArray("a_position", positions, 0); + program->setAttributeArray("a_texCoord", texCoords, 0); + + funcs->glClearColor(0.0, 0.0, 0.0, 1.0); + funcs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + funcs->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_contextFactory->UnlockFrame(); + } +} + +void MapWidget::resizeGL(int width, int height) +{ + float w = m_ratio * width; + float h = m_ratio * height; + m_framework.OnSize(w, h); + m_framework.SetVisibleViewport(m2::RectD(0, 0, w, h)); + if (m_skin) + { + m_skin->Resize(w, h); + + gui::TWidgetsLayoutInfo layout; + m_skin->ForEach( + [&layout](gui::EWidget w, gui::Position const & pos) { layout[w] = pos.m_pixelPivot; }); + + m_framework.SetWidgetLayout(std::move(layout)); + } +} + +void MapWidget::mouseDoubleClickEvent(QMouseEvent * e) +{ + QOpenGLWidget::mouseDoubleClickEvent(e); + if (IsLeftButton(e)) + m_framework.Scale(Framework::SCALE_MAG_LIGHT, GetDevicePoint(e), true); +} + +void MapWidget::mousePressEvent(QMouseEvent * e) +{ + QOpenGLWidget::mousePressEvent(e); + if (IsLeftButton(e)) + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_DOWN)); +} + +void MapWidget::mouseMoveEvent(QMouseEvent * e) +{ + QOpenGLWidget::mouseMoveEvent(e); + if (IsLeftButton(e)) + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_MOVE)); +} + +void MapWidget::mouseReleaseEvent(QMouseEvent * e) +{ + QOpenGLWidget::mouseReleaseEvent(e); + if (IsLeftButton(e)) + m_framework.TouchEvent(GetTouchEvent(e, df::TouchEvent::TOUCH_UP)); +} + +void MapWidget::wheelEvent(QWheelEvent * e) +{ + QOpenGLWidget::wheelEvent(e); + m_framework.Scale(exp(e->delta() / 360.0), m2::PointD(L2D(e->x()), L2D(e->y())), false); +} +} // namespace common +} // namespace qt diff --git a/qt/qt_common/map_widget.hpp b/qt/qt_common/map_widget.hpp new file mode 100644 index 0000000000..e4251118ec --- /dev/null +++ b/qt/qt_common/map_widget.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include "drape/pointers.hpp" +#include "drape_frontend/gui/skin.hpp" +#include "drape_frontend/user_event_stream.hpp" +#include "qt/qt_common/qtoglcontextfactory.hpp" + +#include +#include + +#include + +class Framework; +class QMouseEvent; +class QWidget; +class ScreenBase; + +namespace qt +{ +namespace common +{ +class ScaleSlider; + +class MapWidget : public QOpenGLWidget +{ + Q_OBJECT + +public: + MapWidget(Framework & framework, QWidget * parent); + ~MapWidget(); + + void BindHotkeys(QWidget & parent); + void BindSlider(ScaleSlider & slider); + void CreateEngine(); + +public Q_SLOTS: + void ScalePlus(); + void ScaleMinus(); + void ScalePlusLight(); + void ScaleMinusLight(); + + void ScaleChanged(int action); + void SliderPressed(); + void SliderReleased(); + +public: + Q_SIGNAL void BeforeEngineCreation(); + +protected: + enum class SliderState + { + Pressed, + Released + }; + + int L2D(int px) const { return px * m_ratio; } + m2::PointD GetDevicePoint(QMouseEvent * e) const; + df::Touch GetTouch(QMouseEvent * e) const; + df::TouchEvent GetTouchEvent(QMouseEvent * e, df::TouchEvent::ETouchType type) const; + df::Touch GetSymmetrical(df::Touch const & touch) const; + + void UpdateScaleControl(); + + // QOpenGLWidget overrides: + void initializeGL() override; + void paintGL() override; + void resizeGL(int width, int height) override; + + void mouseDoubleClickEvent(QMouseEvent * e) override; + void mousePressEvent(QMouseEvent * e) override; + void mouseMoveEvent(QMouseEvent * e) override; + void mouseReleaseEvent(QMouseEvent * e) override; + void wheelEvent(QWheelEvent * e) override; + + Framework & m_framework; + ScaleSlider * m_slider; + SliderState m_sliderState; + + qreal m_ratio; + drape_ptr m_contextFactory; + std::unique_ptr m_skin; + + unique_ptr m_updateTimer; +}; +} // namespace common +} // namespace qt diff --git a/qt/qt_common/proxy_style.cpp b/qt/qt_common/proxy_style.cpp new file mode 100644 index 0000000000..c9ed436034 --- /dev/null +++ b/qt/qt_common/proxy_style.cpp @@ -0,0 +1,126 @@ +#include "qt/qt_common/proxy_style.hpp" + +namespace qt +{ +namespace common +{ +ProxyStyle::ProxyStyle(QStyle * p) : QStyle(), style(p) {} + +void ProxyStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex * option, + QPainter * painter, const QWidget * widget) const +{ + style->drawComplexControl(control, option, painter, widget); +} + +void ProxyStyle::drawControl(ControlElement element, const QStyleOption * option, + QPainter * painter, const QWidget * widget) const +{ + style->drawControl(element, option, painter, widget); +} + +void ProxyStyle::drawItemPixmap(QPainter * painter, const QRect & rect, int alignment, + const QPixmap & pixmap) const +{ + style->drawItemPixmap(painter, rect, alignment, pixmap); +} + +void ProxyStyle::drawItemText(QPainter * painter, const QRect & rect, int alignment, + const QPalette & pal, bool enabled, const QString & text, + QPalette::ColorRole textRole) const +{ + style->drawItemText(painter, rect, alignment, pal, enabled, text, textRole); +} + +void ProxyStyle::drawPrimitive(PrimitiveElement elem, const QStyleOption * option, + QPainter * painter, const QWidget * widget) const +{ + style->drawPrimitive(elem, option, painter, widget); +} + +QPixmap ProxyStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap & pixmap, + const QStyleOption * option) const +{ + return style->generatedIconPixmap(iconMode, pixmap, option); +} + +QStyle::SubControl ProxyStyle::hitTestComplexControl(ComplexControl control, + const QStyleOptionComplex * option, + const QPoint & pos, + const QWidget * widget) const +{ + return style->hitTestComplexControl(control, option, pos, widget); +} + +QRect ProxyStyle::itemPixmapRect(const QRect & rect, int alignment, const QPixmap & pixmap) const +{ + return style->itemPixmapRect(rect, alignment, pixmap); +} + +QRect ProxyStyle::itemTextRect(const QFontMetrics & metrics, const QRect & rect, int alignment, + bool enabled, const QString & text) const +{ + return style->itemTextRect(metrics, rect, alignment, enabled, text); +} + +int ProxyStyle::pixelMetric(PixelMetric metric, const QStyleOption * option, + const QWidget * widget) const +{ + return style->pixelMetric(metric, option, widget); +} + +void ProxyStyle::polish(QWidget * widget) { style->polish(widget); } + +void ProxyStyle::polish(QApplication * app) { style->polish(app); } + +void ProxyStyle::polish(QPalette & pal) { style->polish(pal); } + +QSize ProxyStyle::sizeFromContents(ContentsType type, const QStyleOption * option, + const QSize & contentsSize, const QWidget * widget) const +{ + return style->sizeFromContents(type, option, contentsSize, widget); +} + +QIcon ProxyStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption * option, + const QWidget * widget) const +{ + return style->standardIcon(standardIcon, option, widget); +} + +QPalette ProxyStyle::standardPalette() const { return style->standardPalette(); } + +QPixmap ProxyStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption * option, + const QWidget * widget) const +{ + return style->standardPixmap(standardPixmap, option, widget); +} + +int ProxyStyle::styleHint(StyleHint hint, const QStyleOption * option, const QWidget * widget, + QStyleHintReturn * returnData) const +{ + return style->styleHint(hint, option, widget, returnData); +} + +QRect ProxyStyle::subControlRect(ComplexControl control, const QStyleOptionComplex * option, + SubControl subControl, const QWidget * widget) const +{ + return style->subControlRect(control, option, subControl, widget); +} + +QRect ProxyStyle::subElementRect(SubElement element, const QStyleOption * option, + const QWidget * widget) const +{ + return style->subElementRect(element, option, widget); +} + +void ProxyStyle::unpolish(QWidget * widget) { style->unpolish(widget); } + +void ProxyStyle::unpolish(QApplication * app) { style->unpolish(app); } + +int ProxyStyle::layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, + Qt::Orientation orientation, const QStyleOption * option, + const QWidget * widget) const +{ + return style->layoutSpacing(control1, control2, orientation, option, widget); +} +} // namespace common +} // namespace qt diff --git a/qt/qt_common/proxy_style.hpp b/qt/qt_common/proxy_style.hpp new file mode 100644 index 0000000000..c0b3a22ca6 --- /dev/null +++ b/qt/qt_common/proxy_style.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include + +namespace qt +{ +namespace common +{ +class ProxyStyle : public QStyle +{ +public: + explicit ProxyStyle(QStyle * p); + + void drawComplexControl(ComplexControl control, const QStyleOptionComplex * option, + QPainter * painter, const QWidget * widget = 0) const; + void drawControl(ControlElement element, const QStyleOption * option, QPainter * painter, + const QWidget * widget = 0) const; + void drawItemPixmap(QPainter * painter, const QRect & rect, int alignment, + const QPixmap & pixmap) const; + void drawItemText(QPainter * painter, const QRect & rect, int alignment, const QPalette & pal, + bool enabled, const QString & text, + QPalette::ColorRole textRole = QPalette::NoRole) const; + void drawPrimitive(PrimitiveElement elem, const QStyleOption * option, QPainter * painter, + const QWidget * widget = 0) const; + QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap & pixmap, + const QStyleOption * option) const; + SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex * option, + const QPoint & pos, const QWidget * widget = 0) const; + QRect itemPixmapRect(const QRect & rect, int alignment, const QPixmap & pixmap) const; + QRect itemTextRect(const QFontMetrics & metrics, const QRect & rect, int alignment, bool enabled, + const QString & text) const; + int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, + const QWidget * widget = 0) const; + void polish(QWidget * widget); + void polish(QApplication * app); + void polish(QPalette & pal); + QSize sizeFromContents(ContentsType type, const QStyleOption * option, const QSize & contentsSize, + const QWidget * widget = 0) const; + QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption * option = 0, + const QWidget * widget = 0) const; + QPalette standardPalette() const; + QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption * option = 0, + const QWidget * widget = 0) const; + int styleHint(StyleHint hint, const QStyleOption * option = 0, const QWidget * widget = 0, + QStyleHintReturn * returnData = 0) const; + QRect subControlRect(ComplexControl control, const QStyleOptionComplex * option, + SubControl subControl, const QWidget * widget = 0) const; + QRect subElementRect(SubElement element, const QStyleOption * option, + const QWidget * widget = 0) const; + void unpolish(QWidget * widget); + void unpolish(QApplication * app); + int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, + Qt::Orientation orientation, const QStyleOption * option = 0, + const QWidget * widget = 0) const; + +private: + QStyle * style; +}; +} // namespace common +} // namespace qt diff --git a/qt/qt_common/qt_common.pro b/qt/qt_common/qt_common.pro new file mode 100644 index 0000000000..b3026b6571 --- /dev/null +++ b/qt/qt_common/qt_common.pro @@ -0,0 +1,29 @@ +# Qt common library. + +TARGET = qt_common +TEMPLATE = lib +CONFIG += staticlib warn_on + +ROOT_DIR = ../.. + +include($$ROOT_DIR/common.pri) + +QT *= core gui widgets + +SOURCES += \ + helpers.cpp \ + map_widget.cpp \ + proxy_style.cpp \ + qtoglcontext.cpp \ + qtoglcontextfactory.cpp \ + scale_slider.cpp \ + +HEADERS += \ + helpers.hpp \ + map_widget.hpp \ + proxy_style.hpp \ + qtoglcontext.hpp \ + qtoglcontextfactory.hpp \ + scale_slider.hpp \ + +RESOURCES += res/resources_common.qrc diff --git a/qt/qtoglcontext.cpp b/qt/qt_common/qtoglcontext.cpp similarity index 95% rename from qt/qtoglcontext.cpp rename to qt/qt_common/qtoglcontext.cpp index 3bb75d15e1..9793e2f020 100644 --- a/qt/qtoglcontext.cpp +++ b/qt/qt_common/qtoglcontext.cpp @@ -1,4 +1,4 @@ -#include "qt/qtoglcontext.hpp" +#include "qt/qt_common/qtoglcontext.hpp" #include "base/assert.hpp" #include "base/logging.hpp" @@ -7,6 +7,10 @@ #include "drape/glfunctions.hpp" +namespace qt +{ +namespace common +{ QtRenderOGLContext::QtRenderOGLContext(QOpenGLContext * rootContext, QOffscreenSurface * surface) : m_surface(surface) { @@ -126,3 +130,5 @@ void QtUploadOGLContext::setDefaultFramebuffer() { ASSERT(false, ()); } +} // namespace common +} // namespace qt diff --git a/qt/qtoglcontext.hpp b/qt/qt_common/qtoglcontext.hpp similarity index 94% rename from qt/qtoglcontext.hpp rename to qt/qt_common/qtoglcontext.hpp index 1e4ac1dab4..79e773bd98 100644 --- a/qt/qtoglcontext.hpp +++ b/qt/qt_common/qtoglcontext.hpp @@ -7,6 +7,10 @@ #include #include +namespace qt +{ +namespace common +{ class QtRenderOGLContext : public dp::OGLContext { public: @@ -51,3 +55,5 @@ private: QOpenGLContext * m_ctx = nullptr; QOffscreenSurface * m_surface = nullptr; }; +} // namespace common +} // namespace qt diff --git a/qt/qtoglcontextfactory.cpp b/qt/qt_common/qtoglcontextfactory.cpp similarity index 93% rename from qt/qtoglcontextfactory.cpp rename to qt/qt_common/qtoglcontextfactory.cpp index 2d8093da53..4a35517875 100644 --- a/qt/qtoglcontextfactory.cpp +++ b/qt/qt_common/qtoglcontextfactory.cpp @@ -1,7 +1,11 @@ -#include "qt/qtoglcontextfactory.hpp" +#include "qt/qt_common/qtoglcontextfactory.hpp" #include "base/assert.hpp" +namespace qt +{ +namespace common +{ QtOGLContextFactory::QtOGLContextFactory(QOpenGLContext * rootContext) : m_rootContext(rootContext) , m_drawContext(nullptr) @@ -76,3 +80,5 @@ QOffscreenSurface * QtOGLContextFactory::createSurface() return result; } +} // namespace common +} // namespace qt diff --git a/qt/qtoglcontextfactory.hpp b/qt/qt_common/qtoglcontextfactory.hpp similarity index 88% rename from qt/qtoglcontextfactory.hpp rename to qt/qt_common/qtoglcontextfactory.hpp index 16bb0c7362..ef08d6ae08 100644 --- a/qt/qtoglcontextfactory.hpp +++ b/qt/qt_common/qtoglcontextfactory.hpp @@ -1,11 +1,15 @@ #pragma once #include "drape/oglcontextfactory.hpp" -#include "qt/qtoglcontext.hpp" +#include "qt/qt_common/qtoglcontext.hpp" #include #include +namespace qt +{ +namespace common +{ class QtOGLContextFactory : public dp::OGLContextFactory { public: @@ -33,3 +37,5 @@ private: QtUploadOGLContext * m_uploadContext; QOffscreenSurface * m_uploadSurface; }; +} // namespace common +} // namespace qt diff --git a/qt/res/minus.png b/qt/qt_common/res/minus.png similarity index 100% rename from qt/res/minus.png rename to qt/qt_common/res/minus.png diff --git a/qt/res/plus.png b/qt/qt_common/res/plus.png similarity index 100% rename from qt/res/plus.png rename to qt/qt_common/res/plus.png diff --git a/qt/qt_common/res/resources_common.qrc b/qt/qt_common/res/resources_common.qrc new file mode 100644 index 0000000000..9db3deeeb5 --- /dev/null +++ b/qt/qt_common/res/resources_common.qrc @@ -0,0 +1,6 @@ + + + plus.png + minus.png + + diff --git a/qt/qt_common/scale_slider.cpp b/qt/qt_common/scale_slider.cpp new file mode 100644 index 0000000000..512a809ee7 --- /dev/null +++ b/qt/qt_common/scale_slider.cpp @@ -0,0 +1,76 @@ +#include "qt/qt_common/scale_slider.hpp" + +#include "qt/qt_common/map_widget.hpp" +#include "qt/qt_common/proxy_style.hpp" + +#include "indexer/scales.hpp" + +#include "base/math.hpp" + +#include + +#include "base/stl_add.hpp" + +namespace qt +{ +namespace common +{ +namespace +{ +class MyProxyStyle : public ProxyStyle +{ +public: + MyProxyStyle(QStyle * parent) : ProxyStyle(parent) {} + + int styleHint(StyleHint hint, const QStyleOption * option, const QWidget * widget, + QStyleHintReturn * returnData) const override + { + if (hint == SH_Slider_AbsoluteSetButtons) + return Qt::LeftButton; + return ProxyStyle::styleHint(hint, option, widget, returnData); + } +}; +} // namespace + +ScaleSlider::ScaleSlider(Qt::Orientation orient, QWidget * parent) + : QSlider(orient, parent), m_factor(20) +{ + setStyle(new MyProxyStyle(style())); + SetRange(2, scales::GetUpperScale()); + setTickPosition(QSlider::TicksRight); +} + +// static +void ScaleSlider::Embed(Qt::Orientation orient, QToolBar & toolBar, MapWidget & mapWidget) +{ + toolBar.addAction(QIcon(":/navig64/plus.png"), tr("Scale +"), &mapWidget, SLOT(ScalePlus())); + { + auto slider = my::make_unique(orient, &toolBar); + mapWidget.BindSlider(*slider); + toolBar.addWidget(slider.release()); + } + toolBar.addAction(QIcon(":/navig64/minus.png"), tr("Scale -"), &mapWidget, SLOT(ScaleMinus())); +} + +double ScaleSlider::GetScaleFactor() const +{ + double const oldValue = value(); + double const newValue = sliderPosition(); + + if (oldValue == newValue) + return 1.0; + double const f = pow(2, fabs(oldValue - newValue) / m_factor); + return (newValue > oldValue ? f : 1.0 / f); +} + +void ScaleSlider::SetPosWithBlockedSignals(double pos) +{ + bool const blocked = signalsBlocked(); + blockSignals(true); + setSliderPosition(my::rounds(pos * m_factor)); + blockSignals(blocked); +} + +void ScaleSlider::SetRange(int low, int up) { setRange(low * m_factor, up * m_factor); } +} // namespace common +} // namespace qt diff --git a/qt/qt_common/scale_slider.hpp b/qt/qt_common/scale_slider.hpp new file mode 100644 index 0000000000..8d58c5a39d --- /dev/null +++ b/qt/qt_common/scale_slider.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +class QToolBar; + +namespace qt +{ +namespace common +{ +class MapWidget; + +class ScaleSlider : public QSlider +{ +public: + ScaleSlider(Qt::Orientation orient, QWidget * parent); + + static void Embed(Qt::Orientation orient, QToolBar & toolBar, MapWidget & mapWidget); + + double GetScaleFactor() const; + void SetPosWithBlockedSignals(double pos); + +private: + void SetRange(int low, int up); + + int m_factor; +}; +} // namespace common +} // namespace qt diff --git a/qt/res/resources.qrc b/qt/res/resources.qrc index f76648f7da..aa357ac750 100644 --- a/qt/res/resources.qrc +++ b/qt/res/resources.qrc @@ -7,8 +7,6 @@ right.png world.png download.png - plus.png - minus.png location-search.png location.png select.png diff --git a/qt/search_panel.cpp b/qt/search_panel.cpp index 9a843ea68c..4a51b27538 100644 --- a/qt/search_panel.cpp +++ b/qt/search_panel.cpp @@ -2,6 +2,7 @@ #include "qt/draw_widget.hpp" #include "map/bookmark_manager.hpp" +#include "map/framework.hpp" #include "map/user_mark_container.hpp" #include "drape/constants.hpp" diff --git a/qt/slider_ctrl.cpp b/qt/slider_ctrl.cpp deleted file mode 100644 index 5605b37a33..0000000000 --- a/qt/slider_ctrl.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "qt/slider_ctrl.hpp" -#include "qt/proxystyle.hpp" - -#include "base/math.hpp" - - -namespace qt -{ - /////////////////////////////////////////////////////////////////////////////////////////////// - // QClickSmoothSlider implementation - /////////////////////////////////////////////////////////////////////////////////////////////// - - QClickSmoothSlider::QClickSmoothSlider(Qt::Orientation orient, QWidget * pParent, int factor) - : base_t(orient, pParent), m_factor(factor) - { - /// This style cause slider to set value exactly to the cursor position (not "page scroll") - /// @todo Do investigate this stuff with Qt5. - class MyProxyStyle : public ProxyStyle - { - public: - MyProxyStyle(QStyle * p) : ProxyStyle(p) {} - - virtual int styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const - { - if (hint == SH_Slider_AbsoluteSetButtons) - return Qt::LeftButton; - else - return ProxyStyle::styleHint(hint, option, widget, returnData); - } - }; - - setStyle(new MyProxyStyle(style())); - } - - QClickSmoothSlider::~QClickSmoothSlider() - { - QStyle * p = style(); - delete p; - } - - void QClickSmoothSlider::SetRange(int low, int up) - { - setRange(low * m_factor, up * m_factor); - } - - /////////////////////////////////////////////////////////////////////////////////////////////// - // QScaleSlider implementation - /////////////////////////////////////////////////////////////////////////////////////////////// - - QScaleSlider::QScaleSlider(Qt::Orientation orient, QWidget * pParent, int factor) - : base_t(orient, pParent, factor) - { - } - - double QScaleSlider::GetScaleFactor() const - { - double const oldV = value(); - double const newV = sliderPosition(); - - if (oldV != newV) - { - double const f = pow(2, fabs(oldV - newV) / m_factor); - return (newV > oldV ? f : 1.0 / f); - } - else return 1.0; - } - - void QScaleSlider::SetPosWithBlockedSignals(double pos) - { - bool const b = signalsBlocked(); - blockSignals(true); - - setSliderPosition(my::rounds(pos * m_factor)); - - blockSignals(b); - } -} diff --git a/qt/slider_ctrl.hpp b/qt/slider_ctrl.hpp deleted file mode 100644 index dba3654fc4..0000000000 --- a/qt/slider_ctrl.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - #include -#else - #include -#endif - -namespace qt -{ - class QClickSmoothSlider : public QSlider - { - typedef QSlider base_t; - - protected: - int m_factor; - - public: - QClickSmoothSlider(Qt::Orientation orient, QWidget * pParent, int factor); - virtual ~QClickSmoothSlider(); - - void SetRange(int low, int up); - }; - - class QScaleSlider : public QClickSmoothSlider - { - typedef QClickSmoothSlider base_t; - - public: - QScaleSlider(Qt::Orientation orient, QWidget * pParent, int factor); - - double GetScaleFactor() const; - void SetPosWithBlockedSignals(double pos); - }; -} diff --git a/search/search_quality/CMakeLists.txt b/search/search_quality/CMakeLists.txt index d02a06a040..e01dc02edf 100644 --- a/search/search_quality/CMakeLists.txt +++ b/search/search_quality/CMakeLists.txt @@ -11,5 +11,6 @@ set(SRC add_library(${PROJECT_NAME} ${SRC}) +add_subdirectory(assessment_tool) add_subdirectory(features_collector_tool) add_subdirectory(search_quality_tool) diff --git a/search/search_quality/assessment_tool/CMakeLists.txt b/search/search_quality/assessment_tool/CMakeLists.txt new file mode 100644 index 0000000000..d7a3c78875 --- /dev/null +++ b/search/search_quality/assessment_tool/CMakeLists.txt @@ -0,0 +1,50 @@ +project(assessment_tool) + +include_directories(${OMIM_ROOT}/3party/gflags/src) +include_directories(${OMIM_ROOT}/3party/glm) + +set(SRC assessment_tool.cc) + +add_executable(${PROJECT_NAME} ${SRC}) + +omim_link_libraries( + ${PROJECT_NAME} + qt_common + map + drape_frontend + routing + search_quality + search + storage + tracking + traffic + indexer + drape + partners_api + platform + editor geometry + coding + base + expat + freetype + fribidi + gflags + jansson + minizip + oauthcpp + opening_hours + openlr + osrm + protobuf + pugixml + sdf_image + stats_client + stb_image + succinct + ${Qt5Widgets_LIBRARIES} + ${LIBZ} +) + +link_opengl(${PROJECT_NAME}) +link_qt5_core(${PROJECT_NAME}) +link_qt5_network(${PROJECT_NAME}) diff --git a/search/search_quality/assessment_tool/assessment_tool.cc b/search/search_quality/assessment_tool/assessment_tool.cc new file mode 100644 index 0000000000..82a4bc7c86 --- /dev/null +++ b/search/search_quality/assessment_tool/assessment_tool.cc @@ -0,0 +1,116 @@ +#include "qt/qt_common/helpers.hpp" +#include "qt/qt_common/map_widget.hpp" +#include "qt/qt_common/scale_slider.hpp" + +#include "map/framework.hpp" + +#include "search/search_quality/helpers.hpp" + +#include "platform/platform.hpp" + +#include "base/logging.hpp" + +#include +#include +#include +#include +#include +#include + +#include "3party/gflags/src/gflags/gflags.h" + +#include + +DEFINE_string(resources_path, "", "Path to resources directory"); +DEFINE_string(data_path, "", "Path to data directory"); + +namespace +{ +class MainWindow : public QMainWindow +{ +public: + MainWindow(Framework & framework) : m_framework(framework) + { + setWindowTitle(tr("Assessment tool")); + InitMenuBar(); + InitMapWidget(); + } + +private: + void InitMenuBar() + { + auto * bar = menuBar(); + + auto * fileMenu = bar->addMenu(tr("&File")); + + { + auto open = make_unique(tr("&Open queries..."), this); + open->setShortcuts(QKeySequence::Open); + open->setStatusTip(tr("Open the file with queries for assessment")); + connect(open.get(), &QAction::triggered, this, &MainWindow::Open); + fileMenu->addAction(open.release()); + } + + fileMenu->addSeparator(); + + { + auto quit = make_unique(tr("&Quit"), this); + quit->setShortcuts(QKeySequence::Quit); + quit->setStatusTip(tr("Exit the tool")); + connect(quit.get(), &QAction::triggered, this, &QWidget::close); + fileMenu->addAction(quit.release()); + } + } + + void InitMapWidget() + { + auto widget = make_unique(m_framework, this); + widget->BindHotkeys(*this); + InitToolBar(*widget); + setCentralWidget(widget.release()); + } + + void InitToolBar(qt::common::MapWidget & widget) + { + auto toolBar = make_unique(this); + toolBar->setOrientation(Qt::Vertical); + toolBar->setIconSize(QSize(32, 32)); + qt::common::ScaleSlider::Embed(Qt::Vertical, *toolBar, widget); + addToolBar(Qt::RightToolBarArea, toolBar.release()); + } + + void Open() + { + auto const file = QFileDialog::getOpenFileName(this, tr("Open queries..."), QString(), + tr("JSON files (*.json)")) + .toStdString(); + if (file.empty()) + return; + // TODO (@y): implement this + } + + Framework & m_framework; +}; +} // namespace + +int main(int argc, char ** argv) +{ + search::ChangeMaxNumberOfOpenFiles(search::kMaxOpenFiles); + + google::SetUsageMessage("Features collector tool."); + google::ParseCommandLineFlags(&argc, &argv, true); + + Platform & platform = GetPlatform(); + if (!FLAGS_resources_path.empty()) + platform.SetResourceDir(FLAGS_resources_path); + if (!FLAGS_data_path.empty()) + platform.SetWritableDirForTests(FLAGS_data_path); + + Q_INIT_RESOURCE(resources_common); + QApplication app(argc, argv); + + Framework framework; + MainWindow window(framework); + window.show(); + return app.exec(); +}