File indexing completed on 2024-04-14 03:40:31
0001 /*************************************************************************** 0002 * Copyright (C) 2004-2007 by Albert Astals Cid * 0003 * aacid@kde.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "mapwidget.h" 0012 0013 #include <QGraphicsPixmapItem> 0014 #include <QGraphicsRectItem> 0015 #include <QGraphicsScene> 0016 #include <QMouseEvent> 0017 #include <QScrollBar> 0018 0019 #include <KLocalizedString> 0020 #include <math.h> 0021 0022 #include <settings.h> 0023 0024 mapWidget::mapWidget(QWidget *parent) : QGraphicsView(parent) 0025 { 0026 p_mode = None; 0027 p_zoomRect = nullptr; 0028 p_automaticZoom = false; 0029 0030 setCacheMode( CacheBackground ); 0031 p_scene = new QGraphicsScene( this ); 0032 setScene(p_scene); 0033 setViewportUpdateMode(SmartViewportUpdate); 0034 } 0035 0036 void mapWidget::init(const QImage &mapImage) 0037 { 0038 p_originalImage = mapImage; 0039 p_scene->clear(); 0040 resetCachedContent(); 0041 p_scene->addPixmap(QPixmap::fromImage(p_originalImage)); 0042 p_scene->setSceneRect( p_originalImage.rect() ); 0043 0044 // work around bug in QGraphicsView? 0045 QMetaObject::invokeMethod(this, "setAutomaticZoom", Qt::QueuedConnection, Q_ARG(bool, p_automaticZoom)); 0046 } 0047 0048 void mapWidget::setMapMove(bool b) 0049 { 0050 if (b) 0051 p_mode = WantMove; 0052 else if ( p_mode == WantMove || p_mode == Moving ) 0053 p_mode = None; 0054 updateActions(); 0055 } 0056 0057 void mapWidget::setMapZoom(bool b) 0058 { 0059 if (b) 0060 p_mode = WantZoom; 0061 else if ( p_mode == WantZoom || p_mode == Zooming ) 0062 p_mode = None; 0063 updateActions(); 0064 } 0065 0066 void mapWidget::mousePressEvent(QMouseEvent *e) 0067 { 0068 p_initial = mapToScene( e->pos() ); 0069 0070 if (e -> button() == Qt::LeftButton) 0071 { 0072 if ( p_mode == WantZoom ) 0073 { 0074 p_zoomRect = p_scene->addRect( QRectF( p_initial, QSize( 0, 0 ) ) ); 0075 p_mode = Zooming; 0076 updateActions(); 0077 } 0078 else if ( p_mode == WantMove ) 0079 { 0080 p_prev = e->pos(); 0081 setCursor(Qt::SizeAllCursor); 0082 p_mode = Moving; 0083 updateActions(); 0084 } 0085 else 0086 { 0087 QRectF fixed_rect = QRectF(p_originalImage.rect()); 0088 fixed_rect.adjust(0, 0, -1, -1); // Fixing edge case 0089 if ( fixed_rect.contains( p_initial ) ) 0090 { 0091 QRgb rgb = p_originalImage.pixel( int(p_initial.x()), int(p_initial.y()) ); 0092 Q_EMIT clicked( rgb, e->pos(), false ); // not moving 0093 } 0094 } 0095 } 0096 else if (e -> button() == Qt::MiddleButton) 0097 { 0098 p_modeBeforeMidClick = p_mode; 0099 p_mode = WantMove; 0100 updateActions(); 0101 p_prev = e->pos(); 0102 setCursor(Qt::SizeAllCursor); 0103 p_mode = Moving; 0104 updateActions(); 0105 } 0106 else if ( p_mode == WantZoom ) 0107 { 0108 setOriginalImage(); 0109 updateActions(); 0110 } 0111 else e->ignore(); // that makes the event go to mapasker and clear the popup 0112 } 0113 0114 void mapWidget::mouseMoveEvent(QMouseEvent *e) 0115 { 0116 if ( p_mode == Zooming ) 0117 { 0118 QPointF current = mapToScene( e->pos() ); 0119 0120 QRectF r; 0121 r.setTopLeft( p_initial ); 0122 r.setBottomRight( current ); 0123 p_zoomRect->setRect( r.normalized() ); 0124 } 0125 else if ( p_mode == Moving ) 0126 { 0127 QPoint diff = p_prev - e->pos(); 0128 0129 horizontalScrollBar()->setValue( horizontalScrollBar()->value() + diff.x() ); 0130 verticalScrollBar()->setValue( verticalScrollBar()->value() + diff.y() ); 0131 0132 p_prev = e->pos(); 0133 } 0134 else if (e -> buttons() == Qt::LeftButton && kgeographySettings::self() -> tooltipFollowsMouse()) 0135 { 0136 p_initial = mapToScene( e->pos() ); 0137 QRectF fixed_rect = QRectF(p_originalImage.rect()); 0138 fixed_rect.adjust(0, 0, -1, -1); // Fixing edge case 0139 if ( fixed_rect.contains( p_initial ) ) 0140 { 0141 QRgb rgb = p_originalImage.pixel( int(p_initial.x()), int(p_initial.y()) ); 0142 Q_EMIT clicked( rgb, e->pos(), true ); // moving 0143 } 0144 } 0145 } 0146 0147 void mapWidget::mouseReleaseEvent(QMouseEvent *e) 0148 { 0149 if ( p_mode == Zooming ) 0150 { 0151 p_automaticZoom = false; 0152 fitInView( p_zoomRect, Qt::KeepAspectRatio ); 0153 delete p_zoomRect; 0154 p_zoomRect = nullptr; 0155 0156 p_mode = WantZoom; 0157 } 0158 else if ( p_mode == Moving ) 0159 { 0160 unsetCursor(); 0161 if ( e -> button() == Qt::MiddleButton ) 0162 { 0163 p_mode = p_modeBeforeMidClick; 0164 updateActions(); 0165 } 0166 else p_mode = WantMove; 0167 } 0168 } 0169 0170 void mapWidget::resizeEvent(QResizeEvent *) 0171 { 0172 updateZoom(); 0173 updateActions(); 0174 0175 // Another hack to work around buginess in QGraphicsView 0176 if ( transform().isIdentity() ) 0177 { 0178 QMetaObject::invokeMethod(this, "setAutomaticZoom", Qt::QueuedConnection, Q_ARG(bool, p_automaticZoom)); 0179 } 0180 } 0181 0182 void mapWidget::wheelEvent(QWheelEvent *e) 0183 { 0184 if ( e->modifiers() == Qt::NoModifier ) QGraphicsView::wheelEvent(e); 0185 else if ( e->modifiers() == Qt::ShiftModifier ) 0186 { 0187 // Scroll horizontally by swapping x and y for the delta 0188 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0189 QWheelEvent reorientedEvent(e->position(), e->globalPosition(), e->pixelDelta().transposed(), -e->angleDelta().transposed(), e->buttons(), Qt::NoModifier, e->phase(), e->inverted(), e->source(), e->pointingDevice()); 0190 #else 0191 QWheelEvent reorientedEvent(e->position(), e->globalPosition(), e->pixelDelta().transposed(), e->angleDelta().transposed(), e->buttons(), Qt::NoModifier, e->phase(), e->inverted(), e->source()); 0192 #endif 0193 QGraphicsView::wheelEvent(&reorientedEvent); 0194 } 0195 else if ( e->modifiers() == Qt::ControlModifier ) 0196 { 0197 int delta = e->angleDelta().y(); 0198 if ( delta != 0 ) 0199 { 0200 const qreal rescale = pow(2, qreal(delta/120)/2.0); 0201 scale(rescale, rescale); 0202 } 0203 } 0204 } 0205 0206 void mapWidget::setAutomaticZoom(bool automaticZoom) 0207 { 0208 if (!automaticZoom) setOriginalImage(); 0209 else 0210 { 0211 p_automaticZoom = automaticZoom; 0212 updateZoom(); 0213 updateActions(); 0214 } 0215 } 0216 0217 void mapWidget::setOriginalImage() 0218 { 0219 p_automaticZoom = false; 0220 0221 // Possibly bug in QGraphicsView? The view isn't updated properly 0222 // if the transform isn't set to something non-identity first 0223 // Or probably a bug in this code, but this makes it show nicely centered 0224 // in the view if the widget is bigger than the map 0225 setTransform( QTransform( 2, 0, 0, 2, 0, 0 ) ); 0226 resetTransform(); 0227 0228 updateActions(); 0229 } 0230 0231 void mapWidget::updateZoom() 0232 { 0233 if ( !p_automaticZoom ) 0234 return; 0235 fitInView( p_originalImage.rect(), Qt::KeepAspectRatio ); 0236 } 0237 0238 QSize mapWidget::mapSize() const 0239 { 0240 return p_originalImage.size(); 0241 } 0242 0243 void mapWidget::updateActions() 0244 { 0245 // Whether the image is bigger than that viewable 0246 const bool biggerThanView = (p_originalImage.width() * transform().m11() >= width()) || (p_originalImage.height() * transform().m22() >= height()); 0247 0248 Q_EMIT setMoveActionEnabled( !p_automaticZoom && biggerThanView ); 0249 Q_EMIT setMoveActionChecked( !p_automaticZoom && (p_mode == Moving || p_mode == WantMove) && biggerThanView ); 0250 Q_EMIT setZoomActionChecked( p_mode == Zooming || p_mode == WantZoom ); 0251 } 0252 0253 #include "moc_mapwidget.cpp"