QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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::widgetChanged );
106 connect( mContrastSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
107 connect( mGammaSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
108 connect( spinBoxSaturation, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
109 connect( spinColorizeStrength, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
110 connect( btnColorizeColor, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
111 connect( mInvertColorsCheck, &QAbstractButton::toggled, this, &QgsPanelWidget::widgetChanged );
112
113 connect( mBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
114 connect( mZoomedInResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
115 connect( mZoomedOutResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
116 connect( mMaximumOversamplingSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
117 connect( mCbEarlyResampling, &QAbstractButton::toggled, this, &QgsPanelWidget::widgetChanged );
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 widgetChanged();
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 if ( QgsRasterRenderer *newRenderer = rendererWidget->renderer() )
152 {
153 // there are transparency related data stored in renderer instances, but they
154 // are not configured in the widget, so we need to copy them over from existing renderer
155 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
156 newRenderer->copyCommonProperties( oldRenderer, false );
157 mRasterLayer->setRenderer( newRenderer );
158 }
159 }
160
161 // Hue and saturation controls
162 if ( QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
163 {
164 hueSaturationFilter->setSaturation( sliderSaturation->value() );
165 hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
166 hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
167 hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
168 hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
169 hueSaturationFilter->setInvertColors( mInvertColorsCheck->isChecked() );
170 }
171
172 mResamplingUtils.refreshLayerFromWidgets();
173
174 mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
175}
176
178{
179 mRasterLayer = layer;
180
181 cboRenderers->blockSignals( true );
182 cboRenderers->clear();
184 const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
185 for ( const QString &name : constRenderersList )
186 {
187 if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
188 {
189 if ( ( mRasterLayer->rasterType() != Qgis::RasterLayerType::SingleBandColorData && entry.name != "singlebandcolordata"_L1 )
190 || ( mRasterLayer->rasterType() == Qgis::RasterLayerType::SingleBandColorData && entry.name == "singlebandcolordata"_L1 ) )
191 {
192 cboRenderers->addItem( entry.icon(), entry.visibleName, entry.name );
193 }
194 }
195 }
196 cboRenderers->setCurrentIndex( -1 );
197 cboRenderers->blockSignals( false );
198
199 if ( QgsRasterRenderer *renderer = mRasterLayer->renderer() )
200 {
201 setRendererWidget( renderer->type() );
202 }
203
204 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
205 {
206 mSliderBrightness->setValue( brightnessFilter->brightness() );
207 mSliderContrast->setValue( brightnessFilter->contrast() );
208 mGammaSpinBox->setValue( brightnessFilter->gamma() );
209 }
210
211 btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
212 btnColorizeColor->setContext( u"symbology"_s );
213
214 // Hue and saturation color control
215 //set hue and saturation controls to current values
216 if ( const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
217 {
218 sliderSaturation->setValue( hueSaturationFilter->saturation() );
219 comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
220
221 // Set initial state of saturation controls based on grayscale mode choice
222 toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
223
224 // Set initial state of colorize controls
225 mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
226 btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
227 toggleColorizeControls( hueSaturationFilter->colorizeOn() );
228 sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
229
230 mInvertColorsCheck->setChecked( hueSaturationFilter->invertColors() );
231 }
232
233 //blend mode
234 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mRasterLayer ) );
235 mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
236
237 //set combo boxes to current resampling types
238 mResamplingUtils.refreshWidgetsFromLayer();
239}
240
241void QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked()
242{
243 mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
244 mSliderBrightness->setValue( 0 );
245 mSliderContrast->setValue( 0 );
246 mGammaSpinBox->setValue( 1.0 );
247 sliderSaturation->setValue( 0 );
248 comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
249 mColorizeCheck->setChecked( false );
250 sliderColorizeStrength->setValue( 100 );
251 mInvertColorsCheck->setChecked( false );
252}
253
254void QgsRendererRasterPropertiesWidget::toggleSaturationControls( int grayscaleMode )
255{
256 // Enable or disable saturation controls based on choice of grayscale mode
257 if ( grayscaleMode == 0 )
258 {
259 sliderSaturation->setEnabled( true );
260 spinBoxSaturation->setEnabled( true );
261 }
262 else
263 {
264 sliderSaturation->setEnabled( false );
265 spinBoxSaturation->setEnabled( false );
266 }
267 emit widgetChanged();
268}
269
270void QgsRendererRasterPropertiesWidget::toggleColorizeControls( bool colorizeEnabled )
271{
272 // Enable or disable colorize controls based on checkbox
273 btnColorizeColor->setEnabled( colorizeEnabled );
274 sliderColorizeStrength->setEnabled( colorizeEnabled );
275 spinColorizeStrength->setEnabled( colorizeEnabled );
276 emit widgetChanged();
277}
278
279void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
280{
281 QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
282 QgsRasterRendererWidget *oldWidget = mRendererWidget;
283
284 int alphaBand = -1;
285 double opacity = 1;
286 QColor nodataColor;
287 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
288 {
289 // Retain alpha band and opacity when switching renderer
290 alphaBand = oldRenderer->alphaBand();
291 opacity = oldRenderer->opacity();
292 nodataColor = oldRenderer->nodataColor();
293 }
294
295 QgsRasterRendererRegistryEntry rendererEntry;
296 if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
297 {
298 if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
299 {
300 QgsDebugMsgLevel( u"renderer has widgetCreateFunction"_s, 3 );
301 // Current canvas extent (used to calc min/max) in layer CRS
302 const QgsRectangle myExtent = QgsCoordinateTransform::isTransformationPossible( mRasterLayer->crs(), mMapCanvas->mapSettings().destinationCrs() )
303 ? mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() )
304 : mRasterLayer->extent();
305 if ( oldWidget )
306 {
307 std::unique_ptr<QgsRasterRenderer> oldRenderer( oldWidget->renderer() );
308 if ( !oldRenderer || oldRenderer->type() != rendererName )
309 {
310 if ( rendererName == "singlebandgray"_L1 )
311 {
312 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::SingleBandGray, mRasterLayer->dataProvider() ) );
313 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
314 }
315 else if ( rendererName == "multibandcolor"_L1 )
316 {
317 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::MultiBandColor, mRasterLayer->dataProvider() ) );
318 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
319 }
320 }
321 }
322 mRasterLayer->renderer()->setAlphaBand( alphaBand );
323 mRasterLayer->renderer()->setOpacity( opacity );
324 mRasterLayer->renderer()->setNodataColor( nodataColor );
325 mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
326 mRendererWidget->setMapCanvas( mMapCanvas );
328 stackedWidget->addWidget( mRendererWidget );
329 stackedWidget->setCurrentWidget( mRendererWidget );
330 if ( oldWidget )
331 {
332 // Compare used bands in new and old renderer and reset transparency dialog if different
333 QgsRasterRenderer *oldRenderer = oldWidget->renderer();
334 QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
335#if 0
336 QList<int> oldBands = oldRenderer->usesBands();
337 QList<int> newBands = newRenderer->usesBands();
338
339 if ( oldBands != newBands )
340 {
341 populateTransparencyTable( newRenderer );
342 }
343#endif
344
345 delete oldRenderer;
346 delete newRenderer;
347 }
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:4924
@ SingleBandGray
A single band image drawn as a range of gray colors.
Definition qgis.h:4938
@ 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:4946
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.
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 widgetChanged()
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.
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
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:6880
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
Registry for raster renderer entries.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction