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"