QGIS API Documentation 4.3.0-Master (8c22baaae17)
Loading...
Searching...
No Matches
qgsrendererrasterpropertieswidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrendererrasterpropertieswidget.cpp
3 ---------------------
4 begin : May 2016
5 copyright : (C) 2016 by Nathan Woodrow
6 email : woodrow dot nathan 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 ***************************************************************************/
16
17#include "qgis.h"
18#include "qgsapplication.h"
22#include "qgsmapcanvas.h"
26#include "qgsproject.h"
27#include "qgsprojectutils.h"
29#include "qgsrasterlayer.h"
36
37#include <QString>
38
39#include "moc_qgsrendererrasterpropertieswidget.cpp"
40
41using namespace Qt::StringLiterals;
42
43void QgsRendererRasterPropertiesWidget::initRendererWidgetFunctions()
44{
45 static bool sInitialized = false;
46 if ( sInitialized )
47 return;
48
56
57 sInitialized = true;
58}
59
61 : QgsMapLayerConfigWidget( layer, canvas, parent )
62 , mRasterLayer( qobject_cast<QgsRasterLayer *>( layer ) )
63{
64 if ( !mRasterLayer )
65 return;
66
67 setupUi( this );
68 connect( mResetColorRenderingBtn, &QToolButton::clicked, this, &QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked );
69
70 initRendererWidgetFunctions();
71
72 mResamplingUtils.initWidgets( mRasterLayer, mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox, mMaximumOversamplingSpinBox, mCbEarlyResampling );
73
74 connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::rendererChanged );
75
76 connect( mSliderBrightness, &QAbstractSlider::valueChanged, mBrightnessSpinBox, &QSpinBox::setValue );
77 connect( mBrightnessSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), mSliderBrightness, &QAbstractSlider::setValue );
78 mBrightnessSpinBox->setClearValue( 0 );
79
80 connect( mSliderContrast, &QAbstractSlider::valueChanged, mContrastSpinBox, &QSpinBox::setValue );
81 connect( mContrastSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), mSliderContrast, &QAbstractSlider::setValue );
82 mContrastSpinBox->setClearValue( 0 );
83
84 connect( mSliderGamma, &QAbstractSlider::valueChanged, this, &QgsRendererRasterPropertiesWidget::updateGammaSpinBox );
85 connect( mGammaSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRendererRasterPropertiesWidget::updateGammaSlider );
86 mGammaSpinBox->setClearValue( 1.0 );
87
88 // Connect saturation slider and spin box
89 connect( sliderSaturation, &QAbstractSlider::valueChanged, spinBoxSaturation, &QSpinBox::setValue );
90 connect( spinBoxSaturation, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), sliderSaturation, &QAbstractSlider::setValue );
91 spinBoxSaturation->setClearValue( 0 );
92
93 // Connect colorize strength slider and spin box
94 connect( sliderColorizeStrength, &QAbstractSlider::valueChanged, spinColorizeStrength, &QSpinBox::setValue );
95 connect( spinColorizeStrength, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), sliderColorizeStrength, &QAbstractSlider::setValue );
96 spinColorizeStrength->setClearValue( 100 );
97
98 // enable or disable saturation slider and spin box depending on grayscale combo choice
99 connect( comboGrayscale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::toggleSaturationControls );
100
101 // enable or disable colorize colorbutton with colorize checkbox
102 connect( mColorizeCheck, &QAbstractButton::toggled, this, &QgsRendererRasterPropertiesWidget::toggleColorizeControls );
103
104 // Just connect the spin boxes because the sliders update the spinners
105 connect( mBrightnessSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
106 connect( mContrastSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
107 connect( mGammaSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
108 connect( spinBoxSaturation, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
109 connect( spinColorizeStrength, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
110 connect( btnColorizeColor, &QgsColorButton::colorChanged, this, &QgsPanelWidget::changed );
111 connect( mInvertColorsCheck, &QAbstractButton::toggled, this, &QgsPanelWidget::changed );
112
113 connect( mBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::changed );
114 connect( mZoomedInResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::changed );
115 connect( mZoomedOutResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::changed );
116 connect( mMaximumOversamplingSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::changed );
117 connect( mCbEarlyResampling, &QAbstractButton::toggled, this, &QgsPanelWidget::changed );
118
119 // finally sync to the layer - even though some actions may emit widgetChanged signal,
120 // this is not a problem - nobody is listening to our signals yet
121 syncToLayer( mRasterLayer );
122
123 connect( mRasterLayer, &QgsMapLayer::styleChanged, this, &QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged );
124}
125
130
132{
133 const QString rendererName = cboRenderers->currentData().toString();
134 setRendererWidget( rendererName );
135 emit changed();
136}
137
139{
140 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
141 {
142 brightnessFilter->setBrightness( mSliderBrightness->value() );
143 brightnessFilter->setContrast( mSliderContrast->value() );
144 brightnessFilter->setGamma( mGammaSpinBox->value() );
145 }
146
147 if ( QgsRasterRendererWidget *rendererWidget = dynamic_cast<QgsRasterRendererWidget *>( stackedWidget->currentWidget() ) )
148 {
149 rendererWidget->doComputations();
150
151 std::unique_ptr< QgsRasterRenderer > newRenderer( rendererWidget->renderer() );
152 if ( newRenderer )
153 {
154 // there are transparency related data stored in renderer instances, but they
155 // are not configured in the widget, so we need to copy them over from existing renderer
156 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
157 newRenderer->copyCommonProperties( oldRenderer, false );
158 mRasterLayer->setRenderer( newRenderer.release() );
159 }
160 }
161
162 // Hue and saturation controls
163 if ( QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
164 {
165 hueSaturationFilter->setSaturation( sliderSaturation->value() );
166 hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
167 hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
168 hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
169 hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
170 hueSaturationFilter->setInvertColors( mInvertColorsCheck->isChecked() );
171 }
172
173 mResamplingUtils.refreshLayerFromWidgets();
174
175 mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
176}
177
179{
180 mRasterLayer = layer;
181
182 cboRenderers->blockSignals( true );
183 cboRenderers->clear();
185 const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
186 for ( const QString &name : constRenderersList )
187 {
188 if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
189 {
190 if ( ( mRasterLayer->rasterType() != Qgis::RasterLayerType::SingleBandColorData && entry.name != "singlebandcolordata"_L1 )
191 || ( mRasterLayer->rasterType() == Qgis::RasterLayerType::SingleBandColorData && entry.name == "singlebandcolordata"_L1 ) )
192 {
193 cboRenderers->addItem( entry.icon(), entry.visibleName, entry.name );
194 }
195 }
196 }
197 cboRenderers->setCurrentIndex( -1 );
198 cboRenderers->blockSignals( false );
199
200 if ( QgsRasterRenderer *renderer = mRasterLayer->renderer() )
201 {
202 setRendererWidget( renderer->type() );
203 }
204
205 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
206 {
207 mSliderBrightness->setValue( brightnessFilter->brightness() );
208 mSliderContrast->setValue( brightnessFilter->contrast() );
209 mGammaSpinBox->setValue( brightnessFilter->gamma() );
210 }
211
212 btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
213 btnColorizeColor->setContext( u"symbology"_s );
214
215 // Hue and saturation color control
216 //set hue and saturation controls to current values
217 if ( const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
218 {
219 sliderSaturation->setValue( hueSaturationFilter->saturation() );
220 comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
221
222 // Set initial state of saturation controls based on grayscale mode choice
223 toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
224
225 // Set initial state of colorize controls
226 mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
227 btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
228 toggleColorizeControls( hueSaturationFilter->colorizeOn() );
229 sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
230
231 mInvertColorsCheck->setChecked( hueSaturationFilter->invertColors() );
232 }
233
234 //blend mode
235 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mRasterLayer ) );
236 mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
237
238 //set combo boxes to current resampling types
239 mResamplingUtils.refreshWidgetsFromLayer();
240}
241
242void QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked()
243{
244 mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
245 mSliderBrightness->setValue( 0 );
246 mSliderContrast->setValue( 0 );
247 mGammaSpinBox->setValue( 1.0 );
248 sliderSaturation->setValue( 0 );
249 comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
250 mColorizeCheck->setChecked( false );
251 sliderColorizeStrength->setValue( 100 );
252 mInvertColorsCheck->setChecked( false );
253}
254
255void QgsRendererRasterPropertiesWidget::toggleSaturationControls( int grayscaleMode )
256{
257 // Enable or disable saturation controls based on choice of grayscale mode
258 if ( grayscaleMode == 0 )
259 {
260 sliderSaturation->setEnabled( true );
261 spinBoxSaturation->setEnabled( true );
262 }
263 else
264 {
265 sliderSaturation->setEnabled( false );
266 spinBoxSaturation->setEnabled( false );
267 }
268 emit changed();
269}
270
271void QgsRendererRasterPropertiesWidget::toggleColorizeControls( bool colorizeEnabled )
272{
273 // Enable or disable colorize controls based on checkbox
274 btnColorizeColor->setEnabled( colorizeEnabled );
275 sliderColorizeStrength->setEnabled( colorizeEnabled );
276 spinColorizeStrength->setEnabled( colorizeEnabled );
277 emit changed();
278}
279
280void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
281{
282 QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
283 QgsRasterRendererWidget *oldWidget = mRendererWidget;
284
285 int alphaBand = -1;
286 double opacity = 1;
287 QColor nodataColor;
288 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
289 {
290 // Retain alpha band and opacity when switching renderer
291 alphaBand = oldRenderer->alphaBand();
292 opacity = oldRenderer->opacity();
293 nodataColor = oldRenderer->nodataColor();
294 }
295
296 QgsRasterRendererRegistryEntry rendererEntry;
297 if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
298 {
299 if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
300 {
301 QgsDebugMsgLevel( u"renderer has widgetCreateFunction"_s, 3 );
302 // Current canvas extent (used to calc min/max) in layer CRS
303 const QgsRectangle myExtent = QgsCoordinateTransform::isTransformationPossible( mRasterLayer->crs(), mMapCanvas->mapSettings().destinationCrs() )
304 ? mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() )
305 : mRasterLayer->extent();
306 if ( oldWidget )
307 {
308 std::unique_ptr<QgsRasterRenderer> oldRenderer( oldWidget->renderer() );
309 if ( !oldRenderer || oldRenderer->type() != rendererName )
310 {
311 if ( rendererName == "singlebandgray"_L1 )
312 {
313 whileBlocking( mRasterLayer )
314 ->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::SingleBandGray, mRasterLayer->dataProvider() ).release() );
315 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
316 }
317 else if ( rendererName == "multibandcolor"_L1 )
318 {
319 whileBlocking( mRasterLayer )
320 ->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::MultiBandColor, mRasterLayer->dataProvider() ).release() );
321 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
322 }
323 }
324 }
325 mRasterLayer->renderer()->setAlphaBand( alphaBand );
326 mRasterLayer->renderer()->setOpacity( opacity );
327 mRasterLayer->renderer()->setNodataColor( nodataColor );
328 mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
329 mRendererWidget->setMapCanvas( mMapCanvas );
330 connect( mRendererWidget, &QgsRasterRendererWidget::widgetChanged, this, &QgsPanelWidget::changed );
331 stackedWidget->addWidget( mRendererWidget );
332 stackedWidget->setCurrentWidget( mRendererWidget );
333#if 0
334 if ( oldWidget )
335 {
336 // Compare used bands in new and old renderer and reset transparency dialog if different
337 std::unique_ptr< QgsRasterRenderer > oldRenderer( oldWidget->renderer() );
338 std::unique_ptr< QgsRasterRenderer > newRenderer( mRendererWidget->renderer() );
339 QList<int> oldBands = oldRenderer->usesBands();
340 QList<int> newBands = newRenderer->usesBands();
341
342 if ( oldBands != newBands )
343 {
344 populateTransparencyTable( newRenderer );
345 }
346 }
347#endif
348 }
349 }
350
351 if ( mRendererWidget != oldWidget )
352 delete oldWidget;
353
354 const int widgetIndex = cboRenderers->findData( rendererName );
355 if ( widgetIndex != -1 )
356 {
357 whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
358 }
359}
360
361void QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged()
362{
363 if ( mRendererWidget )
364 {
365 QgsRasterRenderer *renderer = mRasterLayer->renderer();
366 if ( QgsMultiBandColorRenderer *mbcr = dynamic_cast<QgsMultiBandColorRenderer *>( renderer ) )
367 {
368 const QgsContrastEnhancement *redCe = mbcr->redContrastEnhancement();
369 if ( redCe )
370 {
371 mRendererWidget->setMin( QLocale().toString( redCe->minimumValue() ), 0 );
372 mRendererWidget->setMax( QLocale().toString( redCe->maximumValue() ), 0 );
373 }
374 const QgsContrastEnhancement *greenCe = mbcr->greenContrastEnhancement();
375 if ( greenCe )
376 {
377 mRendererWidget->setMin( QLocale().toString( greenCe->minimumValue() ), 1 );
378 mRendererWidget->setMax( QLocale().toString( greenCe->maximumValue() ), 1 );
379 }
380 const QgsContrastEnhancement *blueCe = mbcr->blueContrastEnhancement();
381 if ( blueCe )
382 {
383 mRendererWidget->setMin( QLocale().toString( blueCe->minimumValue() ), 2 );
384 mRendererWidget->setMax( QLocale().toString( blueCe->maximumValue() ), 2 );
385 }
386 }
387 else if ( QgsSingleBandGrayRenderer *sbgr = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer ) )
388 {
389 const QgsContrastEnhancement *ce = sbgr->contrastEnhancement();
390 if ( ce )
391 {
392 mRendererWidget->setMin( QLocale().toString( ce->minimumValue() ) );
393 mRendererWidget->setMax( QLocale().toString( ce->maximumValue() ) );
394 }
395 }
396 }
397}
398
399void QgsRendererRasterPropertiesWidget::updateGammaSpinBox( int value )
400{
401 mGammaSpinBox->setValue( value / 100.0 );
402}
403
404void QgsRendererRasterPropertiesWidget::updateGammaSlider( double value )
405{
406 mSliderGamma->setValue( value * 100 );
407}
@ SingleBandColorData
Single band containing color data.
Definition qgis.h:5322
@ SingleBandGray
A single band image drawn as a range of gray colors.
Definition qgis.h:5336
@ MultiBandColor
A layer containing 2 or more bands, mapped to RGB color space. In the case of a multiband with only t...
Definition qgis.h:5344
static QgsRasterRendererRegistry * rasterRendererRegistry()
Returns the application's raster renderer registry, used for managing raster layer renderers.
Brightness/contrast and gamma correction filter pipe for rasters.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
double minimumValue() const
Returns the minimum value for the contrast enhancement range.
double maximumValue() const
Returns the maximum value for the contrast enhancement range.
static bool isTransformationPossible(const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination)
Returns true if it is theoretically possible to transform between source and destination CRSes.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Factory method to create the renderer for this type.
Color and saturation filter pipe for rasters.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsMapLayerConfigWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
A panel widget that can be shown in the map style dock.
QgsMapLayer * layer()
Returns the layer the widget is associated with.
Base class for all map layer types.
Definition qgsmaplayer.h:83
void styleChanged()
Signal emitted whenever a change affects the layer's style.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
void changed()
Emitted when the widget state changes.
static bool layerIsContainedInGroupLayer(QgsProject *project, QgsMapLayer *layer)
Returns true if the specified layer is a child layer from any QgsGroupLayer in the given project.
static QgsProject * instance()
Returns the QgsProject singleton instance.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Widget creation function (mainly for the use by the renderer registry).
Represents a raster layer.
void insertWidgetFunction(const QString &rendererName, QgsRasterRendererWidgetCreateFunc func)
Sets the widget creation function for a renderer.
QStringList renderersList() const
Returns a list of the names of registered renderers.
Abstract base class for widgets which configure a QgsRasterRenderer.
virtual QgsRasterRenderer * renderer()=0
Creates a new renderer, using the properties defined in the widget.
void widgetChanged()
Emitted when something on the widget has changed.
Raster renderer pipe that applies colors to a raster.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Widget creation function (use by the renderer registry).
void rendererChanged()
called when user changes renderer type
QgsRendererRasterPropertiesWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
A widget to hold the renderer properties for a raster layer.
void syncToLayer(QgsRasterLayer *layer)
Sync the widget to the given layer.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the dialog.
void apply() override
Apply the changes from the dialog to the layer.
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
static QgsRasterRendererWidget * create(QgsRasterLayer *layer, const QgsRectangle &extent)
Creates new raster renderer widget.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:7637
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:80
Registry for raster renderer entries.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction