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"