1 /***************************************************************************
2 qgsmapcanvasdockwidget.cpp
3 --------------------------
4 begin : February 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15 #include "qgsmapcanvasdockwidget.h"
16 #include "qgsmapcanvas.h"
17 #include "qgsexception.h"
18 #include "qgsprojectionselectiondialog.h"
19 #include "qgsscalecombobox.h"
20 #include "qgsdoublespinbox.h"
21 #include "qgssettings.h"
22 #include "qgsmaptoolpan.h"
23 #include "qgsmapthemecollection.h"
24 #include "qgsproject.h"
25 #include "qgsmapthemes.h"
26 #include "qgslayertreeview.h"
27 #include "qgslayertreeviewdefaultactions.h"
28 #include "qgisapp.h"
29 #include "qgsvertexmarker.h"
30 #include "qgsrubberband.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsapplication.h"
33 #include <QMessageBox>
34 #include <QMenu>
35 #include <QToolBar>
36 #include <QToolButton>
37 #include <QRadioButton>
38
39
QgsMapCanvasDockWidget(const QString & name,QWidget * parent)40 QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *parent )
41 : QgsDockWidget( parent )
42 {
43 setupUi( this );
44 setAttribute( Qt::WA_DeleteOnClose );
45
46 mContents->layout()->setContentsMargins( 0, 0, 0, 0 );
47 static_cast< QVBoxLayout * >( mContents->layout() )->setSpacing( 0 );
48
49 setWindowTitle( name );
50 mToolbar->setIconSize( QgisApp::instance()->iconSize( true ) );
51
52 mMapCanvas = new QgsMapCanvas( this );
53 mXyMarker = new QgsVertexMarker( mMapCanvas );
54 mXyMarker->setIconType( QgsVertexMarker::ICON_CIRCLE );
55 mXyMarker->setIconSize( 6 );
56 mXyMarker->setColor( QColor( 30, 30, 30, 225 ) );
57 mXyMarker->setFillColor( QColor( 255, 255, 255, 225 ) );
58
59 mExtentRubberBand = new QgsRubberBand( mMapCanvas, QgsWkbTypes::PolygonGeometry );
60 mExtentRubberBand->setStrokeColor( Qt::red );
61 mExtentRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 225 ) );
62 mExtentRubberBand->setFillColor( Qt::transparent );
63
64 mPanTool = new QgsMapToolPan( mMapCanvas );
65 mMapCanvas->setMapTool( mPanTool );
66
67 mMainWidget->setLayout( new QVBoxLayout() );
68 mMainWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
69
70 mMainWidget->layout()->addWidget( mMapCanvas );
71
72 mMenu = new QMenu();
73 connect( mMenu, &QMenu::aboutToShow, this, &QgsMapCanvasDockWidget::menuAboutToShow );
74
75 mToolbar->addSeparator();
76
77 QToolButton *btnMapThemes = new QToolButton;
78 btnMapThemes->setAutoRaise( true );
79 btnMapThemes->setToolTip( tr( "Set View Theme" ) );
80 btnMapThemes->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ) );
81 btnMapThemes->setPopupMode( QToolButton::InstantPopup );
82 btnMapThemes->setMenu( mMenu );
83 mToolbar->addWidget( btnMapThemes );
84
85 QMenu *settingsMenu = new QMenu();
86 QToolButton *settingsButton = new QToolButton();
87 settingsButton->setAutoRaise( true );
88 settingsButton->setToolTip( tr( "View Settings" ) );
89 settingsButton->setMenu( settingsMenu );
90 settingsButton->setPopupMode( QToolButton::InstantPopup );
91 settingsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOptions.svg" ) ) );
92 mToolbar->addWidget( settingsButton );
93
94 connect( mActionSetCrs, &QAction::triggered, this, &QgsMapCanvasDockWidget::setMapCrs );
95 connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapCanvasDockWidget::mapCrsChanged );
96 connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapCanvasDockWidget::updateExtentRect );
97 connect( mActionZoomFullExtent, &QAction::triggered, mMapCanvas, &QgsMapCanvas::zoomToProjectExtent );
98 connect( mActionZoomToLayers, &QAction::triggered, mMapCanvas, [ = ] { QgisApp::instance()->layerTreeView()->defaultActions()->zoomToLayers( mMapCanvas ); } );
99 connect( mActionZoomToSelected, &QAction::triggered, mMapCanvas, [ = ] { mMapCanvas->zoomToSelected(); } );
100 mapCrsChanged();
101
102 QgsMapSettingsAction *settingsAction = new QgsMapSettingsAction( settingsMenu );
103 settingsMenu->addAction( settingsAction );
104
105 settingsMenu->addSeparator();
106 settingsMenu->addAction( mActionShowAnnotations );
107 settingsMenu->addAction( mActionShowCursor );
108 settingsMenu->addAction( mActionShowExtent );
109 settingsMenu->addAction( mActionShowLabels );
110 settingsMenu->addSeparator();
111 settingsMenu->addAction( mActionSetCrs );
112 settingsMenu->addAction( mActionRename );
113
114 connect( settingsMenu, &QMenu::aboutToShow, this, &QgsMapCanvasDockWidget::settingsMenuAboutToShow );
115
116 connect( mActionRename, &QAction::triggered, this, &QgsMapCanvasDockWidget::renameTriggered );
117 mActionShowAnnotations->setChecked( mMapCanvas->annotationsVisible() );
118 connect( mActionShowAnnotations, &QAction::toggled, this, [ = ]( bool checked ) { mMapCanvas->setAnnotationsVisible( checked ); } );
119 mActionShowCursor->setChecked( true );
120 connect( mActionShowCursor, &QAction::toggled, this, [ = ]( bool checked ) { mXyMarker->setVisible( checked ); } );
121 mActionShowExtent->setChecked( false );
122 connect( mActionShowExtent, &QAction::toggled, this, [ = ]( bool checked ) { mExtentRubberBand->setVisible( checked ); updateExtentRect(); } );
123 mActionShowLabels->setChecked( true );
124 connect( mActionShowLabels, &QAction::toggled, this, &QgsMapCanvasDockWidget::showLabels );
125
126
127 mSyncExtentRadio = settingsAction->syncExtentRadio();
128 mSyncSelectionRadio = settingsAction->syncSelectionRadio();
129 mScaleCombo = settingsAction->scaleCombo();
130 mRotationEdit = settingsAction->rotationSpinBox();
131 mMagnificationEdit = settingsAction->magnifierSpinBox();
132 mSyncScaleCheckBox = settingsAction->syncScaleCheckBox();
133 mScaleFactorWidget = settingsAction->scaleFactorSpinBox();
134
135 connect( mSyncSelectionRadio, &QRadioButton::toggled, this, [ = ]( bool checked )
136 {
137 autoZoomToSelection( checked );
138 if ( checked )
139 {
140 syncSelection();
141 }
142 } );
143
144 connect( mSyncExtentRadio, &QRadioButton::toggled, this, [ = ]( bool checked )
145 {
146 if ( checked )
147 {
148 syncViewCenter( mMainCanvas );
149 }
150 } );
151
152 connect( mScaleCombo, &QgsScaleComboBox::scaleChanged, this, [ = ]( double scale )
153 {
154 if ( !mBlockScaleUpdate )
155 {
156 mBlockScaleUpdate = true;
157 mMapCanvas->zoomScale( scale );
158 mBlockScaleUpdate = false;
159 }
160 } );
161 connect( mMapCanvas, &QgsMapCanvas::scaleChanged, this, [ = ]( double scale )
162 {
163 if ( !mBlockScaleUpdate )
164 {
165 mBlockScaleUpdate = true;
166 mScaleCombo->setScale( scale );
167 mBlockScaleUpdate = false;
168 }
169 } );
170
171 connect( mRotationEdit, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( double value )
172 {
173 if ( !mBlockRotationUpdate )
174 {
175 mBlockRotationUpdate = true;
176 mMapCanvas->setRotation( value );
177 mMapCanvas->refresh();
178 mBlockRotationUpdate = false;
179 }
180 } );
181
182 connect( mMapCanvas, &QgsMapCanvas::rotationChanged, this, [ = ]( double rotation )
183 {
184 if ( !mBlockRotationUpdate )
185 {
186 mBlockRotationUpdate = true;
187 mRotationEdit->setValue( rotation );
188 mBlockRotationUpdate = false;
189 }
190 } );
191
192 connect( mMagnificationEdit, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( double value )
193 {
194 if ( !mBlockMagnificationUpdate )
195 {
196 mBlockMagnificationUpdate = true;
197 mMapCanvas->setMagnificationFactor( value / 100 );
198 mMapCanvas->refresh();
199 mBlockMagnificationUpdate = false;
200 }
201 } );
202
203 connect( mMapCanvas, &QgsMapCanvas::magnificationChanged, this, [ = ]( double factor )
204 {
205 if ( !mBlockMagnificationUpdate )
206 {
207 mBlockMagnificationUpdate = true;
208 mMagnificationEdit->setValue( factor * 100 );
209 mBlockMagnificationUpdate = false;
210 }
211 } );
212
213 connect( mScaleFactorWidget, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsMapCanvasDockWidget::mapScaleChanged );
214 connect( mSyncScaleCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
215 {
216 if ( checked )
217 mapScaleChanged();
218 }
219 );
220
221 mResizeTimer.setSingleShot( true );
222 connect( &mResizeTimer, &QTimer::timeout, this, [ = ]
223 {
224 mBlockExtentSync = false;
225 if ( mSyncExtentRadio->isChecked() )
226 syncViewCenter( mMainCanvas );
227 } );
228
229 connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeRenamed, this, &QgsMapCanvasDockWidget::currentMapThemeRenamed );
230 }
231
setMainCanvas(QgsMapCanvas * canvas)232 void QgsMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
233 {
234 if ( mMainCanvas )
235 {
236 disconnect( mMainCanvas, &QgsMapCanvas::xyCoordinates, this, &QgsMapCanvasDockWidget::syncMarker );
237 disconnect( mMainCanvas, &QgsMapCanvas::scaleChanged, this, &QgsMapCanvasDockWidget::mapScaleChanged );
238 disconnect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged );
239 disconnect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::updateExtentRect );
240 disconnect( mMainCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapCanvasDockWidget::updateExtentRect );
241 }
242
243 mMainCanvas = canvas;
244 connect( mMainCanvas, &QgsMapCanvas::xyCoordinates, this, &QgsMapCanvasDockWidget::syncMarker );
245 connect( mMainCanvas, &QgsMapCanvas::scaleChanged, this, &QgsMapCanvasDockWidget::mapScaleChanged );
246 connect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged );
247 connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged, Qt::UniqueConnection );
248 connect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::updateExtentRect );
249 connect( mMainCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapCanvasDockWidget::updateExtentRect );
250 updateExtentRect();
251 }
252
mapCanvas()253 QgsMapCanvas *QgsMapCanvasDockWidget::mapCanvas()
254 {
255 return mMapCanvas;
256 }
257
setViewCenterSynchronized(bool enabled)258 void QgsMapCanvasDockWidget::setViewCenterSynchronized( bool enabled )
259 {
260 mSyncExtentRadio->setChecked( enabled );
261 }
262
isViewCenterSynchronized() const263 bool QgsMapCanvasDockWidget::isViewCenterSynchronized() const
264 {
265 return mSyncExtentRadio->isChecked();
266 }
267
isAutoZoomToSelected() const268 bool QgsMapCanvasDockWidget::isAutoZoomToSelected() const
269 {
270 return mSyncSelectionRadio->isChecked();
271 }
272
setAutoZoomToSelected(bool autoZoom)273 void QgsMapCanvasDockWidget::setAutoZoomToSelected( bool autoZoom )
274 {
275 mSyncSelectionRadio->setChecked( autoZoom );
276 }
277
setCursorMarkerVisible(bool visible)278 void QgsMapCanvasDockWidget::setCursorMarkerVisible( bool visible )
279 {
280 mActionShowCursor->setChecked( visible );
281 }
282
isCursorMarkerVisible() const283 bool QgsMapCanvasDockWidget::isCursorMarkerVisible() const
284 {
285 return mXyMarker->isVisible();
286 }
287
setMainCanvasExtentVisible(bool visible)288 void QgsMapCanvasDockWidget::setMainCanvasExtentVisible( bool visible )
289 {
290 mActionShowExtent->setChecked( visible );
291 }
292
isMainCanvasExtentVisible() const293 bool QgsMapCanvasDockWidget::isMainCanvasExtentVisible() const
294 {
295 return mExtentRubberBand->isVisible();
296 }
297
setScaleFactor(double factor)298 void QgsMapCanvasDockWidget::setScaleFactor( double factor )
299 {
300 mScaleFactorWidget->setValue( factor );
301 }
302
setViewScaleSynchronized(bool enabled)303 void QgsMapCanvasDockWidget::setViewScaleSynchronized( bool enabled )
304 {
305 mSyncScaleCheckBox->setChecked( enabled );
306 }
307
isViewScaleSynchronized() const308 bool QgsMapCanvasDockWidget::isViewScaleSynchronized() const
309 {
310 return mSyncScaleCheckBox->isChecked();
311 }
312
setLabelsVisible(bool enabled)313 void QgsMapCanvasDockWidget::setLabelsVisible( bool enabled )
314 {
315 mActionShowLabels->setChecked( enabled );
316 }
317
labelsVisible() const318 bool QgsMapCanvasDockWidget::labelsVisible() const
319 {
320 return mActionShowLabels->isChecked();
321 }
322
scaleFactor() const323 double QgsMapCanvasDockWidget::scaleFactor() const
324 {
325 return mScaleFactorWidget->value();
326 }
327
resizeEvent(QResizeEvent *)328 void QgsMapCanvasDockWidget::resizeEvent( QResizeEvent * )
329 {
330 mBlockExtentSync = true;
331 mResizeTimer.start( 500 );
332 }
333
setMapCrs()334 void QgsMapCanvasDockWidget::setMapCrs()
335 {
336 QgsProjectionSelectionDialog dlg;
337 dlg.setShowNoProjection( true );
338 dlg.setCrs( mMapCanvas->mapSettings().destinationCrs() );
339
340 if ( dlg.exec() )
341 {
342 mMapCanvas->setDestinationCrs( dlg.crs() );
343 }
344 }
345
syncViewCenter(QgsMapCanvas * sourceCanvas)346 void QgsMapCanvasDockWidget::syncViewCenter( QgsMapCanvas *sourceCanvas )
347 {
348 // avoid infinite recursion
349 mBlockExtentSync = true;
350
351 QgsMapCanvas *destCanvas = sourceCanvas == mMapCanvas ? mMainCanvas : mMapCanvas;
352
353 // reproject extent
354 const QgsCoordinateTransform ct( sourceCanvas->mapSettings().destinationCrs(),
355 destCanvas->mapSettings().destinationCrs(), QgsProject::instance() );
356 try
357 {
358 destCanvas->setCenter( ct.transform( sourceCanvas->center() ) );
359 }
360 catch ( QgsCsException & )
361 {
362 destCanvas->setCenter( sourceCanvas->center() );
363 }
364 destCanvas->refresh();
365
366 mBlockExtentSync = false;
367 }
368
syncSelection()369 void QgsMapCanvasDockWidget::syncSelection()
370 {
371 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mMapCanvas->currentLayer() );
372
373 if ( !layer )
374 return;
375
376 mMapCanvas->zoomToSelected( layer );
377 }
378
mapExtentChanged()379 void QgsMapCanvasDockWidget::mapExtentChanged()
380 {
381 if ( mBlockExtentSync )
382 return;
383
384 QgsMapCanvas *sourceCanvas = qobject_cast< QgsMapCanvas * >( sender() );
385 if ( !sourceCanvas )
386 return;
387
388 if ( sourceCanvas == mMapCanvas && mSyncScaleCheckBox->isChecked() )
389 {
390 const double newScaleFactor = mMainCanvas->scale() / mMapCanvas->scale();
391 mScaleFactorWidget->setValue( newScaleFactor );
392 }
393
394 if ( mSyncExtentRadio->isChecked() )
395 syncViewCenter( sourceCanvas );
396 }
397
mapCrsChanged()398 void QgsMapCanvasDockWidget::mapCrsChanged()
399 {
400 mActionSetCrs->setText( tr( "Change Map CRS (%1)…" ).arg( mMapCanvas->mapSettings().destinationCrs().isValid() ?
401 mMapCanvas->mapSettings().destinationCrs().authid() :
402 tr( "No projection" ) ) );
403 }
404
menuAboutToShow()405 void QgsMapCanvasDockWidget::menuAboutToShow()
406 {
407 qDeleteAll( mMenuPresetActions );
408 mMenuPresetActions.clear();
409
410 const QString currentTheme = mMapCanvas->theme();
411
412 QAction *actionFollowMain = new QAction( tr( "(none)" ), mMenu );
413 actionFollowMain->setCheckable( true );
414 if ( currentTheme.isEmpty() || !QgsProject::instance()->mapThemeCollection()->hasMapTheme( currentTheme ) )
415 {
416 actionFollowMain->setChecked( true );
417 }
418 connect( actionFollowMain, &QAction::triggered, this, [ = ]
419 {
420 mMapCanvas->setTheme( QString() );
421 mMapCanvas->refresh();
422 } );
423 mMenuPresetActions.append( actionFollowMain );
424
425 const auto constMapThemes = QgsProject::instance()->mapThemeCollection()->mapThemes();
426 for ( const QString &grpName : constMapThemes )
427 {
428 QAction *a = new QAction( grpName, mMenu );
429 a->setCheckable( true );
430 if ( grpName == currentTheme )
431 {
432 a->setChecked( true );
433 }
434 connect( a, &QAction::triggered, this, [a, this]
435 {
436 mMapCanvas->setTheme( a->text() );
437 mMapCanvas->refresh();
438 } );
439 mMenuPresetActions.append( a );
440 }
441 mMenu->addActions( mMenuPresetActions );
442 }
443
currentMapThemeRenamed(const QString & theme,const QString & newTheme)444 void QgsMapCanvasDockWidget::currentMapThemeRenamed( const QString &theme, const QString &newTheme )
445 {
446 if ( theme == mMapCanvas->theme() )
447 {
448 mMapCanvas->setTheme( newTheme );
449 }
450 }
451
settingsMenuAboutToShow()452 void QgsMapCanvasDockWidget::settingsMenuAboutToShow()
453 {
454 whileBlocking( mActionShowAnnotations )->setChecked( mMapCanvas->annotationsVisible() );
455 }
456
syncMarker(const QgsPointXY & p)457 void QgsMapCanvasDockWidget::syncMarker( const QgsPointXY &p )
458 {
459 if ( !mXyMarker->isVisible() )
460 return;
461
462 // reproject point
463 const QgsCoordinateTransform ct( mMainCanvas->mapSettings().destinationCrs(),
464 mMapCanvas->mapSettings().destinationCrs(), QgsProject::instance() );
465 QgsPointXY t = p;
466 try
467 {
468 t = ct.transform( p );
469 }
470 catch ( QgsCsException & )
471 {}
472
473 mXyMarker->setCenter( t );
474 }
475
mapScaleChanged()476 void QgsMapCanvasDockWidget::mapScaleChanged()
477 {
478 if ( !mSyncScaleCheckBox->isChecked() )
479 return;
480
481 const double newScale = mMainCanvas->scale() / mScaleFactorWidget->value();
482 const bool prev = mBlockExtentSync;
483 mBlockExtentSync = true;
484 mMapCanvas->zoomScale( newScale );
485 mBlockExtentSync = prev;
486 }
487
updateExtentRect()488 void QgsMapCanvasDockWidget::updateExtentRect()
489 {
490 if ( !mExtentRubberBand->isVisible() )
491 return;
492
493 QPolygonF mainCanvasPoly = mMainCanvas->mapSettings().visiblePolygon();
494 // close polygon
495 mainCanvasPoly << mainCanvasPoly.at( 0 );
496 QgsGeometry g = QgsGeometry::fromQPolygonF( mainCanvasPoly );
497 if ( mMainCanvas->mapSettings().destinationCrs() !=
498 mMapCanvas->mapSettings().destinationCrs() )
499 {
500 // reproject extent
501 const QgsCoordinateTransform ct( mMainCanvas->mapSettings().destinationCrs(),
502 mMapCanvas->mapSettings().destinationCrs(), QgsProject::instance() );
503 g = g.densifyByCount( 5 );
504 try
505 {
506 g.transform( ct );
507 }
508 catch ( QgsCsException & )
509 {
510 }
511 }
512 mExtentRubberBand->setToGeometry( g, nullptr );
513 }
514
showLabels(bool show)515 void QgsMapCanvasDockWidget::showLabels( bool show )
516 {
517 Qgis::MapSettingsFlags flags = mMapCanvas->mapSettings().flags();
518 if ( show )
519 flags = flags | Qgis::MapSettingsFlag::DrawLabeling;
520 else
521 flags = flags & ~( static_cast< int >( Qgis::MapSettingsFlag::DrawLabeling ) );
522 mMapCanvas->setMapSettingsFlags( flags );
523 }
524
autoZoomToSelection(bool autoZoom)525 void QgsMapCanvasDockWidget::autoZoomToSelection( bool autoZoom )
526 {
527 if ( autoZoom )
528 connect( mMapCanvas, &QgsMapCanvas::selectionChanged, mMapCanvas, qOverload<QgsVectorLayer *>( &QgsMapCanvas::zoomToSelected ) );
529 else
530 disconnect( mMapCanvas, &QgsMapCanvas::selectionChanged, mMapCanvas, qOverload<QgsVectorLayer *>( &QgsMapCanvas::zoomToSelected ) );
531 }
532
QgsMapSettingsAction(QWidget * parent)533 QgsMapSettingsAction::QgsMapSettingsAction( QWidget *parent )
534 : QWidgetAction( parent )
535 {
536 QGridLayout *gLayout = new QGridLayout();
537 gLayout->setContentsMargins( 3, 2, 3, 2 );
538
539 mSyncExtentRadio = new QRadioButton( tr( "Synchronize View Center with Main Map" ) );
540 gLayout->addWidget( mSyncExtentRadio, 0, 0, 1, 2 );
541
542 mSyncSelectionRadio = new QRadioButton( tr( "Synchronize View to Selection" ) );
543 gLayout->addWidget( mSyncSelectionRadio, 1, 0, 1, 2 );
544
545 QLabel *label = new QLabel( tr( "Scale" ) );
546 gLayout->addWidget( label, 2, 0 );
547
548 mScaleCombo = new QgsScaleComboBox();
549 gLayout->addWidget( mScaleCombo, 2, 1 );
550
551 mRotationWidget = new QgsDoubleSpinBox();
552 mRotationWidget->setClearValue( 0.0 );
553 mRotationWidget->setKeyboardTracking( false );
554 mRotationWidget->setMaximumWidth( 120 );
555 mRotationWidget->setDecimals( 1 );
556 mRotationWidget->setRange( -180.0, 180.0 );
557 mRotationWidget->setWrapping( true );
558 mRotationWidget->setSingleStep( 5.0 );
559 mRotationWidget->setSuffix( tr( " °" ) );
560 mRotationWidget->setToolTip( tr( "Current clockwise map rotation in degrees" ) );
561
562 label = new QLabel( tr( "Rotation" ) );
563 gLayout->addWidget( label, 3, 0 );
564 gLayout->addWidget( mRotationWidget, 3, 1 );
565
566 const QgsSettings settings;
567 const int minimumFactor = 100 * QgsGuiUtils::CANVAS_MAGNIFICATION_MIN;
568 const int maximumFactor = 100 * QgsGuiUtils::CANVAS_MAGNIFICATION_MAX;
569 const int defaultFactor = 100 * settings.value( QStringLiteral( "/qgis/magnifier_factor_default" ), 1.0 ).toDouble();
570
571 mMagnifierWidget = new QgsDoubleSpinBox();
572 mMagnifierWidget->setSuffix( QStringLiteral( "%" ) );
573 mMagnifierWidget->setKeyboardTracking( false );
574 mMagnifierWidget->setDecimals( 0 );
575 mMagnifierWidget->setRange( minimumFactor, maximumFactor );
576 mMagnifierWidget->setWrapping( false );
577 mMagnifierWidget->setSingleStep( 50 );
578 mMagnifierWidget->setToolTip( tr( "Magnifier level" ) );
579 mMagnifierWidget->setClearValueMode( QgsDoubleSpinBox::CustomValue );
580 mMagnifierWidget->setClearValue( defaultFactor );
581 mMagnifierWidget->setValue( defaultFactor );
582
583 label = new QLabel( tr( "Magnification" ) );
584 gLayout->addWidget( label, 4, 0 );
585 gLayout->addWidget( mMagnifierWidget, 4, 1 );
586
587 mSyncScaleCheckBox = new QCheckBox( tr( "Synchronize scale" ) );
588 gLayout->addWidget( mSyncScaleCheckBox, 5, 0, 1, 2 );
589
590 mScaleFactorWidget = new QgsDoubleSpinBox();
591 mScaleFactorWidget->setSuffix( tr( "×" ) );
592 mScaleFactorWidget->setDecimals( 2 );
593 mScaleFactorWidget->setRange( 0.01, 100000 );
594 mScaleFactorWidget->setWrapping( false );
595 mScaleFactorWidget->setSingleStep( 0.1 );
596 mScaleFactorWidget->setToolTip( tr( "Multiplication factor for main canvas scale to view scale" ) );
597 mScaleFactorWidget->setClearValueMode( QgsDoubleSpinBox::CustomValue );
598 mScaleFactorWidget->setClearValue( 1.0 );
599 mScaleFactorWidget->setValue( 1.0 );
600 mScaleFactorWidget->setEnabled( false );
601
602 connect( mSyncScaleCheckBox, &QCheckBox::toggled, mScaleFactorWidget, &QgsDoubleSpinBox::setEnabled );
603
604 label = new QLabel( tr( "Scale Factor" ) );
605 gLayout->addWidget( label, 6, 0 );
606 gLayout->addWidget( mScaleFactorWidget, 6, 1 );
607
608 QWidget *w = new QWidget();
609 w->setLayout( gLayout );
610 setDefaultWidget( w );
611 }
612