QGIS API Documentation 3.99.0-Master (752b475928d)
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 "moc_qgsrendererrasterpropertieswidget.cpp"
38
39void QgsRendererRasterPropertiesWidget::initRendererWidgetFunctions()
40{
41 static bool sInitialized = false;
42 if ( sInitialized )
43 return;
44
52
53 sInitialized = true;
54}
55
57 : QgsMapLayerConfigWidget( layer, canvas, parent )
58 , mRasterLayer( qobject_cast<QgsRasterLayer *>( layer ) )
59{
60 if ( !mRasterLayer )
61 return;
62
63 setupUi( this );
64 connect( mResetColorRenderingBtn, &QToolButton::clicked, this, &QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked );
65
66 initRendererWidgetFunctions();
67
68 mResamplingUtils.initWidgets( mRasterLayer, mZoomedInResamplingComboBox, mZoomedOutResamplingComboBox, mMaximumOversamplingSpinBox, mCbEarlyResampling );
69
70 connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::rendererChanged );
71
72 connect( mSliderBrightness, &QAbstractSlider::valueChanged, mBrightnessSpinBox, &QSpinBox::setValue );
73 connect( mBrightnessSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), mSliderBrightness, &QAbstractSlider::setValue );
74 mBrightnessSpinBox->setClearValue( 0 );
75
76 connect( mSliderContrast, &QAbstractSlider::valueChanged, mContrastSpinBox, &QSpinBox::setValue );
77 connect( mContrastSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), mSliderContrast, &QAbstractSlider::setValue );
78 mContrastSpinBox->setClearValue( 0 );
79
80 connect( mSliderGamma, &QAbstractSlider::valueChanged, this, &QgsRendererRasterPropertiesWidget::updateGammaSpinBox );
81 connect( mGammaSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsRendererRasterPropertiesWidget::updateGammaSlider );
82 mGammaSpinBox->setClearValue( 1.0 );
83
84 // Connect saturation slider and spin box
85 connect( sliderSaturation, &QAbstractSlider::valueChanged, spinBoxSaturation, &QSpinBox::setValue );
86 connect( spinBoxSaturation, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), sliderSaturation, &QAbstractSlider::setValue );
87 spinBoxSaturation->setClearValue( 0 );
88
89 // Connect colorize strength slider and spin box
90 connect( sliderColorizeStrength, &QAbstractSlider::valueChanged, spinColorizeStrength, &QSpinBox::setValue );
91 connect( spinColorizeStrength, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), sliderColorizeStrength, &QAbstractSlider::setValue );
92 spinColorizeStrength->setClearValue( 100 );
93
94 // enable or disable saturation slider and spin box depending on grayscale combo choice
95 connect( comboGrayscale, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererRasterPropertiesWidget::toggleSaturationControls );
96
97 // enable or disable colorize colorbutton with colorize checkbox
98 connect( mColorizeCheck, &QAbstractButton::toggled, this, &QgsRendererRasterPropertiesWidget::toggleColorizeControls );
99
100 // Just connect the spin boxes because the sliders update the spinners
101 connect( mBrightnessSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
102 connect( mContrastSpinBox, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
103 connect( mGammaSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
104 connect( spinBoxSaturation, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
105 connect( spinColorizeStrength, static_cast<void ( QSpinBox::* )( int )>( &QSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
106 connect( btnColorizeColor, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
107 connect( mInvertColorsCheck, &QAbstractButton::toggled, this, &QgsPanelWidget::widgetChanged );
108
109 connect( mBlendModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
110 connect( mZoomedInResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
111 connect( mZoomedOutResamplingComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
112 connect( mMaximumOversamplingSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPanelWidget::widgetChanged );
113 connect( mCbEarlyResampling, &QAbstractButton::toggled, this, &QgsPanelWidget::widgetChanged );
114
115 // finally sync to the layer - even though some actions may emit widgetChanged signal,
116 // this is not a problem - nobody is listening to our signals yet
117 syncToLayer( mRasterLayer );
118
119 connect( mRasterLayer, &QgsMapLayer::styleChanged, this, &QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged );
120}
121
126
128{
129 const QString rendererName = cboRenderers->currentData().toString();
130 setRendererWidget( rendererName );
131 emit widgetChanged();
132}
133
135{
136 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
137 {
138 brightnessFilter->setBrightness( mSliderBrightness->value() );
139 brightnessFilter->setContrast( mSliderContrast->value() );
140 brightnessFilter->setGamma( mGammaSpinBox->value() );
141 }
142
143 if ( QgsRasterRendererWidget *rendererWidget = dynamic_cast<QgsRasterRendererWidget *>( stackedWidget->currentWidget() ) )
144 {
145 rendererWidget->doComputations();
146
147 if ( QgsRasterRenderer *newRenderer = rendererWidget->renderer() )
148 {
149 // there are transparency related data stored in renderer instances, but they
150 // are not configured in the widget, so we need to copy them over from existing renderer
151 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
152 newRenderer->copyCommonProperties( oldRenderer, false );
153 mRasterLayer->setRenderer( newRenderer );
154 }
155 }
156
157 // Hue and saturation controls
158 if ( QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
159 {
160 hueSaturationFilter->setSaturation( sliderSaturation->value() );
161 hueSaturationFilter->setGrayscaleMode( ( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
162 hueSaturationFilter->setColorizeOn( mColorizeCheck->checkState() );
163 hueSaturationFilter->setColorizeColor( btnColorizeColor->color() );
164 hueSaturationFilter->setColorizeStrength( sliderColorizeStrength->value() );
165 hueSaturationFilter->setInvertColors( mInvertColorsCheck->isChecked() );
166 }
167
168 mResamplingUtils.refreshLayerFromWidgets();
169
170 mRasterLayer->setBlendMode( mBlendModeComboBox->blendMode() );
171}
172
174{
175 mRasterLayer = layer;
176
177 cboRenderers->blockSignals( true );
178 cboRenderers->clear();
180 const auto constRenderersList = QgsApplication::rasterRendererRegistry()->renderersList();
181 for ( const QString &name : constRenderersList )
182 {
183 if ( QgsApplication::rasterRendererRegistry()->rendererData( name, entry ) )
184 {
185 if ( ( mRasterLayer->rasterType() != Qgis::RasterLayerType::SingleBandColorData && entry.name != QLatin1String( "singlebandcolordata" ) ) || ( mRasterLayer->rasterType() == Qgis::RasterLayerType::SingleBandColorData && entry.name == QLatin1String( "singlebandcolordata" ) ) )
186 {
187 cboRenderers->addItem( entry.icon(), entry.visibleName, entry.name );
188 }
189 }
190 }
191 cboRenderers->setCurrentIndex( -1 );
192 cboRenderers->blockSignals( false );
193
194 if ( QgsRasterRenderer *renderer = mRasterLayer->renderer() )
195 {
196 setRendererWidget( renderer->type() );
197 }
198
199 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
200 {
201 mSliderBrightness->setValue( brightnessFilter->brightness() );
202 mSliderContrast->setValue( brightnessFilter->contrast() );
203 mGammaSpinBox->setValue( brightnessFilter->gamma() );
204 }
205
206 btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
207 btnColorizeColor->setContext( QStringLiteral( "symbology" ) );
208
209 // Hue and saturation color control
210 //set hue and saturation controls to current values
211 if ( const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
212 {
213 sliderSaturation->setValue( hueSaturationFilter->saturation() );
214 comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
215
216 // Set initial state of saturation controls based on grayscale mode choice
217 toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
218
219 // Set initial state of colorize controls
220 mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
221 btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
222 toggleColorizeControls( hueSaturationFilter->colorizeOn() );
223 sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
224
225 mInvertColorsCheck->setChecked( hueSaturationFilter->invertColors() );
226 }
227
228 //blend mode
229 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mRasterLayer ) );
230 mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
231
232 //set combo boxes to current resampling types
233 mResamplingUtils.refreshWidgetsFromLayer();
234}
235
236void QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked()
237{
238 mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
239 mSliderBrightness->setValue( 0 );
240 mSliderContrast->setValue( 0 );
241 mGammaSpinBox->setValue( 1.0 );
242 sliderSaturation->setValue( 0 );
243 comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
244 mColorizeCheck->setChecked( false );
245 sliderColorizeStrength->setValue( 100 );
246 mInvertColorsCheck->setChecked( false );
247}
248
249void QgsRendererRasterPropertiesWidget::toggleSaturationControls( int grayscaleMode )
250{
251 // Enable or disable saturation controls based on choice of grayscale mode
252 if ( grayscaleMode == 0 )
253 {
254 sliderSaturation->setEnabled( true );
255 spinBoxSaturation->setEnabled( true );
256 }
257 else
258 {
259 sliderSaturation->setEnabled( false );
260 spinBoxSaturation->setEnabled( false );
261 }
262 emit widgetChanged();
263}
264
265void QgsRendererRasterPropertiesWidget::toggleColorizeControls( bool colorizeEnabled )
266{
267 // Enable or disable colorize controls based on checkbox
268 btnColorizeColor->setEnabled( colorizeEnabled );
269 sliderColorizeStrength->setEnabled( colorizeEnabled );
270 spinColorizeStrength->setEnabled( colorizeEnabled );
271 emit widgetChanged();
272}
273
274void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
275{
276 QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
277 QgsRasterRendererWidget *oldWidget = mRendererWidget;
278
279 int alphaBand = -1;
280 double opacity = 1;
281 QColor nodataColor;
282 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
283 {
284 // Retain alpha band and opacity when switching renderer
285 alphaBand = oldRenderer->alphaBand();
286 opacity = oldRenderer->opacity();
287 nodataColor = oldRenderer->nodataColor();
288 }
289
290 QgsRasterRendererRegistryEntry rendererEntry;
291 if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
292 {
293 if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
294 {
295 QgsDebugMsgLevel( QStringLiteral( "renderer has widgetCreateFunction" ), 3 );
296 // Current canvas extent (used to calc min/max) in layer CRS
297 const QgsRectangle myExtent = QgsCoordinateTransform::isTransformationPossible( mRasterLayer->crs(), mMapCanvas->mapSettings().destinationCrs() )
298 ? mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() )
299 : mRasterLayer->extent();
300 if ( oldWidget )
301 {
302 std::unique_ptr<QgsRasterRenderer> oldRenderer( oldWidget->renderer() );
303 if ( !oldRenderer || oldRenderer->type() != rendererName )
304 {
305 if ( rendererName == QLatin1String( "singlebandgray" ) )
306 {
307 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::SingleBandGray, mRasterLayer->dataProvider() ) );
308 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
309 }
310 else if ( rendererName == QLatin1String( "multibandcolor" ) )
311 {
312 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::MultiBandColor, mRasterLayer->dataProvider() ) );
313 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
314 }
315 }
316 }
317 mRasterLayer->renderer()->setAlphaBand( alphaBand );
318 mRasterLayer->renderer()->setOpacity( opacity );
319 mRasterLayer->renderer()->setNodataColor( nodataColor );
320 mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
321 mRendererWidget->setMapCanvas( mMapCanvas );
323 stackedWidget->addWidget( mRendererWidget );
324 stackedWidget->setCurrentWidget( mRendererWidget );
325 if ( oldWidget )
326 {
327 // Compare used bands in new and old renderer and reset transparency dialog if different
328 QgsRasterRenderer *oldRenderer = oldWidget->renderer();
329 QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
330#if 0
331 QList<int> oldBands = oldRenderer->usesBands();
332 QList<int> newBands = newRenderer->usesBands();
333
334 if ( oldBands != newBands )
335 {
336 populateTransparencyTable( newRenderer );
337 }
338#endif
339
340 delete oldRenderer;
341 delete newRenderer;
342 }
343 }
344 }
345
346 if ( mRendererWidget != oldWidget )
347 delete oldWidget;
348
349 const int widgetIndex = cboRenderers->findData( rendererName );
350 if ( widgetIndex != -1 )
351 {
352 whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
353 }
354}
355
356void QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged()
357{
358 if ( mRendererWidget )
359 {
360 QgsRasterRenderer *renderer = mRasterLayer->renderer();
361 if ( QgsMultiBandColorRenderer *mbcr = dynamic_cast<QgsMultiBandColorRenderer *>( renderer ) )
362 {
363 const QgsContrastEnhancement *redCe = mbcr->redContrastEnhancement();
364 if ( redCe )
365 {
366 mRendererWidget->setMin( QLocale().toString( redCe->minimumValue() ), 0 );
367 mRendererWidget->setMax( QLocale().toString( redCe->maximumValue() ), 0 );
368 }
369 const QgsContrastEnhancement *greenCe = mbcr->greenContrastEnhancement();
370 if ( greenCe )
371 {
372 mRendererWidget->setMin( QLocale().toString( greenCe->minimumValue() ), 1 );
373 mRendererWidget->setMax( QLocale().toString( greenCe->maximumValue() ), 1 );
374 }
375 const QgsContrastEnhancement *blueCe = mbcr->blueContrastEnhancement();
376 if ( blueCe )
377 {
378 mRendererWidget->setMin( QLocale().toString( blueCe->minimumValue() ), 2 );
379 mRendererWidget->setMax( QLocale().toString( blueCe->maximumValue() ), 2 );
380 }
381 }
382 else if ( QgsSingleBandGrayRenderer *sbgr = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer ) )
383 {
384 const QgsContrastEnhancement *ce = sbgr->contrastEnhancement();
385 if ( ce )
386 {
387 mRendererWidget->setMin( QLocale().toString( ce->minimumValue() ) );
388 mRendererWidget->setMax( QLocale().toString( ce->maximumValue() ) );
389 }
390 }
391 }
392}
393
394void QgsRendererRasterPropertiesWidget::updateGammaSpinBox( int value )
395{
396 mGammaSpinBox->setValue( value / 100.0 );
397}
398
399void QgsRendererRasterPropertiesWidget::updateGammaSlider( double value )
400{
401 mSliderGamma->setValue( value * 100 );
402}
@ SingleBandColorData
Single band containing color data.
Definition qgis.h:4767
@ SingleBandGray
A single band image drawn as a range of gray colors.
Definition qgis.h:4781
@ 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:4789
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:80
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:6511
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
Registry for raster renderer entries.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction