QGIS API Documentation 3.99.0-Master (d270888f95f)
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 ) || ( mRasterLayer->rasterType() == Qgis::RasterLayerType::SingleBandColorData && entry.name == "singlebandcolordata"_L1 ) )
190 {
191 cboRenderers->addItem( entry.icon(), entry.visibleName, entry.name );
192 }
193 }
194 }
195 cboRenderers->setCurrentIndex( -1 );
196 cboRenderers->blockSignals( false );
197
198 if ( QgsRasterRenderer *renderer = mRasterLayer->renderer() )
199 {
200 setRendererWidget( renderer->type() );
201 }
202
203 if ( QgsBrightnessContrastFilter *brightnessFilter = mRasterLayer->brightnessFilter() )
204 {
205 mSliderBrightness->setValue( brightnessFilter->brightness() );
206 mSliderContrast->setValue( brightnessFilter->contrast() );
207 mGammaSpinBox->setValue( brightnessFilter->gamma() );
208 }
209
210 btnColorizeColor->setColorDialogTitle( tr( "Select Color" ) );
211 btnColorizeColor->setContext( u"symbology"_s );
212
213 // Hue and saturation color control
214 //set hue and saturation controls to current values
215 if ( const QgsHueSaturationFilter *hueSaturationFilter = mRasterLayer->hueSaturationFilter() )
216 {
217 sliderSaturation->setValue( hueSaturationFilter->saturation() );
218 comboGrayscale->setCurrentIndex( ( int ) hueSaturationFilter->grayscaleMode() );
219
220 // Set initial state of saturation controls based on grayscale mode choice
221 toggleSaturationControls( static_cast<int>( hueSaturationFilter->grayscaleMode() ) );
222
223 // Set initial state of colorize controls
224 mColorizeCheck->setChecked( hueSaturationFilter->colorizeOn() );
225 btnColorizeColor->setColor( hueSaturationFilter->colorizeColor() );
226 toggleColorizeControls( hueSaturationFilter->colorizeOn() );
227 sliderColorizeStrength->setValue( hueSaturationFilter->colorizeStrength() );
228
229 mInvertColorsCheck->setChecked( hueSaturationFilter->invertColors() );
230 }
231
232 //blend mode
233 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mRasterLayer ) );
234 mBlendModeComboBox->setBlendMode( mRasterLayer->blendMode() );
235
236 //set combo boxes to current resampling types
237 mResamplingUtils.refreshWidgetsFromLayer();
238}
239
240void QgsRendererRasterPropertiesWidget::mResetColorRenderingBtn_clicked()
241{
242 mBlendModeComboBox->setBlendMode( QPainter::CompositionMode_SourceOver );
243 mSliderBrightness->setValue( 0 );
244 mSliderContrast->setValue( 0 );
245 mGammaSpinBox->setValue( 1.0 );
246 sliderSaturation->setValue( 0 );
247 comboGrayscale->setCurrentIndex( ( int ) QgsHueSaturationFilter::GrayscaleOff );
248 mColorizeCheck->setChecked( false );
249 sliderColorizeStrength->setValue( 100 );
250 mInvertColorsCheck->setChecked( false );
251}
252
253void QgsRendererRasterPropertiesWidget::toggleSaturationControls( int grayscaleMode )
254{
255 // Enable or disable saturation controls based on choice of grayscale mode
256 if ( grayscaleMode == 0 )
257 {
258 sliderSaturation->setEnabled( true );
259 spinBoxSaturation->setEnabled( true );
260 }
261 else
262 {
263 sliderSaturation->setEnabled( false );
264 spinBoxSaturation->setEnabled( false );
265 }
266 emit widgetChanged();
267}
268
269void QgsRendererRasterPropertiesWidget::toggleColorizeControls( bool colorizeEnabled )
270{
271 // Enable or disable colorize controls based on checkbox
272 btnColorizeColor->setEnabled( colorizeEnabled );
273 sliderColorizeStrength->setEnabled( colorizeEnabled );
274 spinColorizeStrength->setEnabled( colorizeEnabled );
275 emit widgetChanged();
276}
277
278void QgsRendererRasterPropertiesWidget::setRendererWidget( const QString &rendererName )
279{
280 QgsDebugMsgLevel( "rendererName = " + rendererName, 3 );
281 QgsRasterRendererWidget *oldWidget = mRendererWidget;
282
283 int alphaBand = -1;
284 double opacity = 1;
285 QColor nodataColor;
286 if ( QgsRasterRenderer *oldRenderer = mRasterLayer->renderer() )
287 {
288 // Retain alpha band and opacity when switching renderer
289 alphaBand = oldRenderer->alphaBand();
290 opacity = oldRenderer->opacity();
291 nodataColor = oldRenderer->nodataColor();
292 }
293
294 QgsRasterRendererRegistryEntry rendererEntry;
295 if ( QgsApplication::rasterRendererRegistry()->rendererData( rendererName, rendererEntry ) )
296 {
297 if ( rendererEntry.widgetCreateFunction ) // Single band color data renderer e.g. has no widget
298 {
299 QgsDebugMsgLevel( u"renderer has widgetCreateFunction"_s, 3 );
300 // Current canvas extent (used to calc min/max) in layer CRS
301 const QgsRectangle myExtent = QgsCoordinateTransform::isTransformationPossible( mRasterLayer->crs(), mMapCanvas->mapSettings().destinationCrs() )
302 ? mMapCanvas->mapSettings().outputExtentToLayerExtent( mRasterLayer, mMapCanvas->extent() )
303 : mRasterLayer->extent();
304 if ( oldWidget )
305 {
306 std::unique_ptr<QgsRasterRenderer> oldRenderer( oldWidget->renderer() );
307 if ( !oldRenderer || oldRenderer->type() != rendererName )
308 {
309 if ( rendererName == "singlebandgray"_L1 )
310 {
311 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::SingleBandGray, mRasterLayer->dataProvider() ) );
312 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
313 }
314 else if ( rendererName == "multibandcolor"_L1 )
315 {
316 whileBlocking( mRasterLayer )->setRenderer( QgsApplication::rasterRendererRegistry()->defaultRendererForDrawingStyle( Qgis::RasterDrawingStyle::MultiBandColor, mRasterLayer->dataProvider() ) );
317 whileBlocking( mRasterLayer )->setDefaultContrastEnhancement();
318 }
319 }
320 }
321 mRasterLayer->renderer()->setAlphaBand( alphaBand );
322 mRasterLayer->renderer()->setOpacity( opacity );
323 mRasterLayer->renderer()->setNodataColor( nodataColor );
324 mRendererWidget = rendererEntry.widgetCreateFunction( mRasterLayer, myExtent );
325 mRendererWidget->setMapCanvas( mMapCanvas );
327 stackedWidget->addWidget( mRendererWidget );
328 stackedWidget->setCurrentWidget( mRendererWidget );
329 if ( oldWidget )
330 {
331 // Compare used bands in new and old renderer and reset transparency dialog if different
332 QgsRasterRenderer *oldRenderer = oldWidget->renderer();
333 QgsRasterRenderer *newRenderer = mRendererWidget->renderer();
334#if 0
335 QList<int> oldBands = oldRenderer->usesBands();
336 QList<int> newBands = newRenderer->usesBands();
337
338 if ( oldBands != newBands )
339 {
340 populateTransparencyTable( newRenderer );
341 }
342#endif
343
344 delete oldRenderer;
345 delete newRenderer;
346 }
347 }
348 }
349
350 if ( mRendererWidget != oldWidget )
351 delete oldWidget;
352
353 const int widgetIndex = cboRenderers->findData( rendererName );
354 if ( widgetIndex != -1 )
355 {
356 whileBlocking( cboRenderers )->setCurrentIndex( widgetIndex );
357 }
358}
359
360void QgsRendererRasterPropertiesWidget::refreshAfterStyleChanged()
361{
362 if ( mRendererWidget )
363 {
364 QgsRasterRenderer *renderer = mRasterLayer->renderer();
365 if ( QgsMultiBandColorRenderer *mbcr = dynamic_cast<QgsMultiBandColorRenderer *>( renderer ) )
366 {
367 const QgsContrastEnhancement *redCe = mbcr->redContrastEnhancement();
368 if ( redCe )
369 {
370 mRendererWidget->setMin( QLocale().toString( redCe->minimumValue() ), 0 );
371 mRendererWidget->setMax( QLocale().toString( redCe->maximumValue() ), 0 );
372 }
373 const QgsContrastEnhancement *greenCe = mbcr->greenContrastEnhancement();
374 if ( greenCe )
375 {
376 mRendererWidget->setMin( QLocale().toString( greenCe->minimumValue() ), 1 );
377 mRendererWidget->setMax( QLocale().toString( greenCe->maximumValue() ), 1 );
378 }
379 const QgsContrastEnhancement *blueCe = mbcr->blueContrastEnhancement();
380 if ( blueCe )
381 {
382 mRendererWidget->setMin( QLocale().toString( blueCe->minimumValue() ), 2 );
383 mRendererWidget->setMax( QLocale().toString( blueCe->maximumValue() ), 2 );
384 }
385 }
386 else if ( QgsSingleBandGrayRenderer *sbgr = dynamic_cast<QgsSingleBandGrayRenderer *>( renderer ) )
387 {
388 const QgsContrastEnhancement *ce = sbgr->contrastEnhancement();
389 if ( ce )
390 {
391 mRendererWidget->setMin( QLocale().toString( ce->minimumValue() ) );
392 mRendererWidget->setMax( QLocale().toString( ce->maximumValue() ) );
393 }
394 }
395 }
396}
397
398void QgsRendererRasterPropertiesWidget::updateGammaSpinBox( int value )
399{
400 mGammaSpinBox->setValue( value / 100.0 );
401}
402
403void QgsRendererRasterPropertiesWidget::updateGammaSlider( double value )
404{
405 mSliderGamma->setValue( value * 100 );
406}
@ SingleBandColorData
Single band containing color data.
Definition qgis.h:4839
@ SingleBandGray
A single band image drawn as a range of gray colors.
Definition qgis.h:4853
@ 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:4861
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:6804
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
Registry for raster renderer entries.
QgsRasterRendererWidgetCreateFunc widgetCreateFunction