QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
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"
26#include "qgsraster.h"
30#include "qgsmaptoolemitpoint.h"
31#include "qgsmapsettings.h"
32#include "qgsrectangle.h"
33#include "qgsmapcanvas.h"
36#include "qgsdoublevalidator.h"
39
41 : QgsMapLayerConfigWidget( layer, canvas, parent )
42 , TRSTRING_NOT_SET( tr( "Not Set" ) )
43 , mRasterLayer( layer )
44 , mMapCanvas( canvas )
45{
46 setupUi( this );
47 connect( pbnAddValuesFromDisplay, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked );
48 connect( pbnAddValuesManually, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnAddValuesManually_clicked );
49 connect( pbnDefaultValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnDefaultValues_clicked );
50 connect( pbnExportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked );
51 connect( pbnImportTransparentPixelValues, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked );
52 connect( pbnRemoveSelectedRow, &QToolButton::clicked, this, &QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked );
53
54 mNodataColorButton->setShowNoColor( true );
55 mNodataColorButton->setColorDialogTitle( tr( "Select No Data Color" ) );
57
58 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsPanelWidget::widgetChanged );
59 connect( cboxTransparencyBand, &QgsRasterBandComboBox::bandChanged, this, &QgsPanelWidget::widgetChanged );
60 connect( mSrcNoDataValueCheckBox, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
61 connect( leNoDataValue, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
62 leNoDataValue->setValidator( new QgsDoubleValidator( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), this ) );
63 connect( mNodataColorButton, &QgsColorButton::colorChanged, this, &QgsPanelWidget::widgetChanged );
64
65 mPixelSelectorTool = nullptr;
66 if ( mMapCanvas )
67 {
68 mPixelSelectorTool = new QgsMapToolEmitPoint( mMapCanvas );
69 connect( mPixelSelectorTool, &QgsMapToolEmitPoint::canvasClicked, this, &QgsRasterTransparencyWidget::pixelSelected );
70 }
71 else
72 {
73 pbnAddValuesFromDisplay->setEnabled( false );
74 }
75
77}
78
80{
81 mContext = context;
82}
83
85{
86 QgsExpressionContext expContext;
90
91 if ( QgsMapCanvas *canvas = mContext.mapCanvas() )
92 {
93 expContext << QgsExpressionContextUtils::mapSettingsScope( canvas->mapSettings() )
94 << new QgsExpressionContextScope( canvas->expressionContextScope() );
95 if ( const QgsExpressionContextScopeGenerator *generator = dynamic_cast< const QgsExpressionContextScopeGenerator * >( canvas->temporalController() ) )
96 {
97 expContext << generator->createExpressionContextScope();
98 }
99 }
100 else
101 {
103 }
104
105 if ( mRasterLayer )
106 expContext << QgsExpressionContextUtils::layerScope( mRasterLayer );
107
108 // additional scopes
109 const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
110 for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
111 {
112 expContext.appendScope( new QgsExpressionContextScope( scope ) );
113 }
114
115 return expContext;
116}
117
119{
120 QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
121 QgsRasterRenderer *renderer = mRasterLayer->renderer();
122 if ( provider )
123 {
124 if ( provider->dataType( 1 ) == Qgis::DataType::ARGB32
126 {
127 gboxNoDataValue->setEnabled( false );
128 gboxCustomTransparency->setEnabled( false );
129 }
130
131 cboxTransparencyBand->setShowNotSetOption( true, tr( "None" ) );
132 cboxTransparencyBand->setLayer( mRasterLayer );
133
134 if ( provider->sourceHasNoDataValue( 1 ) )
135 {
136 lblSrcNoDataValue->setText( QgsRasterBlock::printValue( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) ) );
137 }
138 else
139 {
140 lblSrcNoDataValue->setText( tr( "not defined" ) );
141 }
142
143 mSrcNoDataValueCheckBox->setChecked( provider->useSourceNoDataValue( 1 ) );
144
145 const bool enableSrcNoData = provider->sourceHasNoDataValue( 1 ) && !std::isnan( mRasterLayer->dataProvider()->sourceNoDataValue( 1 ) );
146
147 mSrcNoDataValueCheckBox->setEnabled( enableSrcNoData );
148 lblSrcNoDataValue->setEnabled( enableSrcNoData );
149 }
150
151 if ( renderer )
152 {
153 if ( renderer->nodataColor().isValid() )
154 mNodataColorButton->setColor( renderer->nodataColor() );
155 else
156 mNodataColorButton->setToNull();
157
158 mOpacityWidget->setOpacity( renderer->opacity() );
159
160 cboxTransparencyBand->setBand( renderer->alphaBand() );
161 }
162
163 if ( provider )
164 {
165 const QgsRasterRangeList noDataRangeList = mRasterLayer->dataProvider()->userNoDataValues( 1 );
166 QgsDebugMsg( QStringLiteral( "noDataRangeList.size = %1" ).arg( noDataRangeList.size() ) );
167 if ( !noDataRangeList.isEmpty() )
168 {
169 const double v = QgsRasterBlock::printValue( noDataRangeList.value( 0 ).min() ).toDouble();
170 leNoDataValue->setText( QLocale().toString( v ) );
171 }
172 else
173 {
174 leNoDataValue->setText( QString() );
175 }
176 }
177 else
178 {
179 leNoDataValue->setText( QString() );
180 }
181
184
185 populateTransparencyTable( mRasterLayer->renderer() );
186}
187
188void QgsRasterTransparencyWidget::transparencyCellTextEdited( const QString &text )
189{
190 Q_UNUSED( text )
191 QgsDebugMsg( QStringLiteral( "text = %1" ).arg( text ) );
192 QgsRasterRenderer *renderer = mRasterLayer->renderer();
193 if ( !renderer )
194 {
195 return;
196 }
197 const int nBands = renderer->usesBands().size();
198 if ( nBands == 1 )
199 {
200 QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender() );
201 if ( !lineEdit ) return;
202 int row = -1;
203 int column = -1;
204 for ( int r = 0; r < tableTransparency->rowCount(); r++ )
205 {
206 for ( int c = 0; c < tableTransparency->columnCount(); c++ )
207 {
208 if ( tableTransparency->cellWidget( r, c ) == sender() )
209 {
210 row = r;
211 column = c;
212 break;
213 }
214 }
215 if ( row != -1 ) break;
216 }
217 QgsDebugMsg( QStringLiteral( "row = %1 column =%2" ).arg( row ).arg( column ) );
218
219 if ( column == 0 )
220 {
221 QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, 1 ) );
222 if ( !toLineEdit ) return;
223 const bool toChanged = mTransparencyToEdited.value( row );
224 QgsDebugMsg( QStringLiteral( "toChanged = %1" ).arg( toChanged ) );
225 if ( !toChanged )
226 {
227 toLineEdit->setText( lineEdit->text() );
228 }
229 }
230 else if ( column == 1 )
231 {
232 setTransparencyToEdited( row );
233 }
234 }
235 emit widgetChanged();
236}
237
238void QgsRasterTransparencyWidget::pbnAddValuesFromDisplay_clicked()
239{
240 if ( mMapCanvas && mPixelSelectorTool )
241 {
242 mMapCanvas->setMapTool( mPixelSelectorTool );
243 }
244}
245
246void QgsRasterTransparencyWidget::pbnAddValuesManually_clicked()
247{
248 QgsRasterRenderer *renderer = mRasterLayer->renderer();
249 if ( !renderer )
250 {
251 return;
252 }
253
254 tableTransparency->insertRow( tableTransparency->rowCount() );
255
256 int n = renderer->usesBands().size();
257 if ( n == 1 ) n++;
258
259 for ( int i = 0; i < n; i++ )
260 {
261 setTransparencyCell( tableTransparency->rowCount() - 1, i, std::numeric_limits<double>::quiet_NaN() );
262 }
263
264 setTransparencyCell( tableTransparency->rowCount() - 1, n, 100 );
265
266 //tableTransparency->resizeColumnsToContents();
267 //tableTransparency->resizeRowsToContents();
268}
269
270void QgsRasterTransparencyWidget::pbnDefaultValues_clicked()
271{
272 QgsRasterRenderer *r = mRasterLayer->renderer();
273 if ( !r )
274 {
275 return;
276 }
277
278 const int nBands = r->usesBands().size();
279
280 setupTransparencyTable( nBands );
281
282 //tableTransparency->resizeColumnsToContents(); // works only with values
283 //tableTransparency->resizeRowsToContents();
284
285}
286
287void QgsRasterTransparencyWidget::pbnExportTransparentPixelValues_clicked()
288{
289 const QgsSettings myQSettings;
290 const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
291 QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save Pixel Values as File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
292 if ( !myFileName.isEmpty() )
293 {
294 if ( !myFileName.endsWith( QLatin1String( ".txt" ), Qt::CaseInsensitive ) )
295 {
296 myFileName = myFileName + ".txt";
297 }
298
299 QFile myOutputFile( myFileName );
300 if ( myOutputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
301 {
302 QTextStream myOutputStream( &myOutputFile );
303 myOutputStream << "# " << tr( "QGIS Generated Transparent Pixel Value Export File" ) << '\n';
304 if ( rasterIsMultiBandColor() )
305 {
306 myOutputStream << "#\n#\n# " << tr( "Red" ) << "\t" << tr( "Green" ) << "\t" << tr( "Blue" ) << "\t" << tr( "Percent Transparent" );
307 for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
308 {
309 myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
310 << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
311 << QString::number( transparencyCellValue( myTableRunner, 2 ) ) << "\t"
312 << QString::number( transparencyCellValue( myTableRunner, 3 ) );
313 }
314 }
315 else
316 {
317 myOutputStream << "#\n#\n# " << tr( "Value" ) << "\t" << tr( "Percent Transparent" );
318
319 for ( int myTableRunner = 0; myTableRunner < tableTransparency->rowCount(); myTableRunner++ )
320 {
321 myOutputStream << '\n' << QString::number( transparencyCellValue( myTableRunner, 0 ) ) << "\t"
322 << QString::number( transparencyCellValue( myTableRunner, 1 ) ) << "\t"
323 << QString::number( transparencyCellValue( myTableRunner, 2 ) );
324 }
325 }
326 }
327 else
328 {
329 QMessageBox::warning( this, tr( "Save Pixel Values as File" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
330 }
331 }
332}
333
334void QgsRasterTransparencyWidget::pbnImportTransparentPixelValues_clicked()
335{
336 int myLineCounter = 0;
337 bool myImportError = false;
338 QString myBadLines;
339 const QgsSettings myQSettings;
340 const QString myLastDir = myQSettings.value( QStringLiteral( "lastRasterFileFilterDir" ), QDir::homePath() ).toString();
341 const QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Pixel Values from File" ), myLastDir, tr( "Textfile" ) + " (*.txt)" );
342 QFile myInputFile( myFileName );
343 if ( myInputFile.open( QFile::ReadOnly ) )
344 {
345 QTextStream myInputStream( &myInputFile );
346 QString myInputLine;
347 if ( rasterIsMultiBandColor() )
348 {
349 for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
350 {
351 tableTransparency->removeRow( myTableRunner );
352 }
353
354 while ( !myInputStream.atEnd() )
355 {
356 myLineCounter++;
357 myInputLine = myInputStream.readLine();
358 if ( !myInputLine.isEmpty() )
359 {
360 if ( !myInputLine.simplified().startsWith( '#' ) )
361 {
362#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
363 QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
364#else
365 QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
366#endif
367 if ( myTokens.count() != 4 )
368 {
369 myImportError = true;
370 myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
371 }
372 else
373 {
374 tableTransparency->insertRow( tableTransparency->rowCount() );
375 for ( int col = 0; col < 4; col++ )
376 {
377 setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
378 }
379 }
380 }
381 }
382 }
383 }
384 else
385 {
386 for ( int myTableRunner = tableTransparency->rowCount() - 1; myTableRunner >= 0; myTableRunner-- )
387 {
388 tableTransparency->removeRow( myTableRunner );
389 }
390
391 while ( !myInputStream.atEnd() )
392 {
393 myLineCounter++;
394 myInputLine = myInputStream.readLine();
395 if ( !myInputLine.isEmpty() )
396 {
397 if ( !myInputLine.simplified().startsWith( '#' ) )
398 {
399#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
400 QStringList myTokens = myInputLine.split( QRegExp( "\\s+" ), QString::SkipEmptyParts );
401#else
402 QStringList myTokens = myInputLine.split( QRegularExpression( "\\s+" ), Qt::SkipEmptyParts );
403#endif
404 if ( myTokens.count() != 3 && myTokens.count() != 2 ) // 2 for QGIS < 1.9 compatibility
405 {
406 myImportError = true;
407 myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n";
408 }
409 else
410 {
411 if ( myTokens.count() == 2 )
412 {
413 myTokens.insert( 1, myTokens[0] ); // add 'to' value, QGIS < 1.9 compatibility
414 }
415 tableTransparency->insertRow( tableTransparency->rowCount() );
416 for ( int col = 0; col < 3; col++ )
417 {
418 setTransparencyCell( tableTransparency->rowCount() - 1, col, myTokens[col].toDouble() );
419 }
420 }
421 }
422 }
423 }
424 }
425
426 if ( myImportError )
427 {
428 QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "The following lines contained errors\n\n%1" ).arg( myBadLines ) );
429 }
430 }
431 else if ( !myFileName.isEmpty() )
432 {
433 QMessageBox::warning( this, tr( "Load Pixel Values from File" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) );
434 }
435 //tableTransparency->resizeColumnsToContents();
436 //tableTransparency->resizeRowsToContents();
437 emit widgetChanged();
438}
439
440void QgsRasterTransparencyWidget::pbnRemoveSelectedRow_clicked()
441{
442 if ( 0 < tableTransparency->rowCount() )
443 {
444 tableTransparency->removeRow( tableTransparency->currentRow() );
445 }
446 emit widgetChanged();
447}
448
449bool QgsRasterTransparencyWidget::rasterIsMultiBandColor()
450{
451 return mRasterLayer && nullptr != dynamic_cast<QgsMultiBandColorRenderer *>( mRasterLayer->renderer() );
452}
453
455{
456 //set NoDataValue
457 QgsRasterRangeList myNoDataRangeList;
458 if ( "" != leNoDataValue->text() )
459 {
460 bool myDoubleOk = false;
461 const double myNoDataValue = QgsDoubleValidator::toDouble( leNoDataValue->text(), &myDoubleOk );
462 if ( myDoubleOk )
463 {
464 const QgsRasterRange myNoDataRange( myNoDataValue, myNoDataValue );
465 myNoDataRangeList << myNoDataRange;
466 }
467 }
468 if ( QgsRasterDataProvider *provider = mRasterLayer->dataProvider() )
469 {
470 for ( int bandNo = 1; bandNo <= provider->bandCount(); bandNo++ )
471 {
472 mRasterLayer->dataProvider()->setUserNoDataValue( bandNo, myNoDataRangeList );
473 mRasterLayer->dataProvider()->setUseSourceNoDataValue( bandNo, mSrcNoDataValueCheckBox->isChecked() );
474 }
475 }
476
477 //transparency settings
478 QgsRasterRenderer *rasterRenderer = mRasterLayer->renderer();
479 if ( rasterRenderer )
480 {
481 rasterRenderer->setAlphaBand( cboxTransparencyBand->currentBand() );
482 rasterRenderer->setNodataColor( mNodataColorButton->color() );
483
484 //Walk through each row in table and test value. If not valid set to 0.0 and continue building transparency list
485 QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
486 if ( tableTransparency->columnCount() == 4 )
487 {
489 QList<QgsRasterTransparency::TransparentThreeValuePixel> myTransparentThreeValuePixelList;
490 myTransparentThreeValuePixelList.reserve( tableTransparency->rowCount() );
491 for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
492 {
493 myTransparentPixel.red = transparencyCellValue( myListRunner, 0 );
494 myTransparentPixel.green = transparencyCellValue( myListRunner, 1 );
495 myTransparentPixel.blue = transparencyCellValue( myListRunner, 2 );
496 myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 3 );
497 myTransparentThreeValuePixelList.append( myTransparentPixel );
498 }
499 rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
500 }
501 else if ( tableTransparency->columnCount() == 3 )
502 {
504 QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
505 myTransparentSingleValuePixelList.reserve( tableTransparency->rowCount() );
506 for ( int myListRunner = 0; myListRunner < tableTransparency->rowCount(); myListRunner++ )
507 {
508 myTransparentPixel.min = transparencyCellValue( myListRunner, 0 );
509 myTransparentPixel.max = transparencyCellValue( myListRunner, 1 );
510 myTransparentPixel.percentTransparent = transparencyCellValue( myListRunner, 2 );
511
512 myTransparentSingleValuePixelList.append( myTransparentPixel );
513 }
514 rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
515 }
516
517 rasterRenderer->setRasterTransparency( rasterTransparency );
518
519 //set global transparency
520 rasterRenderer->setOpacity( mOpacityWidget->opacity() );
521 }
522
524}
525
527{
528 button->blockSignals( true );
530 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsRasterTransparencyWidget::updateProperty );
532 button->blockSignals( false );
533}
534
536{
537 const auto propertyOverrideButtons { findChildren< QgsPropertyOverrideButton * >() };
538 for ( QgsPropertyOverrideButton *button : propertyOverrideButtons )
539 {
540 updateDataDefinedButton( button );
541 }
542}
543
545{
546 if ( !button )
547 return;
548
549 if ( button->propertyKey() < 0 )
550 return;
551
552 const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
553 whileBlocking( button )->setToProperty( mPropertyCollection.property( key ) );
554}
555
556void QgsRasterTransparencyWidget::updateProperty()
557{
558 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
559 const QgsRasterPipe::Property key = static_cast< QgsRasterPipe::Property >( button->propertyKey() );
561 emit widgetChanged();
562}
563
564void QgsRasterTransparencyWidget::pixelSelected( const QgsPointXY &canvasPoint )
565{
566 QgsRasterRenderer *renderer = mRasterLayer->renderer();
567 if ( !renderer )
568 {
569 return;
570 }
571
572 //Get the pixel values and add a new entry to the transparency table
573 if ( mMapCanvas && mPixelSelectorTool && mRasterLayer->dataProvider() )
574 {
575 mMapCanvas->unsetMapTool( mPixelSelectorTool );
576
577 const QgsMapSettings &ms = mMapCanvas->mapSettings();
578 const QgsPointXY myPoint = ms.mapToLayerCoordinates( mRasterLayer, canvasPoint );
579
580 const QgsRectangle myExtent = ms.mapToLayerCoordinates( mRasterLayer, mMapCanvas->extent() );
581 const double mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
582 const int myWidth = mMapCanvas->extent().width() / mapUnitsPerPixel;
583 const int myHeight = mMapCanvas->extent().height() / mapUnitsPerPixel;
584
585 const QMap<int, QVariant> myPixelMap = mRasterLayer->dataProvider()->identify( myPoint, QgsRaster::IdentifyFormatValue, myExtent, myWidth, myHeight ).results();
586
587 const QList<int> bands = renderer->usesBands();
588
589 QList<double> values;
590 for ( int i = 0; i < bands.size(); ++i )
591 {
592 const int bandNo = bands.value( i );
593 if ( myPixelMap.count( bandNo ) == 1 )
594 {
595 if ( QgsVariantUtils::isNull( myPixelMap.value( bandNo ) ) )
596 {
597 return; // Don't add nodata, transparent anyway
598 }
599 const double value = myPixelMap.value( bandNo ).toDouble();
600 QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
601 values.append( value );
602 }
603 }
604 if ( bands.size() == 1 )
605 {
606 // Set 'to'
607 values.insert( 1, values.value( 0 ) );
608 }
609 tableTransparency->insertRow( tableTransparency->rowCount() );
610 for ( int i = 0; i < values.size(); i++ )
611 {
612 setTransparencyCell( tableTransparency->rowCount() - 1, i, values.value( i ) );
613 }
614 setTransparencyCell( tableTransparency->rowCount() - 1, tableTransparency->columnCount() - 1, 100 );
615 }
616
617 //tableTransparency->resizeColumnsToContents();
618 //tableTransparency->resizeRowsToContents();
619}
620
621void QgsRasterTransparencyWidget::populateTransparencyTable( QgsRasterRenderer *renderer )
622{
623 if ( !mRasterLayer )
624 {
625 return;
626 }
627
628 if ( !renderer )
629 {
630 return;
631 }
632
633 const int nBands = renderer->usesBands().size();
634 setupTransparencyTable( nBands );
635
636 const QgsRasterTransparency *rasterTransparency = renderer->rasterTransparency();
637 if ( !rasterTransparency )
638 {
639 return;
640 }
641
642 if ( nBands == 1 )
643 {
644 QList<QgsRasterTransparency::TransparentSingleValuePixel> pixelList = rasterTransparency->transparentSingleValuePixelList();
645 for ( int i = 0; i < pixelList.size(); ++i )
646 {
647 tableTransparency->insertRow( i );
648 setTransparencyCell( i, 0, pixelList[i].min );
649 setTransparencyCell( i, 1, pixelList[i].max );
650 setTransparencyCell( i, 2, pixelList[i].percentTransparent );
651 // break synchronization only if values differ
652 if ( pixelList[i].min != pixelList[i].max )
653 {
654 setTransparencyToEdited( i );
655 }
656 }
657 }
658 else if ( nBands == 3 )
659 {
660 QList<QgsRasterTransparency::TransparentThreeValuePixel> pixelList = rasterTransparency->transparentThreeValuePixelList();
661 for ( int i = 0; i < pixelList.size(); ++i )
662 {
663 tableTransparency->insertRow( i );
664 setTransparencyCell( i, 0, pixelList[i].red );
665 setTransparencyCell( i, 1, pixelList[i].green );
666 setTransparencyCell( i, 2, pixelList[i].blue );
667 setTransparencyCell( i, 3, pixelList[i].percentTransparent );
668 }
669 }
670
671 tableTransparency->resizeColumnsToContents();
672 tableTransparency->resizeRowsToContents();
673
674}
675
676void QgsRasterTransparencyWidget::setupTransparencyTable( int nBands )
677{
678 tableTransparency->clear();
679 tableTransparency->setColumnCount( 0 );
680 tableTransparency->setRowCount( 0 );
681 mTransparencyToEdited.clear();
682
683 if ( nBands == 3 )
684 {
685 tableTransparency->setColumnCount( 4 );
686 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Red" ) ) );
687 tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "Green" ) ) );
688 tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Blue" ) ) );
689 tableTransparency->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
690 }
691 else //1 band
692 {
693 tableTransparency->setColumnCount( 3 );
694// Is it important to distinguish the header? It becomes difficult with range.
695#if 0
696 if ( QgsRasterLayer::PalettedColor != mRasterLayer->drawingStyle() &&
697 QgsRasterLayer::PalettedSingleBandGray != mRasterLayer->drawingStyle() &&
698 QgsRasterLayer::PalettedSingleBandPseudoColor != mRasterLayer->drawingStyle() &&
699 QgsRasterLayer::PalettedMultiBandColor != mRasterLayer->drawingStyle() )
700 {
701 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Gray" ) ) );
702 }
703 else
704 {
705 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "Indexed Value" ) ) );
706 }
707#endif
708 tableTransparency->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
709 tableTransparency->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
710 tableTransparency->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr( "Percent Transparent" ) ) );
711 }
712}
713
714void QgsRasterTransparencyWidget::setTransparencyCell( int row, int column, double value )
715{
716 QgsDebugMsg( QStringLiteral( "value = %1" ).arg( value, 0, 'g', 17 ) );
717 QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
718 if ( !provider )
719 return;
720
721 QgsRasterRenderer *renderer = mRasterLayer->renderer();
722 if ( !renderer )
723 return;
724 const int nBands = renderer->usesBands().size();
725
726 QLineEdit *lineEdit = new QLineEdit();
727 lineEdit->setFrame( false ); // frame looks bad in table
728 // Without margins row selection is not displayed (important for delete row)
729 lineEdit->setContentsMargins( 1, 1, 1, 1 );
730
731 if ( column == tableTransparency->columnCount() - 1 )
732 {
733 // transparency
734 // Who needs transparency as floating point?
735 lineEdit->setValidator( new QIntValidator( nullptr ) );
736 lineEdit->setText( QString::number( static_cast<int>( value ) ) );
737 }
738 else
739 {
740 // value
741 QString valueString;
742 switch ( provider->sourceDataType( 1 ) )
743 {
746 lineEdit->setValidator( new QgsDoubleValidator( nullptr ) );
747 if ( !std::isnan( value ) )
748 {
749 const double v = QgsRasterBlock::printValue( value ).toDouble();
750 valueString = QLocale().toString( v );
751 }
752 break;
753 default:
754 lineEdit->setValidator( new QIntValidator( nullptr ) );
755 if ( !std::isnan( value ) )
756 {
757 valueString = QString::number( static_cast<int>( value ) );
758 }
759 break;
760 }
761 lineEdit->setText( valueString );
762 connect( lineEdit, &QLineEdit::textEdited, this, &QgsPanelWidget::widgetChanged );
763 }
764 tableTransparency->setCellWidget( row, column, lineEdit );
765 adjustTransparencyCellWidth( row, column );
766
767 if ( nBands == 1 && ( column == 0 || column == 1 ) )
768 {
769 connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterTransparencyWidget::transparencyCellTextEdited );
770 }
771 //tableTransparency->resizeColumnsToContents();
772 emit widgetChanged();
773}
774
775void QgsRasterTransparencyWidget::adjustTransparencyCellWidth( int row, int column )
776{
777 QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
778 if ( !lineEdit ) return;
779
780 int width = std::max( lineEdit->fontMetrics().boundingRect( lineEdit->text() ).width() + 10, 100 );
781 width = std::max( width, tableTransparency->columnWidth( column ) );
782
783 lineEdit->setFixedWidth( width );
784}
785
786void QgsRasterTransparencyWidget::setTransparencyToEdited( int row )
787{
788 if ( row >= mTransparencyToEdited.size() )
789 {
790 mTransparencyToEdited.resize( row + 1 );
791 }
792 mTransparencyToEdited[row] = true;
793}
794
795double QgsRasterTransparencyWidget::transparencyCellValue( int row, int column )
796{
797 QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( tableTransparency->cellWidget( row, column ) );
798 if ( !lineEdit || lineEdit->text().isEmpty() )
799 {
800 return std::numeric_limits<double>::quiet_NaN();
801 }
802 return QgsDoubleValidator::toDouble( lineEdit->text() );
803
804}
805
807{
808 return mPixelSelectorTool;
809}
@ 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)
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.
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:59
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
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 void setUseSourceNoDataValue(int bandNo, bool use)
Sets the source nodata value usage.
virtual double sourceNoDataValue(int bandNo) const
Value representing no data value.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
virtual QgsRasterRangeList userNoDataValues(int bandNo) const
Returns a list of user no data value ranges.
virtual void setUserNoDataValue(int bandNo, const QgsRasterRangeList &noData)
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.
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in raster pipes.
Property
Data definable properties.
@ RendererOpacity
Raster renderer global opacity.
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 QList< QgsRasterTransparency::TransparentSingleValuePixel > &newList)
Sets the transparent single value pixel list, replacing the whole existing list.
QList< QgsRasterTransparency::TransparentThreeValuePixel > transparentThreeValuePixelList() const
Returns the transparent three value pixel list.
void setTransparentThreeValuePixelList(const QList< QgsRasterTransparency::TransparentThreeValuePixel > &newList)
Sets the transparent three value pixel list, replacing the whole existing list.
QList< QgsRasterTransparency::TransparentSingleValuePixel > transparentSingleValuePixelList() const
Returns the transparent single value pixel list.
@ IdentifyFormatValue
Definition qgsraster.h:60
A rectangle specified with double values.
double width() const
Returns the width of the rectangle.
double height() const
Returns the height of the rectangle.
This class is a composition of two QSettings instances:
Definition qgssettings.h:62
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)
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:2453
#define QgsDebugMsg(str)
Definition qgslogger.h:38
QList< QgsRasterRange > QgsRasterRangeList