File indexing completed on 2024-04-21 03:49:46

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
0005 // SPDX-FileCopyrightText: 2014 Adam Dabrowski <adamdbrw@gmail.com>
0006 //
0007 
0008 #include "MarbleWidgetInputHandler.h"
0009 
0010 #include <QRubberBand>
0011 #include <QToolTip>
0012 #include <QTimer>
0013 #include <QKeyEvent>
0014 
0015 #include "MarbleGlobal.h"
0016 #include "MarbleDebug.h"
0017 #include "MarbleWidget.h"
0018 #include "MarbleMap.h"
0019 #include "ViewportParams.h"
0020 #include "AbstractDataPluginItem.h"
0021 #include "MarbleAbstractPresenter.h"
0022 #include "MarbleWidgetPopupMenu.h"
0023 #include "PopupLayer.h"
0024 #include "RenderPlugin.h"
0025 #include "RoutingLayer.h"
0026 
0027 namespace Marble
0028 {
0029 
0030 class MarbleWidgetInputHandlerPrivate
0031 {
0032     class MarbleWidgetSelectionRubber : public AbstractSelectionRubber
0033     {
0034         public:
0035             explicit MarbleWidgetSelectionRubber(MarbleWidget *widget)
0036                 : m_rubberBand(QRubberBand::Rectangle, widget)
0037             {
0038                 m_rubberBand.hide();
0039             }
0040 
0041             void show() override { m_rubberBand.show(); }
0042             void hide() override { m_rubberBand.hide(); }
0043             bool isVisible() const override { return m_rubberBand.isVisible(); }
0044             const QRect &geometry() const override { return m_rubberBand.geometry(); }
0045             void setGeometry(const QRect &geometry) override { m_rubberBand.setGeometry(geometry); }
0046 
0047         private:
0048             QRubberBand m_rubberBand;
0049     };
0050 
0051     public:
0052         MarbleWidgetInputHandlerPrivate(MarbleWidgetInputHandler *handler, MarbleWidget *widget,
0053                                         MarbleAbstractPresenter *presenter)
0054             : m_inputHandler(handler)
0055             ,m_marbleWidget(widget)
0056             ,m_marblePresenter(presenter)
0057             ,m_selectionRubber(widget)
0058             ,m_debugModeEnabled(false)
0059         {
0060             for(RenderPlugin *renderPlugin: widget->renderPlugins())
0061             {
0062                 if(renderPlugin->isInitialized())
0063                 {
0064                     installPluginEventFilter(renderPlugin);
0065                 }
0066             }
0067             m_marbleWidget->grabGesture(Qt::PinchGesture);
0068         }
0069 
0070         void setCursor(const QCursor &cursor)
0071         {
0072             m_marbleWidget->setCursor(cursor);
0073         }
0074 
0075         bool layersEventFilter(QObject *o, QEvent *e)
0076         {   //FIXME - this should go up in hierarchy to MarbleInputHandler
0077             if (m_marbleWidget->popupLayer()->eventFilter(o, e))
0078             {
0079                 return true;
0080             }
0081 
0082             if (m_marbleWidget->routingLayer()->eventFilter(o, e))
0083             {
0084                 return true;
0085             }
0086 
0087             return false;
0088         }
0089 
0090         void installPluginEventFilter(RenderPlugin *renderPlugin)
0091         {
0092             m_marbleWidget->installEventFilter(renderPlugin);
0093         }
0094 
0095         MarbleWidgetInputHandler *m_inputHandler;
0096         MarbleWidget *m_marbleWidget;
0097         MarbleAbstractPresenter *m_marblePresenter;
0098         MarbleWidgetSelectionRubber m_selectionRubber;
0099         bool m_debugModeEnabled;
0100         bool m_pinchDetected = false;
0101         bool m_panDetected = false;
0102 };
0103 
0104 
0105 void MarbleWidgetInputHandler::setCursor(const QCursor &cursor)
0106 {
0107     d->setCursor(cursor);
0108 }
0109 
0110 bool MarbleWidgetInputHandler::handleKeyPress(QKeyEvent *event)
0111 {
0112     if (d->m_debugModeEnabled) {
0113         if (event->modifiers() == Qt::ControlModifier && d->m_marbleWidget->debugLevelTags()) {
0114             switch(event->key()) {
0115                 case Qt::Key_0:
0116                     d->m_marbleWidget->setLevelToDebug(0);
0117                     break;
0118                 case Qt::Key_1:
0119                     d->m_marbleWidget->setLevelToDebug(1);
0120                     break;
0121                 case Qt::Key_2:
0122                     d->m_marbleWidget->setLevelToDebug(2);
0123                     break;
0124                 case Qt::Key_3:
0125                     d->m_marbleWidget->setLevelToDebug(3);
0126                     break;
0127                 case Qt::Key_4:
0128                     d->m_marbleWidget->setLevelToDebug(4);
0129                     break;
0130                 case Qt::Key_5:
0131                     d->m_marbleWidget->setLevelToDebug(5);
0132                     break;
0133                 case Qt::Key_6:
0134                     d->m_marbleWidget->setLevelToDebug(6);
0135                     break;
0136                 case Qt::Key_7:
0137                     d->m_marbleWidget->setLevelToDebug(7);
0138                     break;
0139                 case Qt::Key_8:
0140                     d->m_marbleWidget->setLevelToDebug(8);
0141                     break;
0142                 case Qt::Key_9:
0143                     d->m_marbleWidget->setLevelToDebug(9);
0144                     break;
0145                 case Qt::Key_Plus:
0146                     d->m_marbleWidget->setLevelToDebug(d->m_marbleWidget->levelToDebug() + 1);
0147                     break;
0148                 case Qt::Key_Minus:
0149                     d->m_marbleWidget->setLevelToDebug(d->m_marbleWidget->levelToDebug() - 1);
0150                     break;
0151             }
0152         } else {
0153             switch(event->key()) {
0154                 case Qt::Key_I:
0155                     MarbleDebug::setEnabled(!MarbleDebug::isEnabled());
0156                     break;
0157                 case Qt::Key_R:
0158                     d->m_marbleWidget->setShowRuntimeTrace(!d->m_marbleWidget->showRuntimeTrace());
0159                     break;
0160                 case Qt::Key_O:
0161                     d->m_marbleWidget->setShowDebugPlacemarks(!d->m_marbleWidget->showDebugPlacemarks());
0162                     break;
0163                 case Qt::Key_P:
0164                     d->m_marbleWidget->setShowDebugPolygons(!d->m_marbleWidget->showDebugPolygons());
0165                     break;
0166                 case Qt::Key_B:
0167                     d->m_marbleWidget->setShowDebugBatchRender(!d->m_marbleWidget->showDebugBatchRender());
0168                     break;
0169                 case Qt::Key_L:
0170                     d->m_marbleWidget->setDebugLevelTags(!d->m_marbleWidget->debugLevelTags());
0171                     break;
0172             }
0173         }
0174     }
0175     return MarbleDefaultInputHandler::handleKeyPress(event);
0176 }
0177 
0178 bool MarbleWidgetInputHandler::handleTouch(QTouchEvent *event)
0179 {
0180     event->accept();
0181 
0182     if (event->touchPoints().count() == 1)
0183     {
0184         QTouchEvent::TouchPoint p = event->touchPoints().at(0);
0185         if (event->type() == QEvent::TouchBegin)
0186         {
0187             d->m_pinchDetected = false;
0188             d->m_panDetected = false;
0189             QMouseEvent press(QMouseEvent::MouseButtonPress, p.pos(),
0190                               Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
0191             handleMouseEvent(&press);
0192         }
0193         else if (event->type() == QEvent::TouchUpdate)
0194         {
0195             if (!d->m_pinchDetected)
0196             {
0197                 d->m_panDetected = true;
0198                 QMouseEvent move(QMouseEvent::MouseMove, p.pos(),
0199                                  Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
0200                 handleMouseEvent(&move);
0201             }
0202         }
0203         else if (event->type() == QEvent::TouchEnd)
0204         {
0205             // avoid triggering mouse clicked signal when we just changed the viewport
0206             if (d->m_pinchDetected || d->m_panDetected)
0207                 blockSignals(true);
0208 
0209             QMouseEvent release(QMouseEvent::MouseButtonRelease, p.pos(),
0210                                 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
0211             handleMouseEvent(&release);
0212 
0213             if (d->m_pinchDetected || d->m_panDetected)
0214             {
0215                 if (d->m_pinchDetected)
0216                     stopInertialEarthRotation();  // ensures we keep the viewport
0217 
0218                 blockSignals(false);
0219             }
0220         }
0221     }
0222     return true;
0223 }
0224 
0225 bool MarbleWidgetInputHandler::handleGesture(QGestureEvent *e)
0226 {
0227     QPinchGesture *pinch = static_cast<QPinchGesture*>(e->gesture(Qt::PinchGesture));
0228     if (pinch && !d->m_panDetected)
0229     {
0230         d->m_pinchDetected = true;
0231         handlePinchGesture(pinch);
0232         return true;
0233     }
0234 
0235     return false;
0236 }
0237 
0238 void MarbleWidgetInputHandler::handlePinchGesture(QPinchGesture *pinch)
0239 {
0240     MarbleAbstractPresenter *marblePresenter = d->m_marblePresenter;
0241 
0242     switch (pinch->state())
0243     {
0244     case Qt::NoGesture:
0245         break;
0246     case Qt::GestureStarted:
0247         marblePresenter->setViewContext(Animation);
0248         break;
0249     case Qt::GestureUpdated:
0250     {
0251         qreal scaleFactor = pinch->scaleFactor();
0252         QPoint center = d->m_marbleWidget->mapFromGlobal(pinch->centerPoint().toPoint());
0253 
0254         if (scaleFactor > 1.0)
0255             scaleFactor = 0.2;
0256         else if (scaleFactor < 1.0)
0257             scaleFactor = -0.2;
0258         else return;  // 1 .. no change
0259 
0260         qreal zoom = marblePresenter->zoom();
0261         bool oldAnim = marblePresenter->animationsEnabled();
0262         qreal newDistance = marblePresenter->distanceFromZoom(zoom + 20 * scaleFactor);
0263         marblePresenter->setAnimationsEnabled(false);
0264         marblePresenter->zoomAt(center, newDistance);
0265         marblePresenter->setAnimationsEnabled(oldAnim);
0266         break;
0267     }
0268     case Qt::GestureFinished:
0269     case Qt::GestureCanceled:
0270         restoreViewContext();
0271         break;
0272     }
0273 }
0274 
0275 AbstractSelectionRubber *MarbleWidgetInputHandler::selectionRubber()
0276 {
0277     return &d->m_selectionRubber;
0278 }
0279 
0280 bool MarbleWidgetInputHandler::layersEventFilter(QObject *o, QEvent *e)
0281 {
0282     return d->layersEventFilter(o, e);
0283 }
0284 
0285 void MarbleWidgetInputHandler::installPluginEventFilter(RenderPlugin *renderPlugin)
0286 {
0287     d->installPluginEventFilter(renderPlugin);
0288 }
0289 
0290 MarbleWidgetInputHandler::MarbleWidgetInputHandler(MarbleAbstractPresenter *marblePresenter, MarbleWidget *widget)
0291     : MarbleDefaultInputHandler(marblePresenter)
0292     ,d(new MarbleWidgetInputHandlerPrivate(this, widget, marblePresenter))
0293 {
0294 }
0295 
0296 void MarbleWidgetInputHandler::setDebugModeEnabled(bool enabled)
0297 {
0298     d->m_debugModeEnabled = enabled;
0299 }
0300 
0301 //FIXME - these should be moved to superclass and popupMenu should be abstracted in MarbleAbstractPresenter
0302 void MarbleWidgetInputHandler::showLmbMenu(int x, int y)
0303 {
0304     if (isMouseButtonPopupEnabled(Qt::LeftButton) && !d->m_pinchDetected && !d->m_panDetected)
0305     {
0306         d->m_marbleWidget->popupMenu()->showLmbMenu(x, y);
0307         toolTipTimer()->stop();
0308     }
0309 }
0310 
0311 void MarbleWidgetInputHandler::showRmbMenu(int x, int y)
0312 {
0313     if (isMouseButtonPopupEnabled(Qt::RightButton))
0314     {
0315         d->m_marbleWidget->popupMenu()->showRmbMenu(x, y);
0316     }
0317 }
0318 
0319 void MarbleWidgetInputHandler::openItemToolTip()
0320 {
0321     if (lastToolTipItem())
0322     {
0323         QToolTip::showText(d->m_marbleWidget->mapToGlobal(toolTipPosition()),
0324                             lastToolTipItem()->toolTip(),
0325                             d->m_marbleWidget,
0326                             lastToolTipItem()->containsRect(toolTipPosition()).toRect());
0327     }
0328 }
0329 
0330 }
0331 
0332 #include "moc_MarbleWidgetInputHandler.cpp"