mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-11 00:04:27 -04:00
322 lines
8.2 KiB
C++
322 lines
8.2 KiB
C++
/***************************************************************************
|
|
qgsmapoverviewcanvas.cpp
|
|
Map canvas subclassed for overview
|
|
-------------------
|
|
begin : 09/14/2005
|
|
copyright : (C) 2005 by Martin Dobias
|
|
email : won.der at centrum.sk
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgsmapcanvas.h"
|
|
#include "qgsmaplayer.h"
|
|
#include "qgsproject.h"
|
|
#include "qgsmapoverviewcanvas.h"
|
|
#include "qgsmaprenderersequentialjob.h"
|
|
#include "qgsmaptopixel.h"
|
|
|
|
#include <QPainter>
|
|
#include <QPaintEvent>
|
|
#include <QResizeEvent>
|
|
#include <QMouseEvent>
|
|
#include "qgslogger.h"
|
|
#include <limits>
|
|
|
|
|
|
QgsMapOverviewCanvas::QgsMapOverviewCanvas( QWidget *parent, QgsMapCanvas *mapCanvas )
|
|
: QWidget( parent )
|
|
, mMapCanvas( mapCanvas )
|
|
|
|
{
|
|
setAutoFillBackground( true );
|
|
setObjectName( QStringLiteral( "theOverviewCanvas" ) );
|
|
mPanningWidget = new QgsPanningWidget( this );
|
|
|
|
mSettings.setTransformContext( mMapCanvas->mapSettings().transformContext() );
|
|
mSettings.setFlag( QgsMapSettings::DrawLabeling, false );
|
|
|
|
connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapOverviewCanvas::drawExtentRect );
|
|
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapOverviewCanvas::destinationCrsChanged );
|
|
connect( mMapCanvas, &QgsMapCanvas::transformContextChanged, this, &QgsMapOverviewCanvas::transformContextChanged );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::resizeEvent( QResizeEvent *e )
|
|
{
|
|
mPixmap = QPixmap();
|
|
|
|
mSettings.setOutputSize( e->size() );
|
|
|
|
updateFullExtent();
|
|
|
|
refresh();
|
|
|
|
QWidget::resizeEvent( e );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::showEvent( QShowEvent *e )
|
|
{
|
|
refresh();
|
|
QWidget::showEvent( e );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::paintEvent( QPaintEvent *pe )
|
|
{
|
|
if ( !mPixmap.isNull() )
|
|
{
|
|
QPainter paint( this );
|
|
paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
|
|
}
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::drawExtentRect()
|
|
{
|
|
if ( !mMapCanvas ) return;
|
|
|
|
const QgsRectangle &extent = mMapCanvas->extent();
|
|
|
|
// show only when valid extent is set
|
|
if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
|
|
{
|
|
mPanningWidget->hide();
|
|
return;
|
|
}
|
|
|
|
const QPolygonF &vPoly = mMapCanvas->mapSettings().visiblePolygon();
|
|
const QgsMapToPixel &cXf = mSettings.mapToPixel();
|
|
QVector< QPoint > pts;
|
|
pts.push_back( cXf.transform( QgsPointXY( vPoly[0] ) ).toQPointF().toPoint() );
|
|
pts.push_back( cXf.transform( QgsPointXY( vPoly[1] ) ).toQPointF().toPoint() );
|
|
pts.push_back( cXf.transform( QgsPointXY( vPoly[2] ) ).toQPointF().toPoint() );
|
|
pts.push_back( cXf.transform( QgsPointXY( vPoly[3] ) ).toQPointF().toPoint() );
|
|
mPanningWidget->setPolygon( QPolygon( pts ) );
|
|
mPanningWidget->show(); // show if hidden
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::mousePressEvent( QMouseEvent *e )
|
|
{
|
|
// if (mPanningWidget->isHidden())
|
|
// return;
|
|
|
|
// set offset in panning widget if inside it
|
|
// for better experience with panning :)
|
|
if ( mPanningWidget->geometry().contains( e->pos() ) )
|
|
{
|
|
mPanningCursorOffset = e->pos() - mPanningWidget->pos();
|
|
}
|
|
else
|
|
{
|
|
// use center of the panning widget if outside
|
|
QSize s = mPanningWidget->size();
|
|
mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
|
|
}
|
|
updatePanningWidget( e->pos() );
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::mouseReleaseEvent( QMouseEvent *e )
|
|
{
|
|
// if (mPanningWidget->isHidden())
|
|
// return;
|
|
|
|
if ( e->button() == Qt::LeftButton )
|
|
{
|
|
// set new extent
|
|
const QgsMapToPixel &cXf = mSettings.mapToPixel();
|
|
QRect rect = mPanningWidget->geometry();
|
|
|
|
QgsPointXY center = cXf.toMapCoordinates( rect.center() );
|
|
mMapCanvas->setCenter( center );
|
|
mMapCanvas->refresh();
|
|
}
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::mouseMoveEvent( QMouseEvent *e )
|
|
{
|
|
// move with panning widget if tracking cursor
|
|
if ( ( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
|
|
{
|
|
updatePanningWidget( e->pos() );
|
|
}
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::updatePanningWidget( QPoint pos )
|
|
{
|
|
// if (mPanningWidget->isHidden())
|
|
// return;
|
|
mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::refresh()
|
|
{
|
|
if ( !isVisible() )
|
|
return;
|
|
|
|
updateFullExtent();
|
|
|
|
if ( !mSettings.hasValidSettings() )
|
|
{
|
|
mPixmap = QPixmap();
|
|
update();
|
|
return; // makes no sense to render anything
|
|
}
|
|
|
|
if ( mJob )
|
|
{
|
|
QgsDebugMsg( "oveview - canceling old" );
|
|
mJob->cancel();
|
|
QgsDebugMsg( "oveview - deleting old" );
|
|
delete mJob; // get rid of previous job (if any)
|
|
}
|
|
|
|
QgsDebugMsg( "oveview - starting new" );
|
|
|
|
// TODO: setup overview mode
|
|
mJob = new QgsMapRendererSequentialJob( mSettings );
|
|
connect( mJob, &QgsMapRendererJob::finished, this, &QgsMapOverviewCanvas::mapRenderingFinished );
|
|
mJob->start();
|
|
|
|
setBackgroundColor( mMapCanvas->mapSettings().backgroundColor() );
|
|
|
|
// schedule repaint
|
|
update();
|
|
|
|
// update panning widget
|
|
drawExtentRect();
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::mapRenderingFinished()
|
|
{
|
|
QgsDebugMsg( "overview - finished" );
|
|
mPixmap = QPixmap::fromImage( mJob->renderedImage() );
|
|
|
|
delete mJob;
|
|
mJob = nullptr;
|
|
|
|
// schedule repaint
|
|
update();
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::layerRepaintRequested( bool deferred )
|
|
{
|
|
if ( !deferred )
|
|
refresh();
|
|
}
|
|
|
|
|
|
void QgsMapOverviewCanvas::setBackgroundColor( const QColor &color )
|
|
{
|
|
mSettings.setBackgroundColor( color );
|
|
|
|
// set erase color
|
|
QPalette palette;
|
|
palette.setColor( backgroundRole(), color );
|
|
setPalette( palette );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::setLayers( const QList<QgsMapLayer *> &layers )
|
|
{
|
|
Q_FOREACH ( QgsMapLayer *ml, mSettings.layers() )
|
|
{
|
|
disconnect( ml, &QgsMapLayer::repaintRequested, this, &QgsMapOverviewCanvas::layerRepaintRequested );
|
|
}
|
|
|
|
mSettings.setLayers( layers );
|
|
|
|
Q_FOREACH ( QgsMapLayer *ml, mSettings.layers() )
|
|
{
|
|
connect( ml, &QgsMapLayer::repaintRequested, this, &QgsMapOverviewCanvas::layerRepaintRequested );
|
|
}
|
|
|
|
updateFullExtent();
|
|
|
|
refresh();
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::updateFullExtent()
|
|
{
|
|
QgsRectangle rect;
|
|
if ( mSettings.hasValidSettings() )
|
|
rect = mSettings.fullExtent();
|
|
else
|
|
rect = mMapCanvas->fullExtent();
|
|
|
|
// expand a bit to keep features on margin
|
|
rect.scale( 1.1 );
|
|
|
|
mSettings.setExtent( rect );
|
|
drawExtentRect();
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::destinationCrsChanged()
|
|
{
|
|
mSettings.setDestinationCrs( mMapCanvas->mapSettings().destinationCrs() );
|
|
}
|
|
|
|
void QgsMapOverviewCanvas::transformContextChanged()
|
|
{
|
|
mSettings.setTransformContext( mMapCanvas->mapSettings().transformContext() );
|
|
}
|
|
|
|
QList<QgsMapLayer *> QgsMapOverviewCanvas::layers() const
|
|
{
|
|
return mSettings.layers();
|
|
}
|
|
|
|
|
|
/// @cond PRIVATE
|
|
|
|
QgsPanningWidget::QgsPanningWidget( QWidget *parent )
|
|
: QWidget( parent )
|
|
{
|
|
setObjectName( QStringLiteral( "panningWidget" ) );
|
|
setMinimumSize( 5, 5 );
|
|
setAttribute( Qt::WA_NoSystemBackground );
|
|
}
|
|
|
|
void QgsPanningWidget::setPolygon( const QPolygon &p )
|
|
{
|
|
if ( p == mPoly ) return;
|
|
mPoly = p;
|
|
|
|
//ensure polygon is closed
|
|
if ( mPoly.at( 0 ) != mPoly.at( mPoly.length() - 1 ) )
|
|
mPoly.append( mPoly.at( 0 ) );
|
|
|
|
setGeometry( p.boundingRect() );
|
|
update();
|
|
}
|
|
|
|
void QgsPanningWidget::paintEvent( QPaintEvent *pe )
|
|
{
|
|
Q_UNUSED( pe );
|
|
|
|
QPainter p;
|
|
p.begin( this );
|
|
p.setPen( Qt::red );
|
|
QPolygonF t = mPoly.translated( -mPoly.boundingRect().left(), -mPoly.boundingRect().top() );
|
|
|
|
// drawPolygon causes issues on windows - corners of path may be missing resulting in triangles being drawn
|
|
// instead of rectangles! (Same cause as #13343)
|
|
QPainterPath path;
|
|
path.addPolygon( t );
|
|
p.drawPath( path );
|
|
|
|
p.end();
|
|
}
|
|
|
|
|
|
|
|
///@endcond
|