QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsrastertransparencywidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrastertransparencywidget.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 ***************************************************************************/
15#include <QWidget>
16#include <QIntValidator>
17#include <QFile>
18#include <QTextStream>
19#include <QMessageBox>
20#include <QFileDialog>
21#include <QRegularExpression>
22
23#include "qgssettings.h"
25#include "qgsrasterlayer.h"
28#include "qgsmaptoolemitpoint.h"
29#include "qgsmapsettings.h"
30#include "qgsrectangle.h"
31#include "qgsmapcanvas.h"
34#include "qgsdoublevalidator.h"
37
39 : QgsMapLayerConfigWidget( layer, canvas, parent )
40 , TRSTRING_NOT_SET( tr( "Not Set" ) )
41 , mRasterLayer( layer )
42 , mMapCanvas( canvas )
43{
44 setupUi( this );
45 connect( pbnAddValuesFromDisplay, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked );
46 connect( pbnAddValuesManually, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesManually_clicked );
47 connect( pbnDefaultValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnDefaultValues_clicked );
48 connect( pbnExportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked );
49 connect( pbnImportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked );
50 connect( pbnRemoveSelectedRow, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked );
51
52 mNodataColorButton->setShowNoColor( true );
53 mNodataColorButton->setColorDialogTitle( tr( "Select NoData Color" ) );
55
56 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsPanelWidget::widgetChanged );
57 connect( cboxTransparencyBand, &QgsRasterBandComboBox::bandChanged, this, &QgsPanelWidget::widgetChanged );
58 connect( mSrcNoDataValueCheckBox, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
59 connect( leNoDataValue, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
60 leNoDataValue->setValidator( new QgsDoubleValidator( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), this ) );
61 connect( mNodataColorButton, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
62
63 mPixelSelectorTool = nullptr;
64 if ( mMapCanvas )
65 {
66 mPixelSelectorTool = new QgsMapToolEmitPoint( mMapCanvas );
67 connect( mPixelSelectorTool, &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterTransparencyWidget::pixelSelected );
68 }
69 else
70 {
71 pbnAddValuesFromDisplay->setEnabled( false );
72 }
73
75}
76
78{
79 mContext = context;
80}
81
83{
84 QgsExpressionContext expContext;
88
89 if ( QgsMapCanvas *canvas = mContext.mapCanvas() )
90 {
91 expContext << QgsExpressionContextUtils::mapSettingsScope( canvas->mapSettings() )
92 << new QgsExpressionContextScope( canvas->expressionContextScope() );
93 if ( const QgsExpressionContextScopeGenerator *generator = dynamic_cast< const QgsExpressionContextScopeGenerator * >( canvas->temporalController() ) )
94 {
95 expContext << generator->createExpressionContextScope();
96 }
97 }
98 else
99 {
101 }
102
103 if ( mRasterLayer )
104 expContext << QgsExpressionContextUtils::layerScope( mRasterLayer );
105
106 // additional scopes
107 const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
108 for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
109 {
110 expContext.appendScope( new QgsExpressionContextScope( scope ) );
111 }
112
113 return expContext;
114}
115
117{
118 QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
119 QgsRasterRenderer *renderer = mRasterLayer->renderer();
120 if ( provider )
121 {
122 if ( provider->dataType( 1 ) == Qgis::DataType::ARGB32
124 {
125 gboxNoDataValue->setEnabled( false );
126 gboxCustomTransparency->setEnabled( false );
127 }
128
129 cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
130 cboxTransparencyBand->setLayer( mRasterLayer );
131 if ( provider->sourceHasNoDataValue( 1 ) )
132 {
133 lblSrcNoDataValue->setText( QgsRasterBlock::printValue( provider->sourceNoDataValue( 1 ) ) );
134 }
135 else
136 {
137 lblSrcNoDataValue->setText( tr( "not defined" ) );
138 }
139
140 mSrcNoDataValueCheckBox->setChecked( provider->useSourceNoDataValue( 1 ) );
141
142 const bool enableSrcNoData = provider->sourceHasNoDataValue( 1 ) && !std::isnan( provider->sourceNoDataValue( 1 ) );
143
144 mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
145 lblSrcNoDataValue->setEnabled( enableSrcNoData );
146 }
147
148 if ( renderer )
149 {
150 if ( renderer->nodataColor().isValid() )
151 mNodataColorButton->setColor( renderer->nodataColor() );
152 else
153 mNodataColorButton->setToNull();
154
155 mOpacityWidget->setOpacity( renderer->opacity() );
156
157 cboxTransparencyBand->setBand( renderer->alphaBand() );
158 }
159
160 if ( provider )
161 {
162 const QgsRasterRangeList noDataRangeList = provider->userNoDataValues( 1 );
163 QgsDebugMsgLevel( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ), 2 );
164 if ( !noDataRangeList.isEmpty() )
165 {
166 const double v = QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ).toDouble();
167 leNoDataValue->setText( QLocale().toString( v ) );
168 }
169 else
170 {
171 leNoDataValue->setText( QString() );
172 }
173 }
174 else
175 {
176 leNoDataValue->setText( QString() );
177 }
178
181
182 populateTransparencyTable( mRasterLayer->renderer() );
183}
184
185void QgsRasterTransparencyWidget::transparencyCellTextEdited( const QString &text )
186{
187 Q_UNUSED( text )
188 QgsDebugMsgLevel( QStringLiteral( "text = %1" ).arg( text ), 2 );
189 QgsRasterRenderer *renderer = mRasterLayer->renderer();
190 if ( !renderer )
191 {
192 return;
193 }
194 const int nBands = renderer->usesBands().size();
195 if ( nBands == 1 )
196 {
197 QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
198 if ( !lineEdit ) return;
199 int row = -1;
200 int column = -1;
201 for ( int r = 0; r < tableTransparency->rowCount(); r++ )
202 {
203 for ( int c = 0; c < tableTransparency->columnCount(); c++ )
204 {
205 if ( tableTransparency->cellWidget( r, c ) == sender() )
206 {
207 row = r;
208 column = c;
209 break;
210 }
211 }
212 if ( row != -1 ) break;
213 }
214 QgsDebugMsgLevel( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ), 2 );
215
216 if ( column == 0 )
217 {
218 QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
219 if ( !toLineEdit ) return;
220 const bool toChanged = mTransparencyToEdited.value( row );
221 QgsDebugMsgLevel( QStringLiteral( "toChanged = %1" ).arg( toChanged ), 2 );
222 if ( !toChanged )
223 {
224 toLineEdit->setText( lineEdit->text() );
225 }
226 }
227 else if ( column == 1 )
228 {
229 setTransparencyToEdited( row );
230 }
231 }
232 emit widgetChanged();
233}
234
235void QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked()
236{
237 if ( mMapCanvas && mPixelSelectorTool )
238 {
239 mMapCanvas->setMapTool( mPixelSelectorTool );
240 }
241}
242
243void QgsRasterTransparencyWidget::pbnAddValuesManually_clicked()
244{
245 QgsRasterRenderer *renderer = mRasterLayer->renderer();
246 if ( !renderer )
247 {
248 return;
249 }
250
251 tableTransparency->insertRow( tableTransparency->rowCount() );
252
253 int n = renderer->usesBands().size();
254 if ( n == 1 ) n++;
255
256 for ( int i = 0; i < n; i++ )
257 {
258 setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
259 }
260
261 setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
262
263 //tableTransparency->resizeColumnsToContents();
264 //tableTransparency->resizeRowsToContents();
265}
266
267void QgsRasterTransparencyWidget::pbnDefaultValues_clicked()
268{
269 QgsRasterRenderer *r = mRasterLayer->renderer();
270 if ( !r )
271 {
272 return;
273 }
274
275 const int nBands = r->usesBands().size();
276
277 setupTransparencyTable( nBands );
278
279 //tableTransparency->resizeColumnsToContents(); // works only with values
280 //tableTransparency->resizeRowsToContents();
281
282}
283
284void QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked()
285{
286 const QgsSettings myQSettings;
287 const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
288 QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save Pixel Values as File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
289 if ( !myFileName.isEmpty() )
290 {
291 if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
292 {
293 myFileName = myFileName + ".txt";
294 }
295
296 QFile myOutputFile( myFileName );
297 if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
298 {
299 QTextStream myOutputStream( &myOutputFile );
300 myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
301 if ( rasterIsMultiBandColor() )
302 {
303 myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
304 for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
305 {
306 myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
307 << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
308 << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
309 << QString::number( transparencyCellValue( myTableRunner, 3 ) );
310 }
311 }
312 else
313 {
314 myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
315
316 for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
317 {
318 myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
319 << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
320 << QString::number( transparencyCellValue( myTableRunner, 2 ) );
321 }
322 }
323 }
324 else
325 {
326 QMessageBox::warning( this, tr( "Save Pixel Values as File" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
327 }
328 }
329}
330
331void QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked()
332{
333 int myLineCounter = 0;
334 bool myImportError = false;
335 QString myBadLines;
336 const QgsSettings myQSettings;
337 const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
338 const QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Pixel Values from File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
339 QFile myInputFile( myFileName );
340 if ( myInputFile.open( QFile::ReadOnly ) )
341 {
342 QTextStream myInputStream( &myInputFile );
343 QString myInputLine;
344 if ( rasterIsMultiBandColor() )
345 {
346 for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
347 {
348 tableTransparency->removeRow( myTableRunner );
349 }
350
351 while ( !myInputStream.atEnd() )
352 {
353 myLineCounter++;
354 myInputLine = myInputStream.readLine();
355 if ( !myInputLine.isEmpty() )
356 {
357 if ( !myInputLine.simplified().startsWith( '#' ) )
358 {
359 QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
360 if ( myTokens.count() != 4 )
361 {
362 myImportError = true;
363 myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
364 }
365 else
366 {
367 tableTransparency->insertRow( tableTransparency->rowCount() );
368 for ( int col = 0; col < 4; col++ )
369 {
370 setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
371 }
372 }
373 }
374 }
375 }
376 }
377 else
378 {
379 for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
380 {
381 tableTransparency->removeRow( myTableRunner );
382 }
383
384 while ( !myInputStream.atEnd() )
385 {
386 myLineCounter++;
387 myInputLine = myInputStream.readLine();
388 if ( !myInputLine.isEmpty() )
389 {
390 if ( !myInputLine.simplified().startsWith( '#' ) )
391 {
392 QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
393 if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
394 {
395 myImportError = true;
396 myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
397 }
398 else
399 {
400 if ( myTokens.count() == 2 )
401 {
402 myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
403 }
404 tableTransparency->insertRow( tableTransparency->rowCount() );
405 for ( int col = 0; col < 3; col++ )
406 {
407 setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
408 }
409 }
410 }
411 }
412 }
413 }
414
415 if ( myImportError )
416 {
417 QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
418 }
419 }
420 else if ( !myFileName.isEmpty() )
421 {
422 QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
423 }
424 //tableTransparency->resizeColumnsToContents();
425 //tableTransparency->resizeRowsToContents();
426 emit widgetChanged();
427}
428
429void QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked()
430{
431 if ( 0 < tableTransparency->rowCount() )
432 {
433 tableTransparency->removeRow( tableTransparency->currentRow() );
434 }
435 emit widgetChanged();
436}
437
438bool QgsRasterTransparencyWidget::rasterIsMultiBandColor()
439{
440 return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
441}
442
444{
445 //set NoDataValue
446 QgsRasterRangeList myNoDataRangeList;
447 if ( "" != leNoDataValue->text() )
448 {
449 bool myDoubleOk = false;
450 const double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
451 if ( myDoubleOk )
452 {
453 const QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
454 myNoDataRangeList << myNoDataRange;
455 }
456 }
457 if ( QgsRasterDataProvider *provider = mRasterLayer->dataProvider() )
458 {
459 for ( int bandNo = 1; bandNo <= provider->bandCount(); bandNo++ )
460 {
461 provider->setUserNoDataValue( bandNo, myNoDataRangeList );
462 provider->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
463 }
464 }
465
466 //transparency settings
467 QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
468 if ( rasterRenderer )
469 {
470 rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
471 rasterRenderer->setNodataColor( mNodataColorButton->color() );
472
473 //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
474 QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
475 if ( tableTransparency->columnCount() == 4 )
476 {
477 QVector<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
478 myTransparentThreeValuePixelList.reserve( tableTransparency->rowCount() );
479 for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
480 {
481 const double red = transparencyCellValue( myListRunner, 0 );
482 const double green = transparencyCellValue( myListRunner, 1 );
483 const double blue = transparencyCellValue( myListRunner, 2 );
484 const double opacity = 1.0 - transparencyCellValue( myListRunner, 3 ) / 100.0;
485 myTransparentThreeValuePixelList.append(
486 QgsRasterTransparency::TransparentThreeValuePixel( red, green, blue, opacity )
487 );
488 }
489 rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
490 }
491 else if ( tableTransparency->columnCount() == 3 )
492 {
493 QVector<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
494 myTransparentSingleValuePixelList.reserve( tableTransparency->rowCount() );
495 for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
496 {
497 const double min = transparencyCellValue( myListRunner, 0 );
498 const double max = transparencyCellValue( myListRunner, 1 );
499 const double opacity = 1.0 - transparencyCellValue( myListRunner, 2 ) / 100.0;
500
501 myTransparentSingleValuePixelList.append(
503 );
504 }
505 rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
506 }
507
508 rasterRenderer->setRasterTransparency( rasterTransparency );
509
510 //set global transparency
511 rasterRenderer->setOpacity( mOpacityWidget->opacity() );
512 }
513
515}
516
518{
519 button->blockSignals( true );
520 button->init( static_cast< int >( key ), mPropertyCollection, QgsRasterPipe::propertyDefinitions(), nullptr );
521 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsRasterTransparencyWidget::updateProperty );
523 button->blockSignals( false );
524}
525
527{
528 const auto propertyOverrideButtons { findChildren< QgsPropertyOverrideButton * >() };
529 for ( QgsPropertyOverrideButton *button : propertyOverrideButtons )
530 {
531 updateDataDefinedButton( button );
532 }
533}
534
536{
537 if ( !button )
538 return;
539
540 if ( button->propertyKey() < 0 )
541 return;
542
543 const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
544 whileBlocking( button )->setToProperty( mPropertyCollection.property( key ) );
545}
546
547void QgsRasterTransparencyWidget::updateProperty()
548{
549 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
550 const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
552 emit widgetChanged();
553}
554
555void QgsRasterTransparencyWidget::pixelSelected( const QgsPointXY &canvasPoint )
556{
557 QgsRasterRenderer *renderer = mRasterLayer->renderer();
558 if ( !renderer )
559 {
560 return;
561 }
562
563 //Get the pixel values and add a new entry to the transparency table
564 if ( mMapCanvas && mPixelSelectorTool && mRasterLayer->dataProvider() )
565 {
566 mMapCanvas->unsetMapTool( mPixelSelectorTool );
567
568 const QgsMapSettings &ms = mMapCanvas->mapSettings();
569 const QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
570
571 const QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
572 const double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
573 const int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
574 const int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
575
576 const QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, Qgis::RasterIdentifyFormat::Value, myExtent, myWidth, myHeight ).results();
577
578 const QList<int> bands = renderer->usesBands();
579
580 QList<double> values;
581 for ( int i = 0; i < bands.size(); ++i )
582 {
583 const int bandNo = bands.value( i );
584 if ( myPixelMap.count( bandNo ) == 1 )
585 {
586 if ( QgsVariantUtils::isNull( myPixelMap.value( bandNo ) ) )
587 {
588 return; // Don't add nodata, transparent anyway
589 }
590 const double value = myPixelMap.value( bandNo ).toDouble();
591 QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 2 );
592 values.append( value );
593 }
594 }
595 if ( bands.size() == 1 )
596 {
597 // Set 'to'
598 values.insert( 1, values.value( 0 ) );
599 }
600 tableTransparency->insertRow( tableTransparency->rowCount() );
601 for ( int i = 0; i < values.size(); i++ )
602 {
603 setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
604 }
605 setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
606 }
607
608 //tableTransparency->resizeColumnsToContents();
609 //tableTransparency->resizeRowsToContents();
610}
611
612void QgsRasterTransparencyWidget::populateTransparencyTable( QgsRasterRenderer *renderer )
613{
614 if ( !mRasterLayer )
615 {
616 return;
617 }
618
619 if ( !renderer )
620 {
621 return;
622 }
623
624 const int nBands = renderer->usesBands().size();
625 setupTransparencyTable( nBands );
626
627 const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
628 if ( !rasterTransparency )
629 {
630 return;
631 }
632
633 if ( nBands == 1 )
634 {
635 QVector<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
636 for ( int i = 0; i < pixelList.size(); ++i )
637 {
638 tableTransparency->insertRow( i );
639 setTransparencyCell( i, 0, pixelList[i].min );
640 setTransparencyCell( i, 1, pixelList[i].max );
641 setTransparencyCell( i, 2, 100 * ( 1 - pixelList[i].opacity ) );
642 // break synchronization only if values differ
643 if ( pixelList[i].min != pixelList[i].max )
644 {
645 setTransparencyToEdited( i );
646 }
647 }
648 }
649 else if ( nBands == 3 )
650 {
651 QVector<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
652 for ( int i = 0; i < pixelList.size(); ++i )
653 {
654 tableTransparency->insertRow( i );
655 setTransparencyCell( i, 0, pixelList[i].red );
656 setTransparencyCell( i, 1, pixelList[i].green );
657 setTransparencyCell( i, 2, pixelList[i].blue );
658 setTransparencyCell( i, 3, 100 * ( 1 - pixelList[i].opacity ) );
659 }
660 }
661
662 tableTransparency->resizeColumnsToContents();
663 tableTransparency->resizeRowsToContents();
664
665}
666
667void QgsRasterTransparencyWidget::setupTransparencyTable( int nBands )
668{
669 tableTransparency->clear();
670 tableTransparency->setColumnCount( 0 );
671 tableTransparency->setRowCount( 0 );
672 mTransparencyToEdited.clear();
673
674 if ( nBands == 3 )
675 {
676 tableTransparency->setColumnCount( 4 );
677 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
678 tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
679 tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
680 tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
681 }
682 else //1 band
683 {
684 tableTransparency->setColumnCount( 3 );
685// Is it important to distinguish the header? It becomes difficult with range.
686#if 0
687 if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
688 QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
689 QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
690 QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
691 {
692 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
693 }
694 else
695 {
696 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
697 }
698#endif
699 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
700 tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
701 tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
702 }
703}
704
705void QgsRasterTransparencyWidget::setTransparencyCell( int row, int column, double value )
706{
707 QgsDebugMsgLevel( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ), 2 );
708 QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
709 if ( !provider )
710 return;
711
712 QgsRasterRenderer *renderer = mRasterLayer->renderer();
713 if ( !renderer )
714 return;
715 const int nBands = renderer->usesBands().size();
716
717 QLineEdit *lineEdit = new QLineEdit();
718 lineEdit->setFrame( false ); // frame looks bad in table
719 // Without margins row selection is not displayed (important for delete row)
720 lineEdit->setContentsMargins( 1, 1, 1, 1 );
721
722 if ( column == tableTransparency->columnCount() - 1 )
723 {
724 // transparency
725 // Who needs transparency as floating point?
726 lineEdit->setValidator( new QIntValidator( nullptr ) );
727 lineEdit->setText( QString::number( static_cast<int>( value ) ) );
728 }
729 else
730 {
731 // value
732 QString valueString;
733 switch ( provider->sourceDataType( 1 ) )
734 {
737 lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
738 if ( !std::isnan( value ) )
739 {
740 const double v = QgsRasterBlock::printValue( value ).toDouble();
741 valueString = QLocale().toString( v );
742 }
743 break;
744 default:
745 lineEdit->setValidator( new QIntValidator( nullptr ) );
746 if ( !std::isnan( value ) )
747 {
748 valueString = QString::number( static_cast<int>( value ) );
749 }
750 break;
751 }
752 lineEdit->setText( valueString );
753 connect( lineEdit, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
754 }
755 tableTransparency->setCellWidget( row, column, lineEdit );
756 adjustTransparencyCellWidth( row, column );
757
758 if ( nBands == 1 && ( column == 0 || column == 1 ) )
759 {
760 connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterTransparencyWidget::transparencyCellTextEdited );
761 }
762 //tableTransparency->resizeColumnsToContents();
763 emit widgetChanged();
764}
765
766void QgsRasterTransparencyWidget::adjustTransparencyCellWidth( int row, int column )
767{
768 QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
769 if ( !lineEdit ) return;
770
771 int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
772 width = std::max( width, tableTransparency->columnWidth( column ) );
773
774 lineEdit->setFixedWidth( width );
775}
776
777void QgsRasterTransparencyWidget::setTransparencyToEdited( int row )
778{
779 if ( row >= mTransparencyToEdited.size() )
780 {
781 mTransparencyToEdited.resize( row + 1 );
782 }
783 mTransparencyToEdited[row] = true;
784}
785
786double QgsRasterTransparencyWidget::transparencyCellValue( int row, int column )
787{
788 QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
789 if ( !lineEdit || lineEdit->text().isEmpty() )
790 {
791 return std::numeric_limits<double>::quiet_NaN();
792 }
793 return QgsDoubleValidator::toDouble( lineEdit->text() );
794
795}
796
798{
799 return mPixelSelectorTool;
800}
@ Float32
Thirty two bit floating point (float)
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Float64
Sixty four bit floating point (double)
@ Value
Numerical pixel value.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
QgsDoubleValidator is a QLineEdit Validator that combines QDoubleValidator and QRegularExpressionVali...
static double toDouble(const QString &input, bool *ok)
Converts input string to double value.
Abstract interface for generating an expression context scope.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:93
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
A panel widget that can be shown in the map style dock.
The QgsMapSettings class contains configuration for rendering of the map.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
A map tool that simply emits a point when clicking on the map.
void canvasClicked(const QgsPointXY &point, Qt::MouseButton button)
signal emitted on canvas click
Renderer for multiband images with the color components.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
void widgetChanged()
Emitted when the widget state changes.
A class to represent a 2D point.
Definition: qgspointxy.h:60
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
A button for controlling property overrides which may apply to a widget.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void changed()
Emitted when property definition changes.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout).
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
int propertyKey() const
Returns the property key linked to the button.
void bandChanged(int band)
Emitted when the currently selected band changes.
static QString printValue(double value)
Print double value with all necessary significant digits.
Base class for raster data providers.
virtual bool sourceHasNoDataValue(int bandNo) const
Returns true if source band has no data value.
virtual bool useSourceNoDataValue(int bandNo) const
Returns the source nodata value usage.
Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, Qgis::RasterIdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
QMap< int, QVariant > results() const
Returns the identify results.
Represents a raster layer.
QgsRasterPipe * pipe()
Returns the raster pipe.
QgsRasterRenderer * renderer() const
Returns the raster's renderer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the pipe's property collection, used for data defined overrides.
Property
Data definable properties.
Definition: qgsrasterpipe.h:60
@ RendererOpacity
Raster renderer global opacity.
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the pipe's property collection, used for data defined overrides.
Raster values range container.
Raster renderer pipe that applies colors to a raster.
QColor nodataColor() const
Returns the color to use for shading nodata pixels.
const QgsRasterTransparency * rasterTransparency() const
double opacity() const
Returns the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
virtual QList< int > usesBands() const
Returns a list of band numbers used by the renderer.
void setAlphaBand(int band)
void setOpacity(double opacity)
Sets the opacity for the renderer, where opacity is a value between 0 (totally transparent) and 1....
void setRasterTransparency(QgsRasterTransparency *t)
void setNodataColor(const QColor &color)
Sets the color to use for shading nodata pixels.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void updateDataDefinedButtons()
Updates all property override buttons to reflect the widgets's current properties.
QgsPropertyCollection mPropertyCollection
Temporary property collection.
void syncToLayer()
Sync the widget state to the layer set for the widget.
QgsMapToolEmitPoint * pixelSelectorTool() const
Returns the (possibly nullptr) map pixel selector tool.
void initializeDataDefinedButton(QgsPropertyOverrideButton *button, QgsRasterPipe::Property key)
Registers a property override button, setting up its initial value, connections and description.
QgsRasterTransparencyWidget(QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
Widget to control a layers transparency and related options.
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a specific property override button to reflect the widgets's current properties.
void apply() override
Apply any changes on the widget to the set layer.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the dialog is shown, e.g., the associated map canvas and expression context...
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
void setTransparentSingleValuePixelList(const QVector< QgsRasterTransparency::TransparentSingleValuePixel > &newList)
Sets the transparent single value pixel list, replacing the whole existing list.
QVector< QgsRasterTransparency::TransparentSingleValuePixel > transparentSingleValuePixelList() const
Returns the transparent single value pixel list.
void setTransparentThreeValuePixelList(const QVector< QgsRasterTransparency::TransparentThreeValuePixel > &newList)
Sets the transparent three value pixel list, replacing the whole existing list.
QVector< QgsRasterTransparency::TransparentThreeValuePixel > transparentThreeValuePixelList() const
Returns the transparent three value pixel list.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:243
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:5111
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QList< QgsRasterRange > QgsRasterRangeList
Defines the transparency for a range of single-band pixel values.
Defines the transparency for a RGB pixel value.